UNPKG

@loglayer/shared

Version:

Shared utilities and types for loglayer packages.

233 lines (232 loc) 6.35 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); //#region src/common.types.ts let LogLevel = /* @__PURE__ */ function(LogLevel) { LogLevel["info"] = "info"; LogLevel["warn"] = "warn"; LogLevel["error"] = "error"; LogLevel["debug"] = "debug"; LogLevel["trace"] = "trace"; LogLevel["fatal"] = "fatal"; return LogLevel; }({}); /** * Mapping of log levels to their numeric values. */ const LogLevelPriority = { ["trace"]: 10, ["debug"]: 20, ["info"]: 30, ["warn"]: 40, ["error"]: 50, ["fatal"]: 60 }; /** * Mapping of numeric values to their log level names. */ const LogLevelPriorityToNames = { 10: "trace", 20: "debug", 30: "info", 40: "warn", 50: "error", 60: "fatal" }; //#endregion //#region src/lazy.ts /** * Symbol used to identify lazy values in context and metadata. * Can be used to check if a value is a lazy wrapper: `LAZY_SYMBOL in value`. * * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} */ const LAZY_SYMBOL = Symbol.for("loglayer.lazy"); /** * String constant used as a replacement value when a lazy callback fails during evaluation. * Exported so users can programmatically detect lazy evaluation failures in their log output. * * @see {@link https://loglayer.dev/logging-api/lazy-evaluation#error-handling | Lazy Evaluation Error Handling Docs} */ const LAZY_EVAL_ERROR = "[LazyEvalError]"; /** * Wraps a callback function to defer its evaluation until log time. * * The callback will only be invoked if the log level is enabled, * avoiding unnecessary computation for disabled log levels. * * Can be used in both `withContext()` and `withMetadata()` at the root level. * * When the callback returns a `Promise` (i.e., is an async function), the * log method will return `Promise<void>` so TypeScript can track that the * operation is asynchronous. * * Adapted from [LogTape's lazy evaluation](https://logtape.org/manual/lazy). * * @example * ```typescript * import { LogLayer, lazy } from "loglayer"; * * const log = new LogLayer({ ... }); * * // Dynamic context - evaluated on each log call * log.withContext({ * memoryUsage: lazy(() => process.memoryUsage().heapUsed), * }); * * // Dynamic metadata - evaluated only if debug is enabled * log.withMetadata({ * data: lazy(() => JSON.stringify(largeObject)), * }).debug("Processing complete"); * ``` * * @see {@link https://loglayer.dev/logging-api/lazy-evaluation | Lazy Evaluation Docs} */ function lazy(fn) { return { [LAZY_SYMBOL]: fn }; } /** * Checks if a value is a lazy value created by {@link lazy}. * @internal */ function isLazy(value) { return value != null && typeof value === "object" && LAZY_SYMBOL in value; } /** * Counts the number of lazy values in a record. * @internal */ function countLazyValues(obj) { let count = 0; for (const key of Object.keys(obj)) if (isLazy(obj[key])) count++; return count; } /** * Resolves any lazy values in a record at the root level. * Returns the original object if no lazy values are found (optimization). * If a lazy callback throws, the value is replaced with LAZY_EVAL_ERROR * and the error is collected in the result. * @internal */ function resolveLazyValues(obj) { let hasLazy = false; for (const key of Object.keys(obj)) if (isLazy(obj[key])) { hasLazy = true; break; } if (!hasLazy) return { resolved: obj, errors: null }; const result = {}; let errors = null; for (const key of Object.keys(obj)) { const value = obj[key]; if (isLazy(value)) try { result[key] = value[LAZY_SYMBOL](); } catch (e) { result[key] = LAZY_EVAL_ERROR; if (!errors) errors = []; errors.push({ key, error: e }); } else result[key] = value; } return { resolved: result, errors }; } /** * Checks if any values in a record are Promises. * @internal */ function hasPromiseValues(obj) { for (const key of Object.keys(obj)) if (obj[key] instanceof Promise) return true; return false; } /** * Replaces any Promise values in a record with LAZY_EVAL_ERROR. * Used to strip async lazy values from context where only sync lazy is supported. * Returns the keys that were replaced. * @internal */ function replacePromiseValues(obj) { let asyncKeys = null; const result = {}; for (const key of Object.keys(obj)) if (obj[key] instanceof Promise) { result[key] = LAZY_EVAL_ERROR; if (!asyncKeys) asyncKeys = []; asyncKeys.push(key); } else result[key] = obj[key]; if (!asyncKeys) return { resolved: obj, asyncKeys: null }; return { resolved: result, asyncKeys }; } /** * Resolves any Promise values in a record using Promise.allSettled. * If a Promise rejects, the value is replaced with LAZY_EVAL_ERROR * and the error is collected in the result. * @internal */ async function resolvePromiseValues(obj) { const keys = Object.keys(obj); const settled = await Promise.allSettled(keys.map((key) => Promise.resolve(obj[key]))); const result = {}; let errors = null; for (let i = 0; i < keys.length; i++) { const s = settled[i]; if (s.status === "fulfilled") result[keys[i]] = s.value; else { result[keys[i]] = LAZY_EVAL_ERROR; if (!errors) errors = []; errors.push({ key: keys[i], error: s.reason }); } } return { resolved: result, errors }; } //#endregion //#region src/template-utils.ts /** * Converts tagged template arguments to a message array. * Detects tagged templates by checking for the `raw` property on TemplateStringsArray. */ function resolveMessages(args) { const first = args[0]; if (Array.isArray(first) && typeof first.raw !== "undefined") { const strings = first; const values = args.slice(1); let result = ""; for (let i = 0; i < strings.length; i++) { result += strings[i]; if (i < values.length) result += String(values[i]); } return [result]; } return args; } //#endregion exports.LAZY_EVAL_ERROR = LAZY_EVAL_ERROR; exports.LAZY_SYMBOL = LAZY_SYMBOL; exports.LogLevel = LogLevel; exports.LogLevelPriority = LogLevelPriority; exports.LogLevelPriorityToNames = LogLevelPriorityToNames; exports.countLazyValues = countLazyValues; exports.hasPromiseValues = hasPromiseValues; exports.isLazy = isLazy; exports.lazy = lazy; exports.replacePromiseValues = replacePromiseValues; exports.resolveLazyValues = resolveLazyValues; exports.resolveMessages = resolveMessages; exports.resolvePromiseValues = resolvePromiseValues;