UNPKG

@axiomhq/logging

Version:
1 lines 11.9 kB
{"version":3,"file":"logger.cjs","sources":["../../src/logger.ts"],"sourcesContent":["import { defaultFormatters } from 'src/default-formatters';\nimport { Transport } from '.';\nimport { Version, isBrowser } from './runtime';\n\nconst LOG_LEVEL = 'info';\n\n/**\n * Symbol used to specify properties that should be added to the root of the log event\n * rather than to the fields property.\n *\n * @example\n * const EVENT = Symbol.for('logging.event');\n * logger.info(\"User logged in\", {\n * userId: 123,\n * [EVENT]: { traceId: \"abc123\" }\n * });\n */\nexport const EVENT = Symbol.for('logging.event');\n\n/**\n * LogEvent interface representing a log entry.\n * This interface defines the structure of log events processed by the logger.\n */\nexport interface LogEvent extends Record<string, any> {\n level: string;\n message: string;\n fields: any;\n _time: string;\n '@app': {\n [key: FrameworkIdentifier['name']]: FrameworkIdentifier['version'];\n };\n source: string;\n}\nexport const LogLevelValue = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n off: 100,\n} as const;\n\nexport const LogLevel = {\n debug: 'debug',\n info: 'info',\n warn: 'warn',\n error: 'error',\n off: 'off',\n} as const;\n\nexport type LogLevelValue = (typeof LogLevelValue)[keyof typeof LogLevelValue];\nexport type LogLevel = keyof typeof LogLevelValue;\n\nexport type Formatter<T extends Record<string, any> = LogEvent, U extends Record<string, any> = LogEvent> = (\n logEvent: T,\n) => U;\n\nexport type FrameworkIdentifier = {\n name: `${string}-version`;\n version: string;\n};\n\nexport type LoggerConfig = {\n args?: Record<string | symbol, any>;\n transports: [Transport, ...Transport[]];\n logLevel?: LogLevel;\n formatters?: Array<Formatter>;\n overrideDefaultFormatters?: boolean;\n};\n\nexport class Logger {\n children: Logger[] = [];\n public logLevel: LogLevelValue = LogLevelValue.debug;\n public config: LoggerConfig;\n\n constructor(public initConfig: LoggerConfig) {\n // check if user passed a log level, if not the default init value will be used as is.\n if (this.initConfig.logLevel != undefined) {\n this.logLevel = LogLevelValue[this.initConfig.logLevel];\n } else if (LOG_LEVEL) {\n this.logLevel = LogLevelValue[LOG_LEVEL as LogLevel];\n }\n\n this.config = { ...initConfig };\n\n if (!this.config.overrideDefaultFormatters) {\n this.config.formatters = [...defaultFormatters, ...(this.config.formatters ?? [])];\n }\n }\n\n raw(log: any) {\n this.config.transports.forEach((transport) => transport.log([log]));\n }\n\n /**\n * Log a debug message\n * @param message The log message\n * @param options Log options that can include fields and a special EVENT symbol\n *\n * @example\n * // Add fields to the log event\n * logger.debug(\"User action\", { userId: 123 });\n */\n debug = (message: string, args: Record<string | symbol, any> = {}) => {\n this.log(LogLevel.debug, message, args);\n };\n\n /**\n * Log an info message\n * @param message The log message\n * @param options Log options that can include fields and a special EVENT symbol\n *\n * @example\n * // Add fields to the log event\n * logger.info(\"User logged in\", { userId: 123 });\n */\n info = (message: string, args: Record<string | symbol, any> = {}) => {\n this.log(LogLevel.info, message, args);\n };\n\n /**\n * Log a warning message\n * @param message The log message\n * @param options Log options that can include fields and a special EVENT symbol\n *\n * @example\n * // Add fields to the log event\n * logger.warn(\"Rate limit approaching\", { requestCount: 950 });\n */\n warn = (message: string, args: Record<string | symbol, any> = {}) => {\n this.log(LogLevel.warn, message, args);\n };\n\n /**\n * Log an error message\n * @param message The log message\n * @param options Log options that can include fields and a special EVENT symbol\n *\n * @example\n * // Log an error with stack trace\n * try {\n * // some code that throws\n * } catch (err) {\n * logger.error(\"Operation failed\", err);\n * }\n */\n error = (message: string, args: Record<string | symbol, any> = {}) => {\n this.log(LogLevel.error, message, args);\n };\n\n /**\n * Create a child logger with additional context fields\n * @param fields Additional context fields to include in all logs from this logger\n *\n * @example\n * // Create a child logger with additional fields\n * const childLogger = logger.with({ userId: 123 });\n */\n with = (fields: Record<string | symbol, any>) => {\n const { [EVENT]: argsEventFields, ...argsRest } = this.config.args ?? {};\n const { [EVENT]: _eventFields, ...rest } = fields;\n\n const eventFields = { ...(argsEventFields ?? {}), ...(_eventFields ?? {}) };\n\n const childConfig = { ...this.config, args: { ...argsRest, ...rest, [EVENT]: eventFields } };\n\n const child = new Logger(childConfig);\n this.children.push(child);\n return child;\n };\n\n private _transformEvent = (level: LogLevel, message: string, args: Record<string | symbol, any> = {}) => {\n let rootFields = {};\n let fields = this.config.args ?? {};\n if (this.config.args && EVENT in this.config.args) {\n const { [EVENT]: argsEventFields, ...argsRest } = this.config.args ?? {};\n rootFields = { ...(argsEventFields ?? {}) };\n fields = argsRest;\n }\n\n const logEvent: LogEvent = {\n level: LogLevel[level].toString(),\n message,\n _time: new Date(Date.now()).toISOString(),\n fields: fields,\n '@app': {\n 'axiom-logging-version': Version ?? 'unknown',\n },\n source: isBrowser ? 'browser-log' : 'server-log',\n };\n\n // Apply root properties from logger config if present\n if (rootFields && typeof rootFields === 'object') {\n Object.assign(logEvent, rootFields);\n }\n\n // Handle Error objects\n if (args instanceof Error) {\n logEvent.fields = {\n ...logEvent.fields,\n message: args.message,\n stack: args.stack,\n name: args.name,\n };\n }\n\n if (typeof args === 'object' && args !== null) {\n // Extract root properties before JSON serialization (since symbols are lost in JSON.stringify)\n const { [EVENT]: rootArgs, ...fieldArgs } = args as Record<string | symbol, any>;\n\n // Process regular fields\n const parsedArgs = JSON.parse(JSON.stringify(fieldArgs, jsonFriendlyErrorReplacer));\n\n // Apply root properties directly to the root of logEvent\n if (rootArgs && typeof rootArgs === 'object' && rootArgs !== null) {\n Object.assign(logEvent, rootArgs);\n }\n\n // Any remaining properties in options are treated as fields\n if (Object.keys(parsedArgs).length > 0) {\n logEvent.fields = { ...logEvent.fields, ...parsedArgs };\n }\n // Handle array-like values\n } else if (Array.isArray(args)) {\n logEvent.fields = { ...logEvent.fields, args: args };\n }\n\n if (this.config.formatters && this.config.formatters.length > 0) {\n // Apply formatters to the entire logEvent\n return this.config.formatters.reduce((acc, formatter) => formatter(acc), logEvent);\n }\n\n return logEvent;\n };\n\n /**\n * Log a message with the specified level\n * @param level The log level\n * @param message The log message\n * @param options Log options or Error object\n */\n log = (level: LogLevel, message: string, args: Record<string | symbol, any> = {}) => {\n this.config.transports.forEach((transport) => transport.log([this._transformEvent(level, message, args)]));\n };\n\n flush = async () => {\n const promises = [\n ...this.config.transports.map((transport) => transport.flush()),\n ...this.children.map((child) => child.flush()),\n ];\n\n await Promise.allSettled(promises);\n };\n}\n\nfunction jsonFriendlyErrorReplacer(_key: string, value: any) {\n if (value instanceof Error) {\n return {\n // Pull all enumerable properties, supporting properties on custom Errors\n ...value,\n // Explicitly pull Error's non-enumerable properties\n name: value.name,\n message: value.message,\n stack: value.stack,\n };\n }\n\n return value;\n}\n"],"names":["defaultFormatters","Version","isBrowser"],"mappings":"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"}