UNPKG

@axiomhq/logging

Version:
196 lines (195 loc) 6.63 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; import { defaultFormatters } from "./default-formatters.js"; import { Version, isBrowser } from "./runtime.js"; const LOG_LEVEL = "info"; const EVENT = Symbol.for("logging.event"); const LogLevelValue = { debug: 0, info: 1, warn: 2, error: 3, off: 100 }; const LogLevel = { debug: "debug", info: "info", warn: "warn", error: "error", off: "off" }; class Logger { constructor(initConfig) { __publicField(this, "children", []); __publicField(this, "logLevel", LogLevelValue.debug); __publicField(this, "config"); /** * Log a debug message * @param message The log message * @param options Log options that can include fields and a special EVENT symbol * * @example * // Add fields to the log event * logger.debug("User action", { userId: 123 }); */ __publicField(this, "debug", (message, args = {}) => { this.log(LogLevel.debug, message, args); }); /** * Log an info message * @param message The log message * @param options Log options that can include fields and a special EVENT symbol * * @example * // Add fields to the log event * logger.info("User logged in", { userId: 123 }); */ __publicField(this, "info", (message, args = {}) => { this.log(LogLevel.info, message, args); }); /** * Log a warning message * @param message The log message * @param options Log options that can include fields and a special EVENT symbol * * @example * // Add fields to the log event * logger.warn("Rate limit approaching", { requestCount: 950 }); */ __publicField(this, "warn", (message, args = {}) => { this.log(LogLevel.warn, message, args); }); /** * Log an error message * @param message The log message * @param options Log options that can include fields and a special EVENT symbol * * @example * // Log an error with stack trace * try { * // some code that throws * } catch (err) { * logger.error("Operation failed", err); * } */ __publicField(this, "error", (message, args = {}) => { this.log(LogLevel.error, message, args); }); /** * Create a child logger with additional context fields * @param fields Additional context fields to include in all logs from this logger * * @example * // Create a child logger with additional fields * const childLogger = logger.with({ userId: 123 }); */ __publicField(this, "with", (fields) => { const { [EVENT]: argsEventFields, ...argsRest } = this.config.args ?? {}; const { [EVENT]: _eventFields, ...rest } = fields; const eventFields = { ...argsEventFields ?? {}, ..._eventFields ?? {} }; const childConfig = { ...this.config, args: { ...argsRest, ...rest, [EVENT]: eventFields } }; const child = new Logger(childConfig); this.children.push(child); return child; }); __publicField(this, "_transformEvent", (level, message, args = {}) => { let rootFields = {}; let fields = this.config.args ?? {}; if (this.config.args && EVENT in this.config.args) { const { [EVENT]: argsEventFields, ...argsRest } = this.config.args ?? {}; rootFields = { ...argsEventFields ?? {} }; fields = argsRest; } const logEvent = { level: LogLevel[level].toString(), message, _time: new Date(Date.now()).toISOString(), fields, "@app": { "axiom-logging-version": Version }, source: isBrowser ? "browser-log" : "server-log" }; if (rootFields && typeof rootFields === "object") { Object.assign(logEvent, rootFields); } if (args instanceof Error) { logEvent.fields = { ...logEvent.fields, message: args.message, stack: args.stack, name: args.name }; } if (typeof args === "object" && args !== null) { const { [EVENT]: rootArgs, ...fieldArgs } = args; const parsedArgs = JSON.parse(JSON.stringify(fieldArgs, jsonFriendlyErrorReplacer)); if (rootArgs && typeof rootArgs === "object" && rootArgs !== null) { Object.assign(logEvent, rootArgs); } if (Object.keys(parsedArgs).length > 0) { logEvent.fields = { ...logEvent.fields, ...parsedArgs }; } } else if (Array.isArray(args)) { logEvent.fields = { ...logEvent.fields, args }; } if (this.config.formatters && this.config.formatters.length > 0) { return this.config.formatters.reduce((acc, formatter) => formatter(acc), logEvent); } return logEvent; }); /** * Log a message with the specified level * @param level The log level * @param message The log message * @param options Log options or Error object */ __publicField(this, "log", (level, message, args = {}) => { this.config.transports.forEach((transport) => transport.log([this._transformEvent(level, message, args)])); }); __publicField(this, "flush", async () => { const promises = [ ...this.config.transports.map((transport) => transport.flush()), ...this.children.map((child) => child.flush()) ]; await Promise.allSettled(promises); }); this.initConfig = initConfig; if (this.initConfig.logLevel != void 0) { this.logLevel = LogLevelValue[this.initConfig.logLevel]; } else { this.logLevel = LogLevelValue[LOG_LEVEL]; } this.config = { ...initConfig }; if (!this.config.overrideDefaultFormatters) { this.config.formatters = [...defaultFormatters, ...this.config.formatters ?? []]; } } raw(log) { this.config.transports.forEach((transport) => transport.log([log])); } } function jsonFriendlyErrorReplacer(_key, value) { if (value instanceof Error) { return { // Pull all enumerable properties, supporting properties on custom Errors ...value, // Explicitly pull Error's non-enumerable properties name: value.name, message: value.message, stack: value.stack }; } return value; } export { EVENT, LogLevel, LogLevelValue, Logger }; //# sourceMappingURL=logger.js.map