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":["Version","isBrowser","defaultFormatters"],"mappings":"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"}