@axiomhq/logging
Version:
The official logging package for Axiom
196 lines (195 loc) • 6.63 kB
JavaScript
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