serilogger
Version:
A structured logging framework for JavaScript, inspired by Serilog.
1,245 lines (1,223 loc) • 52.9 kB
JavaScript
/**
* Represents the severity level of a log event.
*/
var LogEventLevel;
(function (LogEventLevel) {
LogEventLevel[LogEventLevel["off"] = 0] = "off";
LogEventLevel[LogEventLevel["fatal"] = 1] = "fatal";
LogEventLevel[LogEventLevel["error"] = 3] = "error";
LogEventLevel[LogEventLevel["warning"] = 7] = "warning";
LogEventLevel[LogEventLevel["information"] = 15] = "information";
LogEventLevel[LogEventLevel["debug"] = 31] = "debug";
LogEventLevel[LogEventLevel["verbose"] = 63] = "verbose";
})(LogEventLevel || (LogEventLevel = {}));
/**
* Checks if a log event level includes the target log event level.
* @param {LogEventLevel} level The level to check.
* @param {LogEventLevel} target The target level.
* @returns True if the checked level contains the target level, or if the checked level is undefined.
*/
function isEnabled(level, target) {
return typeof level === 'undefined' || (level & target) === target;
}
/**
* Represents a log event.
*/
var LogEvent = /** @class */ (function () {
/**
* Creates a new log event instance.
*/
function LogEvent(timestamp, level, messageTemplate, properties, error) {
this.timestamp = timestamp;
this.level = level;
this.messageTemplate = messageTemplate;
this.properties = properties || {};
this.error = error || undefined;
}
return LogEvent;
}());
var deepClone = function (obj) { return JSON.parse(JSON.stringify(obj)); };
var EnrichStage = /** @class */ (function () {
function EnrichStage(enricher) {
this.enricher = enricher;
}
EnrichStage.prototype.emit = function (events) {
for (var i = 0; i < events.length; ++i) {
var extraProperties = this.enricher instanceof Function
? this.enricher(deepClone(events[i].properties))
: this.enricher;
Object.assign(events[i].properties, extraProperties);
}
return events;
};
EnrichStage.prototype.flush = function () {
return Promise.resolve();
};
return EnrichStage;
}());
var tokenizer = /{@?\w+}/g;
/**
* Represents a message template that can be rendered into a log message.
*/
var MessageTemplate = /** @class */ (function () {
/**
* Creates a new MessageTemplate instance with the given template.
*/
function MessageTemplate(messageTemplate) {
/**
* Get or sets the JSON template string max length. Set to -1 for no max.
*/
this.jsonTemplateStringMaxLength = 70;
if (messageTemplate === null || !messageTemplate.length) {
throw new Error('Argument "messageTemplate" is required.');
}
this.raw = messageTemplate;
this.tokens = this.tokenize(messageTemplate);
}
/**
* Renders this template using the given properties.
* @param {Object} properties Object containing the properties.
* @returns Rendered message.
*/
MessageTemplate.prototype.render = function (properties) {
if (!this.tokens.length) {
return this.raw;
}
properties = properties || {};
var result = [];
for (var i = 0; i < this.tokens.length; ++i) {
var token = this.tokens[i];
if (typeof token.name === 'string') {
if (properties.hasOwnProperty(token.name)) {
result.push(this.toText(properties[token.name]));
}
else {
result.push(token.raw);
}
}
else {
result.push(token.text);
}
}
return result.join('');
};
/**
* Binds the given set of args to their matching tokens.
* @param {any} positionalArgs Arguments.
* @returns Object containing the properties.
*/
MessageTemplate.prototype.bindProperties = function (positionalArgs) {
var result = {};
var nextArg = 0;
for (var i = 0; i < this.tokens.length && nextArg < positionalArgs.length; ++i) {
var token = this.tokens[i];
if (typeof token.name === 'string') {
var p = positionalArgs[nextArg];
result[token.name] = this.capture(p, token.destructure);
nextArg++;
}
}
while (nextArg < positionalArgs.length) {
var arg = positionalArgs[nextArg];
if (typeof arg !== 'undefined') {
result['a' + nextArg] = this.capture(arg);
}
nextArg++;
}
return result;
};
MessageTemplate.prototype.tokenize = function (template) {
var tokens = [];
var result;
var textStart = 0;
while ((result = tokenizer.exec(template)) !== null) {
if (result.index !== textStart) {
tokens.push({ text: template.slice(textStart, result.index) });
}
var destructure = false;
var token = result[0].slice(1, -1);
if (token.indexOf('@') === 0) {
token = token.slice(1);
destructure = true;
}
tokens.push({
name: token,
destructure: destructure,
raw: result[0]
});
textStart = tokenizer.lastIndex;
}
if (textStart >= 0 && textStart < template.length) {
tokens.push({ text: template.slice(textStart) });
}
return tokens;
};
MessageTemplate.prototype.toText = function (property) {
if (typeof property === 'undefined')
return 'undefined';
if (property === null)
return 'null';
if (typeof property === 'string')
return property;
if (typeof property === 'number')
return property.toString();
if (typeof property === 'boolean')
return property.toString();
if (typeof property.toISOString === 'function')
return property.toISOString();
if (typeof property === 'object') {
var s = JSON.stringify(property);
if (this.jsonTemplateStringMaxLength === -1)
return s;
if (s.length > this.jsonTemplateStringMaxLength) {
s = s.slice(0, 67) + '...';
}
return s;
}
return property.toString();
};
MessageTemplate.prototype.capture = function (property, destructure) {
if (typeof property === 'function') {
return property.toString();
}
if (typeof property === 'object') {
// null value will be automatically stringified as "null", in properties it will be as null
// otherwise it will throw an error
if (property === null) {
return property;
}
// Could use instanceof Date, but this way will be kinder
// to values passed from other contexts...
if (destructure || typeof property.toISOString === 'function') {
return property;
}
return property.toString();
}
return property;
};
return MessageTemplate;
}());
var Pipeline = /** @class */ (function () {
function Pipeline() {
this.stages = [];
this.eventQueue = [];
this.flushInProgress = false;
}
/**
* Adds a stage to the end of the pipeline.
* @param {PipelineStage} stage The pipeline stage to add.
*/
Pipeline.prototype.addStage = function (stage) {
this.stages.push(stage);
};
/**
* Emits events through the pipeline. If a flush is currently in progress, the events will be queued and will been
* sent through the pipeline once the flush is complete.
* @param {LogEvent[]} events The events to emit.
*/
Pipeline.prototype.emit = function (events) {
var _this = this;
if (this.flushInProgress) {
this.eventQueue = this.eventQueue.concat(events);
return this.flushPromise;
}
else {
if (!this.stages.length || !events.length) {
return Promise.resolve();
}
var promise = Promise.resolve(this.stages[0].emit(events));
var _loop_1 = function (i) {
promise = promise.then(function (events) { return _this.stages[i].emit(events); });
};
for (var i = 1; i < this.stages.length; ++i) {
_loop_1(i);
}
return promise;
}
};
/**
* Flushes events through the pipeline.
* @returns A {Promise<any>} that resolves when all events have been flushed and the pipeline can accept new events.
*/
Pipeline.prototype.flush = function () {
var _this = this;
if (this.flushInProgress) {
return this.flushPromise;
}
this.flushInProgress = true;
return (this.flushPromise = Promise.resolve()
.then(function () {
if (_this.stages.length === 0) {
return;
}
var promise = _this.stages[0].flush();
var _loop_2 = function (i) {
promise = promise.then(function () { return _this.stages[i].flush(); });
};
for (var i = 1; i < _this.stages.length; ++i) {
_loop_2(i);
}
return promise;
})
.then(function () {
_this.flushInProgress = false;
var queuedEvents = _this.eventQueue.slice();
_this.eventQueue = [];
return _this.emit(queuedEvents);
}));
};
return Pipeline;
}());
var SinkStage = /** @class */ (function () {
function SinkStage(sink) {
this.sink = sink;
}
SinkStage.prototype.emit = function (events) {
this.sink.emit(events);
return events;
};
SinkStage.prototype.flush = function () {
return this.sink.flush();
};
return SinkStage;
}());
/**
* Logs events.
*/
var Logger = /** @class */ (function () {
/**
* Creates a new logger instance using the specified pipeline.
*/
function Logger(pipeline, suppressErrors) {
this.suppressErrors = true;
this._jsonTemplateStringMaxLength = 70;
this.pipeline = pipeline;
this.suppressErrors = typeof suppressErrors === "undefined" || suppressErrors;
}
/**
* Get or sets the JSON template string max length. Set to -1 for no max.
* @param length
*/
Logger.prototype.setJSONTemplateStringMaxLength = function (length) {
this._jsonTemplateStringMaxLength = length;
};
/**
* Creates a child logger that is a copy of the existing instance adding a new Enrichment stage to pipeline.
* @param enricher
* @returns
*/
Logger.prototype.createChild = function (enricher) {
if (enricher instanceof Function || enricher instanceof Object) {
var currentStages = this.pipeline['stages'];
var stages_1 = [];
var sinkStages_1 = [];
currentStages.forEach(function (stage) {
if (stage instanceof SinkStage) {
sinkStages_1.push(stage);
}
else {
stages_1.push(stage);
}
});
// Add new Enrichment
stages_1.push(new EnrichStage(enricher));
var newPipeline_1 = new Pipeline();
// Add Stages
stages_1.forEach(function (stage) { return newPipeline_1.addStage(stage); });
sinkStages_1.forEach(function (stage) { return newPipeline_1.addStage(stage); });
return new Logger(newPipeline_1, this.suppressErrors);
}
else {
throw new TypeError('Argument "enricher" must be either a function or an object.');
}
};
Logger.prototype.fatal = function (errorOrMessageTemplate) {
var properties = [];
for (var _i = 1; _i < arguments.length; _i++) {
properties[_i - 1] = arguments[_i];
}
try {
if (errorOrMessageTemplate instanceof Error) {
this.write(LogEventLevel.fatal, properties[0], properties.slice(1), errorOrMessageTemplate);
}
else {
this.write(LogEventLevel.fatal, errorOrMessageTemplate, properties);
}
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
}
};
Logger.prototype.error = function (errorOrMessageTemplate) {
var properties = [];
for (var _i = 1; _i < arguments.length; _i++) {
properties[_i - 1] = arguments[_i];
}
try {
if (errorOrMessageTemplate instanceof Error) {
this.write(LogEventLevel.error, properties[0], properties.slice(1), errorOrMessageTemplate);
}
else {
this.write(LogEventLevel.error, errorOrMessageTemplate, properties);
}
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
}
};
Logger.prototype.warn = function (errorOrMessageTemplate) {
var properties = [];
for (var _i = 1; _i < arguments.length; _i++) {
properties[_i - 1] = arguments[_i];
}
try {
if (errorOrMessageTemplate instanceof Error) {
this.write(LogEventLevel.warning, properties[0], properties.slice(1), errorOrMessageTemplate);
}
else {
this.write(LogEventLevel.warning, errorOrMessageTemplate, properties);
}
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
}
};
Logger.prototype.info = function (errorOrMessageTemplate) {
var properties = [];
for (var _i = 1; _i < arguments.length; _i++) {
properties[_i - 1] = arguments[_i];
}
try {
if (errorOrMessageTemplate instanceof Error) {
this.write(LogEventLevel.information, properties[0], properties.slice(1), errorOrMessageTemplate);
}
else {
this.write(LogEventLevel.information, errorOrMessageTemplate, properties);
}
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
}
};
Logger.prototype.debug = function (errorOrMessageTemplate) {
var properties = [];
for (var _i = 1; _i < arguments.length; _i++) {
properties[_i - 1] = arguments[_i];
}
try {
if (errorOrMessageTemplate instanceof Error) {
this.write(LogEventLevel.debug, properties[0], properties.slice(1), errorOrMessageTemplate);
}
else {
this.write(LogEventLevel.debug, errorOrMessageTemplate, properties);
}
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
}
};
Logger.prototype.verbose = function (errorOrMessageTemplate) {
var properties = [];
for (var _i = 1; _i < arguments.length; _i++) {
properties[_i - 1] = arguments[_i];
}
try {
if (errorOrMessageTemplate instanceof Error) {
this.write(LogEventLevel.verbose, properties[0], properties.slice(1), errorOrMessageTemplate);
}
else {
this.write(LogEventLevel.verbose, errorOrMessageTemplate, properties);
}
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
}
};
/**
* Flushes the pipeline of this logger.
* @returns A {Promise<any>} that will resolve when the pipeline has been flushed.
*/
Logger.prototype.flush = function () {
return this.suppressErrors
? this.pipeline.flush().catch(function () { })
: this.pipeline.flush();
};
/**
* Emits events through this logger's pipeline.
*/
Logger.prototype.emit = function (events) {
try {
this.pipeline.emit(events);
return events;
}
catch (error) {
if (!this.suppressErrors) {
throw error;
}
return [];
}
};
Logger.prototype.write = function (level, rawMessageTemplate, unboundProperties, error) {
var messageTemplate = new MessageTemplate(rawMessageTemplate);
messageTemplate.jsonTemplateStringMaxLength = this._jsonTemplateStringMaxLength;
var properties = messageTemplate.bindProperties(unboundProperties);
var logEvent = new LogEvent(new Date().toISOString(), level, messageTemplate, properties, error);
this.pipeline.emit([logEvent]);
};
return Logger;
}());
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
function __spreadArray(to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
}
var defaultConsoleSinkOptions = {
removeLogLevelPrefix: false,
includeTimestamps: false,
includeProperties: false
};
var ConsoleSink = /** @class */ (function () {
function ConsoleSink(options) {
this.options = __assign(__assign({}, defaultConsoleSinkOptions), (options || {}));
var internalConsole = this.options.console || typeof console !== 'undefined' && console || null;
var stub = function () {
};
// console.debug is no-op for Node, so use console.log instead.
var nodeConsole = !this.options.console &&
typeof process !== 'undefined' &&
process.versions &&
process.versions.node;
this.console = {
error: (internalConsole && (internalConsole.error || internalConsole.log)) || stub,
warn: (internalConsole && (internalConsole.warn || internalConsole.log)) || stub,
info: (internalConsole && (internalConsole.info || internalConsole.log)) || stub,
debug: (internalConsole && ((!nodeConsole && internalConsole.debug) || internalConsole.log)) || stub,
log: (internalConsole && internalConsole.log) || stub
};
}
ConsoleSink.prototype.emit = function (events) {
for (var i = 0; i < events.length; ++i) {
var e = events[i];
if (!isEnabled(this.options.restrictedToMinimumLevel, e.level))
continue;
switch (e.level) {
case LogEventLevel.fatal:
this.writeToConsole(this.console.error, 'Fatal', e);
break;
case LogEventLevel.error:
this.writeToConsole(this.console.error, 'Error', e);
break;
case LogEventLevel.warning:
this.writeToConsole(this.console.warn, 'Warning', e);
break;
case LogEventLevel.information:
this.writeToConsole(this.console.info, 'Information', e);
break;
case LogEventLevel.debug:
this.writeToConsole(this.console.debug, 'Debug', e);
break;
case LogEventLevel.verbose:
this.writeToConsole(this.console.debug, 'Verbose', e);
break;
default:
this.writeToConsole(this.console.log, 'Log', e);
break;
}
}
return null;
};
ConsoleSink.prototype.flush = function () {
return Promise.resolve();
};
ConsoleSink.prototype.writeToConsole = function (logMethod, prefix, e) {
var output = "" + e.messageTemplate.render(e.properties);
if (!this.options.removeLogLevelPrefix)
output = "[" + prefix + "] " + output;
if (this.options.includeTimestamps)
output = e.timestamp + " " + output;
var values = [];
if (this.options.includeProperties) {
for (var key in e.properties) {
if (e.properties.hasOwnProperty(key)) {
values.push(e.properties[key]);
}
}
}
if (e.error instanceof Error) {
values.push('\n', e.error);
}
logMethod.apply(void 0, __spreadArray([output], values));
};
return ConsoleSink;
}());
var ColoredConsoleSink = /** @class */ (function (_super) {
__extends(ColoredConsoleSink, _super);
function ColoredConsoleSink() {
return _super !== null && _super.apply(this, arguments) || this;
}
ColoredConsoleSink.prototype.writeToConsole = function (logMethod, prefix, e) {
var output = "" + e.messageTemplate.render(e.properties);
if (!this.options.removeLogLevelPrefix)
output = "[" + prefix + "] " + output;
output = "" + this.logLevelToColor(e.level) + output + "\u001B[0m";
if (this.options.includeTimestamps)
output = e.timestamp + " " + output;
var values = [];
if (this.options.includeProperties) {
for (var key in e.properties) {
if (e.properties.hasOwnProperty(key)) {
values.push(e.properties[key]);
}
}
}
if (e.error instanceof Error) {
values.push('\n', e.error);
}
logMethod.apply(void 0, __spreadArray([output], values));
};
ColoredConsoleSink.prototype.logLevelToColor = function (level) {
switch (level) {
case LogEventLevel.verbose:
case LogEventLevel.debug:
return '\x1b[2m';
case LogEventLevel.warning:
return '\x1b[31m';
case LogEventLevel.fatal:
return '\x1b[37m\x1b[41m';
default:
return '';
}
};
return ColoredConsoleSink;
}(ConsoleSink));
var defaultBatchedSinkOptions = {
maxSize: 100,
period: 5,
durableStore: undefined
};
var BatchedSink = /** @class */ (function () {
function BatchedSink(innerSink, options) {
this.durableStorageKey = "serilogger-batched-sink-durable-cache";
this.batchKey = '';
this.shouldCycleContinue = true;
this.innerSink = innerSink || undefined;
this.options = __assign(__assign({}, defaultBatchedSinkOptions), (options || {}));
this.batchedEvents = [];
this.cycleBatch();
if (this.options.durableStore) {
var initialBatch = [];
for (var key in this.options.durableStore) {
if (key.indexOf(this.durableStorageKey) === 0) {
var storedEvents = JSON.parse(this.options.durableStore.getItem(key)).map(function (e) {
e.messageTemplate = new MessageTemplate(e.messageTemplate.raw);
return e;
});
initialBatch = initialBatch.concat(storedEvents);
this.options.durableStore.removeItem(key);
}
}
this.emit(initialBatch);
}
}
BatchedSink.prototype.emit = function (events) {
var _a, _b, _c;
if (this.batchedEvents.length + events.length <= this.options.maxSize) {
(_a = this.batchedEvents).push.apply(_a, events);
this.storeEvents();
}
else {
var cursor = this.options.maxSize - this.batchedEvents.length < 0
? 0
: this.options.maxSize - this.batchedEvents.length;
(_b = this.batchedEvents).push.apply(_b, events.slice(0, cursor));
this.storeEvents();
while (cursor < events.length) {
this.cycleBatch();
(_c = this.batchedEvents).push.apply(_c, events.slice(cursor, (cursor = cursor + this.options.maxSize)));
this.storeEvents();
}
}
return events;
};
BatchedSink.prototype.flush = function () {
this.cycleBatch();
var corePromise = this.flushCore();
return corePromise instanceof Promise ? corePromise : Promise.resolve();
};
/* start_test_code */
/**
* The will stop the cycle. Used for testing.
*/
BatchedSink.prototype.stopCycle = function () {
this.shouldCycleContinue = false;
if (this.batchTimeout)
clearTimeout(this.batchTimeout);
};
/* end_test_code */
BatchedSink.prototype.emitCore = function (events) {
return this.innerSink ? this.innerSink.emit(events) : null;
};
BatchedSink.prototype.flushCore = function () {
return this.innerSink ? this.innerSink.flush() : Promise.resolve();
};
BatchedSink.prototype.cycleBatch = function () {
var _this = this;
if (this.batchTimeout)
clearTimeout(this.batchTimeout);
if (!this.shouldCycleContinue)
return; // Clears the timeout object
if (this.batchedEvents.length) {
var processEvents_1 = this.batchedEvents.slice(0);
this.batchedEvents.length = 0;
var previousBatchKey_1 = this.batchKey;
var emitPromise = this.emitCore(processEvents_1);
(emitPromise instanceof Promise ? emitPromise : Promise.resolve())
.then(function () {
if (_this.options.durableStore) {
return _this.options.durableStore.removeItem(previousBatchKey_1);
}
})
.catch(function () {
var _a;
(_a = _this.batchedEvents).unshift.apply(_a, processEvents_1);
});
}
this.batchKey = this.durableStorageKey + "-" + new Date().getTime();
if (!isNaN(this.options.period) && this.options.period > 0) {
this.batchTimeout = setTimeout(function () { return _this.cycleBatch(); }, this.options.period * 1000);
}
};
BatchedSink.prototype.storeEvents = function () {
if (this.options.durableStore) {
this.options.durableStore.setItem(this.batchKey, JSON.stringify(this.batchedEvents));
}
};
return BatchedSink;
}());
var FilterStage = /** @class */ (function () {
function FilterStage(predicate) {
this.predicate = predicate;
}
FilterStage.prototype.emit = function (events) {
return events.filter(this.predicate);
};
FilterStage.prototype.flush = function () {
return Promise.resolve();
};
return FilterStage;
}());
/**
* Allows dynamic control of the logging level.
*/
var DynamicLevelSwitch = /** @class */ (function () {
function DynamicLevelSwitch(defaultLevel) {
/**
* Gets or sets a delegate that can be called when the pipeline needs to be flushed.
* This should generally not be modified, as it will be provided by the pipeline stage.
*/
this.flushDelegate = function () { return Promise.resolve(); };
this.minLevel = defaultLevel;
}
DynamicLevelSwitch.prototype.fatal = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.fatal];
}
});
});
};
DynamicLevelSwitch.prototype.error = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.error];
}
});
});
};
DynamicLevelSwitch.prototype.warning = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.warning];
}
});
});
};
DynamicLevelSwitch.prototype.information = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.information];
}
});
});
};
DynamicLevelSwitch.prototype.debug = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.debug];
}
});
});
};
DynamicLevelSwitch.prototype.verbose = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.verbose];
}
});
});
};
DynamicLevelSwitch.prototype.off = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = LogEventLevel.off];
}
});
});
};
DynamicLevelSwitch.prototype.set = function (level) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.flushDelegate()];
case 1:
_a.sent();
return [2 /*return*/, this.minLevel = level];
}
});
});
};
DynamicLevelSwitch.prototype.isEnabled = function (level) {
return this.minLevel === undefined || isEnabled(this.minLevel, level);
};
return DynamicLevelSwitch;
}());
var DynamicLevelSwitchStage = /** @class */ (function (_super) {
__extends(DynamicLevelSwitchStage, _super);
function DynamicLevelSwitchStage(dynamicLevelSwitch) {
var _this = _super.call(this, function (e) { return dynamicLevelSwitch.isEnabled(e.level); }) || this;
_this.dynamicLevelSwitch = dynamicLevelSwitch;
return _this;
}
/**
* Sets a delegate that can be called when the pipeline needs to be flushed.
*/
DynamicLevelSwitchStage.prototype.setFlushDelegate = function (flushDelegate) {
this.dynamicLevelSwitch.flushDelegate = flushDelegate;
};
return DynamicLevelSwitchStage;
}(FilterStage));
var ApiSink = /** @class */ (function () {
function ApiSink(options) {
var _this = this;
this.url = null;
this.headers = null;
this.durable = false;
this.compact = false;
this.levelSwitch = null;
this.refreshLevelSwitchTimeoutId = null;
this.refreshLevelSwitchTimeoutInterval = 2 * 60 * 1000;
this.suppressErrors = true;
if (!options) {
throw new Error("'options' parameter is required.");
}
if (!options.url || options.url === '') {
throw new Error("'options.url' parameter is required.");
}
this.url = options.url.replace(/\/$/, '');
this.levelSwitch = options.levelSwitch || null;
this.suppressErrors = options.suppressErrors !== false;
if (options.durable && typeof localStorage === 'undefined') {
if (typeof console !== 'undefined' && console.warn) {
console.warn("'options.durable' parameter was set to true, but 'localStorage' is not available.");
}
this.durable = false;
}
else {
this.durable = !!options.durable;
}
this.compact = !!options.compact;
if (this.durable) {
var requests = {};
var _loop_1 = function (i) {
var storageKey = localStorage.key(i);
if (storageKey.indexOf('serilogger-' + this_1.toString()) !== 0) {
return "continue";
}
var body = localStorage.getItem(storageKey);
requests[storageKey] = this_1.postToLogger(this_1.url, body)
.then(function () { return localStorage.removeItem(storageKey); })
.catch(function (reason) {
if (_this.suppressErrors)
_this.logSuppressedError(reason);
throw new Error(reason);
});
};
var this_1 = this;
for (var i = 0; i < localStorage.length; ++i) {
_loop_1(i);
}
}
if (this.levelSwitch !== null) {
this.refreshLevelSwitchTimeoutId = setTimeout(function () { return _this.sendToServer([]); }, this.refreshLevelSwitchTimeoutInterval);
}
if (this.headers !== null) {
this.headers = options.headers;
}
}
ApiSink.prototype.toString = function () {
return 'ApiSink';
};
ApiSink.prototype.emit = function (events) {
var _this = this;
var filteredEvents = this.levelSwitch
? events.filter(function (e) { return _this.levelSwitch.isEnabled(e.level); })
: events;
if (!filteredEvents.length) {
return Promise.resolve();
}
return this.sendToServer(filteredEvents);
};
ApiSink.prototype.flush = function () {
return Promise.resolve();
};
ApiSink.prototype.sendToServer = function (events) {
return __awaiter(this, void 0, void 0, function () {
var seqEvents, body, storageKey, response, json, reason_1;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
seqEvents = this.compact ? events.reduce(function (s, e) {
var mappedEvent = __assign({ '@l': _this.mapLogLevel(e.level), '@mt': e.messageTemplate.raw, '@t': e.timestamp }, e.properties);
if (e.error instanceof Error && e.error.stack) {
mappedEvent['@x'] = e.error.stack;
}
return "" + s + JSON.stringify(mappedEvent) + "\n";
}, '').replace(/\s+$/g, '') : events.map(function (e) {
var mappedEvent = {
Level: _this.mapLogLevel(e.level),
MessageTemplate: e.messageTemplate.raw,
Properties: e.properties,
Timestamp: e.timestamp
};
if (e.error instanceof Error && e.error.stack) {
mappedEvent['Exception'] = e.error.stack;
}
return mappedEvent;
});
body = this.compact ? seqEvents : JSON.stringify({
Events: seqEvents
});
if (this.durable) {
storageKey = "serilogger-" + this.toString() + "-" + new Date().getTime() + "-" + (Math.floor(Math.random() * 1000000) + 1);
localStorage.setItem(storageKey, body);
}
_a.label = 1;
case 1:
_a.trys.push([1, 4, , 5]);
return [4 /*yield*/, this.postToLogger(this.url, body)];
case 2:
response = _a.sent();
return [4 /*yield*/, response.json()];
case 3:
json = _a.sent();
this.updateLogLevel(json);
if (storageKey)
localStorage.removeItem(storageKey);
return [3 /*break*/, 5];
case 4:
reason_1 = _a.sent();
return [2 /*return*/, this.suppressErrors ? this.logSuppressedError(reason_1) : Promise.reject(reason_1)];
case 5: return [2 /*return*/];
}
});
});
};
ApiSink.prototype.updateLogLevel = function (response) {
var _this = this;
if (!this.levelSwitch)
return;
if (this.refreshLevelSwitchTimeoutId) {
clearTimeout(this.refreshLevelSwitchTimeoutId);
this.refreshLevelSwitchTimeoutId = setTimeout(function () { return _this.sendToServer([]); }, this.refreshLevelSwitchTimeoutInterval);
}
if (response && response.MinimumLevelAccepted) {
switch (response.MinimumLevelAccepted) {
case 'Fatal':
this.levelSwitch.fatal();
break;
case 'Error':
this.levelSwitch.error();
break;
case 'Warning':
this.levelSwitch.warning();
break;
case 'Information':
this.levelSwitch.information();
break;
case 'Debug':
this.levelSwitch.debug();
break;
case 'Verbose':
this.levelSwitch.verbose();
break;
}
}
};
ApiSink.prototype.logSuppressedError = function (reason) {
if (typeof console !== 'undefined' && console.warn) {
console.warn('Suppressed error when logging to ' + this.toString() + ': ' + reason);
}
};
ApiSink.prototype.mapLogLevel = function (logLevel) {
if (logLevel === 1) {
return 'Fatal';
}
else if (logLevel === 3) {
return 'Error';
}
else if (logLevel === 7) {
return 'Warning';
}
else if (logLevel === 31) {
return 'Debug';
}
else if (logLevel === 63) {
return 'Verbose';
}
// Default to Information.
return 'Information';
};
ApiSink.prototype.postToLogger = function (url, body) {
var promise = fetch("" + url, {
headers: this.headers || {},
method: 'POST',
body: body
});
return promise;
};
return ApiSink;
}());
var SeqSink = /** @class */ (function (_super) {
__extends(SeqSink, _super);
function SeqSink(options) {
var _this = _super.call(this, {
compact: options.compact || false,
durable: options.durable || false,
levelSwitch: options.levelSwitch,
suppressErrors: options.suppressErrors || true,
url: options.url,
headers: null
}) || this;
_this.apiKey = null;
_this.apiKey = options.apiKey;
return _this;
}
SeqSink.prototype.toString = function () {
return 'SeqSink';
};
SeqSink.prototype.postToLogger = function (url, body) {
var apiKeyParameter = this.apiKey ? "?apiKey=" + this.apiKey : '';
var promise = fetch(url + "/api/events/raw" + apiKeyParameter, {
headers: {
'content-type': this.compact ? 'application/vnd.serilog.clef' : 'application/json'
},
method: 'POST',
body: body
});
return promise;
};
return SeqSink;
}(ApiSink));
/**
* Configures pipelines for new logger instances.
*/
var LoggerConfiguration = /** @class */ (function () {
function LoggerConfiguration() {
var _this = this;
/**
* Sets the minimum level for any subsequent stages in the pipeline.
*/
this.minLevel = Object.assign(function (levelOrSwitch) {
if (typeof levelOrSwitch === 'undefined' || levelOrSwitch === null) {
throw new TypeError('Argument "levelOrSwitch" is not a valid LogEventLevel value or DynamicLevelSwitch instance.');
}
else if (levelOrSwitch instanceof DynamicLevelSwitch) {
var switchStage = new DynamicLevelSwitchStage(levelOrSwitch);
switchStage.setFlushDelegate(function () { return _this._stages.flush(); });
_this._stages.addStage(switchStage);
return _this;
}
else if (typeof levelOrSwitch === 'string') {
var level_1 = LogEventLevel[levelOrSwitch.toLowerCase()];
if (typeof level_1 === 'undefined' || level_1 === null) {
throw new TypeError('Argument "levelOrSwitch" is not a valid LogEventLevel value.');
}
return _this.filter(function (e) { return isEnabled(level_1, e.level); });
}
else {
return _this.filter(function (e) { return isEnabled(levelOrSwitch, e.level); });
}
}, {
fatal: function () { return _this.minLevel(LogEventLevel.fatal); },
error: function () { return _this.minLevel(LogEventLevel.error); },
warning: function () { return _this.minLevel(LogEventLevel.warning); },
information: function () { return _this.minLevel(LogEventLevel.information); },
debug: function () { return _this.minLevel(LogEventLevel.debug); },
verbose: function () { return _this.minLevel(LogEventLevel.verbose); }
});
this._stages = new Pipeline();
this._sinks = [];
this._suppressErrors = true;
}
/**
* Adds a sink to the pipeline.
* @param {Sink} sink The sink to add.
*/
LoggerConfiguration.prototype.writeTo = function (sink) {
this._sinks.push(new SinkStage(sink));
return this;
};
/**
* Adds a filter to the pipeline.
* @param {(e: LogEvent) => boolean} predicate Filter predicate to use.
*/
LoggerConfiguration.prototype.filter = function (predicate) {
if (predicate instanceof Function) {
this._stages.addStage(new FilterStage(predicate));
}
else {
throw new TypeError('Argument "predicate" must be a function.');
}
return this;
};
/**
* Adds an enricher to the pipeline.
*/
LoggerConfiguration.prototype.enrich = function (enricher) {
if (enricher instanceof Function || enricher instanceof Object) {
this._stages.addStage(new EnrichStage(enricher));
}
else {
throw new TypeError('Argument "enricher" must be either a function or an object.');
}
return this;
};
/**
* Enable or disable error suppress