@logtape/logtape 2.4.0-dev.862 → 2.4.0-dev.868

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.d.cts CHANGED
@@ -60,16 +60,26 @@ interface LoggerConfig<TSinkId extends string, TFilterId extends string> {
60
60
  */
61
61
  sinks?: TSinkId[];
62
62
  /**
63
- * Whether to inherit the sinks that the parent would use for a record's
64
- * level. If `inherit`, those sinks are used along with the specified sinks.
65
- * The parent's `lowestLevel` continues to apply to the inherited sinks. If
66
- * `override`, only the specified sinks are used.
63
+ * How to combine the logger's sinks with its ancestors' sinks.
64
+ *
65
+ * If `inherit`, the sinks that the parent would use for a record's level
66
+ * are used along with the specified sinks. The parent's `lowestLevel`
67
+ * continues to apply to the inherited sinks.
68
+ *
69
+ * If `override`, only the specified sinks are used.
70
+ *
71
+ * If `forward`, every ancestor's configured sinks are used along with the
72
+ * specified sinks, ignoring each ancestor's `lowestLevel` (including
73
+ * `null`); only this logger's own `lowestLevel` applies. An ancestor
74
+ * configured with `parentSinks: "override"` forms a boundary: its own
75
+ * sinks are still inherited, but nothing beyond it. Repeated references
76
+ * to the same sink are not deduplicated. Available since 2.4.0.
67
77
  *
68
78
  * The default is `inherit`.
69
79
  * @default "inherit"
70
80
  * @since 0.6.0
71
81
  */
72
- parentSinks?: "inherit" | "override";
82
+ parentSinks?: "inherit" | "override" | "forward";
73
83
  /**
74
84
  * The filter identifiers to use. If no filters are specified, the logger
75
85
  * uses the filters from the nearest ancestor that has them. Specifying one
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAkBA;AAAuB,UAAN,MAAM,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAA;;;;EAUK,KAAE,EALrB,MAKqB,CALd,OAKc,EALL,IAKK,CAAA;EAAU;;;;EAKjB,OAMqB,CAAA,EAXhC,MAWgC,CAXzB,SAWyB,EAXd,UAWc,CAAA;EAAM;AAAP;AAkB3C;EAAwB,OAAA,EAxBb,YAwBa,CAxBA,OAwBA,EAxBS,SAwBT,CAAA,EAAA;EAAA;;;AACN;EAEb,mBAAA,CAAA,EArBmB,mBAqBD,CArBqB,MAqBrB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EAAA;;;EAAuC,KAC1D,CAAA,EAAA,OAAA;AAAO;AAKX;;;;;AAwCwB;AAkJxB;;;;AAGU,KAtME,YAsMF,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,GArMR,gBAqMQ,CArMS,OAqMT,EArMkB,SAqMlB,CAAA;KAnML,kBAmMkC,CAAA,OAAA,CAAA,GAnMJ,OAmMI,SAnMY,WAmMZ,CAAA,OAAA,CAAA,GAAA,KAAA,GAlMnC,OAkMmC;AAAO;AAsD9C;;AACiB,UApPA,YAoPA,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAO;;AAAR;AAyChB;EAAgC,QAAA,EAAA,MAAA,GAAA,MAAA,EAAA;EAAA;;;EAKV,KACJ,CAAA,EAtRR,OAsRQ,EAAA;EAAO;;;AACf;AAsDV;;;;;;EAM4C,WAA1B,CAAA,EAAA,SAAA,GAAA,UAAA;EAAkB;;AACf;AAiMrB;AAOA;AAYA;EAoBsB,OAAA,CAAA,EAxiBV,SAwiBiB,EAAI;EAkCjB;AAoKhB;;;;gBAvuBgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkJM,oEAGZ,OAAO,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDvB,wEACN,OAAO,SAAS;;;;;;;;;;;;;;iBAyCJ,8EAKZ,aAAa,SAAS,4BACd,UACf,QAAQ,QAAQ;;;;;;;;;;;;iBAsDH,kFAKN,aAAa,SAAS,4BACd,mBAAmB,WAClC,mBAAmB;;;;;iBAiMN,SAAA,CAAA,GAAa;;;;iBAOP,KAAA,CAAA,GAAS;;;;;;iBAYf,SAAA,CAAA;;;;iBAoBM,OAAA,CAAA,GAAW;;;;;;iBAkCjB,WAAA,CAAA;;;;cAoKH,WAAA,SAAoB,KAAK"}
1
+ {"version":3,"file":"config.d.cts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAkBA;AAAuB,UAAN,MAAM,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAA;;;;EAUK,KAAE,EALrB,MAKqB,CALd,OAKc,EALL,IAKK,CAAA;EAAU;;;;EAKjB,OAMqB,CAAA,EAXhC,MAWgC,CAXzB,SAWyB,EAXd,UAWc,CAAA;EAAM;AAAP;AAkB3C;EAAwB,OAAA,EAxBb,YAwBa,CAxBA,OAwBA,EAxBS,SAwBT,CAAA,EAAA;EAAA;;;AACN;EAEb,mBAAA,CAAA,EArBmB,mBAqBD,CArBqB,MAqBrB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EAAA;;;EAAuC,KAC1D,CAAA,EAAA,OAAA;AAAO;AAKX;;;;;AAkDwB;AAkJxB;;;;AAGU,KAhNE,YAgNF,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,GA/MR,gBA+MQ,CA/MS,OA+MT,EA/MkB,SA+MlB,CAAA;KA7ML,kBA6MkC,CAAA,OAAA,CAAA,GA7MJ,OA6MI,SA7MY,WA6MZ,CAAA,OAAA,CAAA,GAAA,KAAA,GA5MnC,OA4MmC;AAAO;AAsD9C;;AACiB,UA9PA,YA8PA,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAO;;AAAR;AAyChB;EAAgC,QAAA,EAAA,MAAA,GAAA,MAAA,EAAA;EAAA;;;EAKV,KACJ,CAAA,EAhSR,OAgSQ,EAAA;EAAO;;;AACf;AAsDV;;;;;;;;;AAOqB;AAiMrB;AAOA;AAYA;AAoBA;AAkCA;AAoKA;;;;;;;;YA9uBY;;;;;;gBAOI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkJM,oEAGZ,OAAO,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDvB,wEACN,OAAO,SAAS;;;;;;;;;;;;;;iBAyCJ,8EAKZ,aAAa,SAAS,4BACd,UACf,QAAQ,QAAQ;;;;;;;;;;;;iBAsDH,kFAKN,aAAa,SAAS,4BACd,mBAAmB,WAClC,mBAAmB;;;;;iBAiMN,SAAA,CAAA,GAAa;;;;iBAOP,KAAA,CAAA,GAAS;;;;;;iBAYf,SAAA,CAAA;;;;iBAoBM,OAAA,CAAA,GAAW;;;;;;iBAkCjB,WAAA,CAAA;;;;cAoKH,WAAA,SAAoB,KAAK"}
package/dist/config.d.ts CHANGED
@@ -60,16 +60,26 @@ interface LoggerConfig<TSinkId extends string, TFilterId extends string> {
60
60
  */
61
61
  sinks?: TSinkId[];
62
62
  /**
63
- * Whether to inherit the sinks that the parent would use for a record's
64
- * level. If `inherit`, those sinks are used along with the specified sinks.
65
- * The parent's `lowestLevel` continues to apply to the inherited sinks. If
66
- * `override`, only the specified sinks are used.
63
+ * How to combine the logger's sinks with its ancestors' sinks.
64
+ *
65
+ * If `inherit`, the sinks that the parent would use for a record's level
66
+ * are used along with the specified sinks. The parent's `lowestLevel`
67
+ * continues to apply to the inherited sinks.
68
+ *
69
+ * If `override`, only the specified sinks are used.
70
+ *
71
+ * If `forward`, every ancestor's configured sinks are used along with the
72
+ * specified sinks, ignoring each ancestor's `lowestLevel` (including
73
+ * `null`); only this logger's own `lowestLevel` applies. An ancestor
74
+ * configured with `parentSinks: "override"` forms a boundary: its own
75
+ * sinks are still inherited, but nothing beyond it. Repeated references
76
+ * to the same sink are not deduplicated. Available since 2.4.0.
67
77
  *
68
78
  * The default is `inherit`.
69
79
  * @default "inherit"
70
80
  * @since 0.6.0
71
81
  */
72
- parentSinks?: "inherit" | "override";
82
+ parentSinks?: "inherit" | "override" | "forward";
73
83
  /**
74
84
  * The filter identifiers to use. If no filters are specified, the logger
75
85
  * uses the filters from the nearest ancestor that has them. Specifying one
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAkBA;AAAuB,UAAN,MAAM,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAA;;;;EAUK,KAAE,EALrB,MAKqB,CALd,OAKc,EALL,IAKK,CAAA;EAAU;;;;EAKjB,OAMqB,CAAA,EAXhC,MAWgC,CAXzB,SAWyB,EAXd,UAWc,CAAA;EAAM;AAAP;AAkB3C;EAAwB,OAAA,EAxBb,YAwBa,CAxBA,OAwBA,EAxBS,SAwBT,CAAA,EAAA;EAAA;;;AACN;EAEb,mBAAA,CAAA,EArBmB,mBAqBD,CArBqB,MAqBrB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EAAA;;;EAAuC,KAC1D,CAAA,EAAA,OAAA;AAAO;AAKX;;;;;AAwCwB;AAkJxB;;;;AAGU,KAtME,YAsMF,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,GArMR,gBAqMQ,CArMS,OAqMT,EArMkB,SAqMlB,CAAA;KAnML,kBAmMkC,CAAA,OAAA,CAAA,GAnMJ,OAmMI,SAnMY,WAmMZ,CAAA,OAAA,CAAA,GAAA,KAAA,GAlMnC,OAkMmC;AAAO;AAsD9C;;AACiB,UApPA,YAoPA,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAO;;AAAR;AAyChB;EAAgC,QAAA,EAAA,MAAA,GAAA,MAAA,EAAA;EAAA;;;EAKV,KACJ,CAAA,EAtRR,OAsRQ,EAAA;EAAO;;;AACf;AAsDV;;;;;;EAM4C,WAA1B,CAAA,EAAA,SAAA,GAAA,UAAA;EAAkB;;AACf;AAiMrB;AAOA;AAYA;EAoBsB,OAAA,CAAA,EAxiBV,SAwiBiB,EAAI;EAkCjB;AAoKhB;;;;gBAvuBgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkJM,oEAGZ,OAAO,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDvB,wEACN,OAAO,SAAS;;;;;;;;;;;;;;iBAyCJ,8EAKZ,aAAa,SAAS,4BACd,UACf,QAAQ,QAAQ;;;;;;;;;;;;iBAsDH,kFAKN,aAAa,SAAS,4BACd,mBAAmB,WAClC,mBAAmB;;;;;iBAiMN,SAAA,CAAA,GAAa;;;;iBAOP,KAAA,CAAA,GAAS;;;;;;iBAYf,SAAA,CAAA;;;;iBAoBM,OAAA,CAAA,GAAW;;;;;;iBAkCjB,WAAA,CAAA;;;;cAoKH,WAAA,SAAoB,KAAK"}
1
+ {"version":3,"file":"config.d.ts","names":[],"sources":["../src/config.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AAkBA;AAAuB,UAAN,MAAM,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAA;;;;EAUK,KAAE,EALrB,MAKqB,CALd,OAKc,EALL,IAKK,CAAA;EAAU;;;;EAKjB,OAMqB,CAAA,EAXhC,MAWgC,CAXzB,SAWyB,EAXd,UAWc,CAAA;EAAM;AAAP;AAkB3C;EAAwB,OAAA,EAxBb,YAwBa,CAxBA,OAwBA,EAxBS,SAwBT,CAAA,EAAA;EAAA;;;AACN;EAEb,mBAAA,CAAA,EArBmB,mBAqBD,CArBqB,MAqBrB,CAAA,MAAA,EAAA,OAAA,CAAA,CAAA;EAAA;;;EAAuC,KAC1D,CAAA,EAAA,OAAA;AAAO;AAKX;;;;;AAkDwB;AAkJxB;;;;AAGU,KAhNE,YAgNF,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,GA/MR,gBA+MQ,CA/MS,OA+MT,EA/MkB,SA+MlB,CAAA;KA7ML,kBA6MkC,CAAA,OAAA,CAAA,GA7MJ,OA6MI,SA7MY,WA6MZ,CAAA,OAAA,CAAA,GAAA,KAAA,GA5MnC,OA4MmC;AAAO;AAsD9C;;AACiB,UA9PA,YA8PA,CAAA,gBAAA,MAAA,EAAA,kBAAA,MAAA,CAAA,CAAA;EAAO;;AAAR;AAyChB;EAAgC,QAAA,EAAA,MAAA,GAAA,MAAA,EAAA;EAAA;;;EAKV,KACJ,CAAA,EAhSR,OAgSQ,EAAA;EAAO;;;AACf;AAsDV;;;;;;;;;AAOqB;AAiMrB;AAOA;AAYA;AAoBA;AAkCA;AAoKA;;;;;;;;YA9uBY;;;;;;gBAOI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkJM,oEAGZ,OAAO,SAAS,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsDvB,wEACN,OAAO,SAAS;;;;;;;;;;;;;;iBAyCJ,8EAKZ,aAAa,SAAS,4BACd,UACf,QAAQ,QAAQ;;;;;;;;;;;;iBAsDH,kFAKN,aAAa,SAAS,4BACd,mBAAmB,WAClC,mBAAmB;;;;;iBAiMN,SAAA,CAAA,GAAa;;;;iBAOP,KAAA,CAAA,GAAS;;;;;;iBAYf,SAAA,CAAA;;;;iBAoBM,OAAA,CAAA,GAAW;;;;;;iBAkCjB,WAAA,CAAA;;;;cAoKH,WAAA,SAAoB,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":["currentConfig: Config<string, string> | null","activeScopedConfigs: Set<CompiledScopedConfig>","strongRefs: Set<LoggerImpl>","filterDisposables: Set<Disposable>","sinkDisposables: Set<Disposable>","asyncFilterDisposables: Set<AsyncDisposable>","asyncSinkDisposables: Set<AsyncDisposable>","unregisterDisposeHook: (() => void) | undefined","cfg: LoggerConfig<TSinkId, TFilterId>","allowAsync: boolean","config: Config<TSinkId, TFilterId>","config: ScopedConfig<TSinkId, TFilterId>","callback: () => TResult","result: Awaited<TResult>","callbackError: unknown","callback: () => SyncCallbackResult<TResult>","result: SyncCallbackResult<TResult>","value: unknown","scopedConfig: CompiledScopedConfig","disposables: Set<Disposable | AsyncDisposable>","errors: unknown[]","functionName: string","callback: () => Promise<T>","callback: () => T","disposables: Set<Disposable>","disposables: Set<AsyncDisposable>","promises: PromiseLike<void>[]","promises: readonly PromiseLike<void>[]","errors: readonly unknown[]","message: string"],"sources":["../src/config.ts"],"sourcesContent":["import type { ContextLocalStorage } from \"./context.ts\";\nimport { type FilterLike, toFilter } from \"./filter.ts\";\nimport type { LogLevel } from \"./level.ts\";\nimport { LoggerImpl } from \"./logger.ts\";\nimport {\n type CompiledScopedConfig,\n compileScopedConfig,\n disposeScopedConfig,\n disposeScopedConfigSync,\n runWithScopedConfig,\n type ScopedConfigLike,\n throwCombinedErrors,\n} from \"./scoped-config.ts\";\nimport { getConsoleSink, type Sink } from \"./sink.ts\";\n\n/**\n * A configuration for the loggers.\n */\nexport interface Config<TSinkId extends string, TFilterId extends string> {\n /**\n * The sinks to use. The keys are the sink identifiers, and the values are\n * {@link Sink}s.\n */\n sinks: Record<TSinkId, Sink>;\n /**\n * The filters to use. The keys are the filter identifiers, and the values\n * are either {@link Filter}s or {@link LogLevel}s.\n */\n filters?: Record<TFilterId, FilterLike>;\n\n /**\n * The loggers to configure.\n */\n loggers: LoggerConfig<TSinkId, TFilterId>[];\n\n /**\n * The context-local storage to use for implicit contexts.\n * @since 0.7.0\n */\n contextLocalStorage?: ContextLocalStorage<Record<string, unknown>>;\n\n /**\n * Whether to reset the configuration before applying this one.\n */\n reset?: boolean;\n}\n\n/**\n * A scoped configuration for the current execution context.\n *\n * Unlike {@link Config}, this type does not include `reset` or\n * `contextLocalStorage`. Scoped configuration changes only the logging policy\n * for a callback; the context-local storage must already be initialized by the\n * process-global configuration.\n *\n * @since 2.3.0\n */\nexport type ScopedConfig<TSinkId extends string, TFilterId extends string> =\n ScopedConfigLike<TSinkId, TFilterId>;\n\ntype SyncCallbackResult<TResult> = TResult extends PromiseLike<unknown> ? never\n : TResult;\n\n/**\n * A logger configuration.\n */\nexport interface LoggerConfig<\n TSinkId extends string,\n TFilterId extends string,\n> {\n /**\n * The category of the logger. If a string, it is equivalent to an array\n * with one element.\n */\n category: string | string[];\n\n /**\n * The sink identifiers to use.\n */\n sinks?: TSinkId[];\n\n /**\n * Whether to inherit the sinks that the parent would use for a record's\n * level. If `inherit`, those sinks are used along with the specified sinks.\n * The parent's `lowestLevel` continues to apply to the inherited sinks. If\n * `override`, only the specified sinks are used.\n *\n * The default is `inherit`.\n * @default \"inherit\"\n * @since 0.6.0\n */\n parentSinks?: \"inherit\" | \"override\";\n\n /**\n * The filter identifiers to use. If no filters are specified, the logger\n * uses the filters from the nearest ancestor that has them. Specifying one\n * or more filters replaces the inherited filters instead of combining with\n * them.\n */\n filters?: TFilterId[];\n\n /**\n * The lowest log level to accept. If `null`, the logger will reject all\n * records.\n * @since 0.8.0\n */\n lowestLevel?: LogLevel | null;\n}\n\n/**\n * The current configuration, if any. Otherwise, `null`.\n */\nlet currentConfig: Config<string, string> | null = null;\nlet activeScopedConfigCount = 0;\nconst activeScopedConfigs: Set<CompiledScopedConfig> = new Set();\nlet globalConfigMutationInProgress = false;\n\n/**\n * Strong references to the loggers.\n * This is to prevent the loggers from being garbage collected so that their\n * sinks and filters are not removed.\n */\nconst strongRefs: Set<LoggerImpl> = new Set();\n\n/**\n * Sync filter disposables to dispose when resetting the configuration.\n */\nconst filterDisposables: Set<Disposable> = new Set();\n\n/**\n * Sync sink disposables to dispose when resetting the configuration.\n */\nconst sinkDisposables: Set<Disposable> = new Set();\n\n/**\n * Async filter disposables to dispose when resetting the configuration.\n */\nconst asyncFilterDisposables: Set<AsyncDisposable> = new Set();\n\n/**\n * Async sink disposables to dispose when resetting the configuration.\n */\nconst asyncSinkDisposables: Set<AsyncDisposable> = new Set();\n\nlet unregisterDisposeHook: (() => void) | undefined;\n\n/**\n * Check if a config is for the meta logger.\n */\nfunction isLoggerConfigMeta<TSinkId extends string, TFilterId extends string>(\n cfg: LoggerConfig<TSinkId, TFilterId>,\n): boolean {\n const category = Array.isArray(cfg.category) ? cfg.category : [cfg.category];\n return category.length === 0 ||\n (category.length === 1 && category[0] === \"logtape\") ||\n (category.length === 2 &&\n category[0] === \"logtape\" &&\n category[1] === \"meta\");\n}\n\nfunction registerDisposeHook(allowAsync: boolean): void {\n unregisterDisposeHook?.();\n unregisterDisposeHook = undefined;\n\n const handler = allowAsync ? disposeInternal : disposeSyncInternal;\n\n if (\n // deno-lint-ignore no-explicit-any\n typeof (globalThis as any).EdgeRuntime !== \"string\" &&\n \"process\" in globalThis &&\n !(\"Deno\" in globalThis)\n ) {\n // deno-lint-ignore no-explicit-any\n const proc = (globalThis as any).process;\n // Use bracket notation to avoid static analysis detection in Edge Runtime.\n const onMethod = proc?.[\"on\"];\n if (typeof onMethod === \"function\") {\n onMethod.call(proc, \"exit\", handler);\n unregisterDisposeHook = () => {\n const offMethod = proc?.[\"off\"] ?? proc?.[\"removeListener\"];\n if (typeof offMethod === \"function\") {\n offMethod.call(proc, \"exit\", handler);\n }\n };\n return;\n }\n }\n\n // Some edge runtimes expose neither process.on() nor addEventListener().\n // In those environments users can still call dispose()/disposeSync() manually.\n // deno-lint-ignore no-explicit-any\n const addEventListenerMethod = (globalThis as any).addEventListener;\n if (typeof addEventListenerMethod !== \"function\") return;\n // deno-lint-ignore no-explicit-any\n const removeEventListenerMethod = (globalThis as any).removeEventListener;\n\n if (\"Deno\" in globalThis) {\n addEventListenerMethod.call(globalThis, \"unload\", handler);\n if (typeof removeEventListenerMethod === \"function\") {\n unregisterDisposeHook = () => {\n removeEventListenerMethod.call(globalThis, \"unload\", handler);\n };\n }\n } else {\n addEventListenerMethod.call(globalThis, \"pagehide\", handler);\n if (typeof removeEventListenerMethod === \"function\") {\n unregisterDisposeHook = () => {\n removeEventListenerMethod.call(globalThis, \"pagehide\", handler);\n };\n }\n }\n}\n\n/**\n * Configure the loggers with the specified configuration.\n *\n * Note that if the given sinks or filters are disposable, they will be\n * disposed when the configuration is reset, or when the process exits.\n *\n * @example\n * ```typescript\n * await configure({\n * sinks: {\n * console: getConsoleSink(),\n * },\n * filters: {\n * slow: (log) =>\n * \"duration\" in log.properties &&\n * log.properties.duration as number > 1000,\n * },\n * loggers: [\n * {\n * category: \"my-app\",\n * sinks: [\"console\"],\n * lowestLevel: \"info\",\n * },\n * {\n * category: [\"my-app\", \"sql\"],\n * filters: [\"slow\"],\n * lowestLevel: \"debug\",\n * },\n * {\n * category: \"logtape\",\n * sinks: [\"console\"],\n * lowestLevel: \"error\",\n * },\n * ],\n * });\n * ```\n *\n * @param config The configuration.\n */\nexport async function configure<\n TSinkId extends string,\n TFilterId extends string,\n>(config: Config<TSinkId, TFilterId>): Promise<void> {\n await runGlobalConfigMutation(\"configure()\", async () => {\n if (currentConfig != null && !config.reset) {\n throw new ConfigError(\n \"Already configured; if you want to reset, turn on the reset flag.\",\n );\n }\n await disposeInternal();\n resetInternal();\n try {\n configureInternal(config, true);\n } catch (e) {\n if (e instanceof ConfigError) {\n await disposeInternal();\n resetInternal();\n }\n throw e;\n }\n });\n}\n\n/**\n * Configure sync loggers with the specified configuration.\n *\n * Note that if the given sinks or filters are disposable, they will be\n * disposed when the configuration is reset, or when the process exits.\n *\n * Also note that passing async sinks or filters will throw. If\n * necessary use {@link resetSync} or {@link disposeSync}.\n *\n * @example\n * ```typescript\n * configureSync({\n * sinks: {\n * console: getConsoleSink(),\n * },\n * loggers: [\n * {\n * category: \"my-app\",\n * sinks: [\"console\"],\n * lowestLevel: \"info\",\n * },\n * {\n * category: \"logtape\",\n * sinks: [\"console\"],\n * lowestLevel: \"error\",\n * },\n * ],\n * });\n * ```\n *\n * @param config The configuration.\n * @since 0.9.0\n */\nexport function configureSync<TSinkId extends string, TFilterId extends string>(\n config: Config<TSinkId, TFilterId>,\n): void {\n runGlobalConfigMutationSync(\"configureSync()\", () => {\n if (currentConfig != null && !config.reset) {\n throw new ConfigError(\n \"Already configured; if you want to reset, turn on the reset flag.\",\n );\n }\n if (asyncFilterDisposables.size > 0 || asyncSinkDisposables.size > 0) {\n throw new ConfigError(\n \"Previously configured async disposables are still active. \" +\n \"Use configure() instead or explicitly dispose them using dispose().\",\n );\n }\n disposeSyncInternal();\n resetInternal();\n try {\n configureInternal(config, false);\n } catch (e) {\n if (e instanceof ConfigError) {\n disposeSyncInternal();\n resetInternal();\n }\n throw e;\n }\n });\n}\n\n/**\n * Runs a callback with a LogTape configuration scoped to the current execution\n * context.\n *\n * The process-global configuration must already provide\n * `contextLocalStorage`. The scoped configuration fully overrides global\n * logger routing while the callback and its async work run.\n *\n * @param config The scoped configuration.\n * @param callback The callback to run.\n * @returns The callback's resolved return value.\n * @since 2.3.0\n */\nexport async function withConfig<\n TSinkId extends string,\n TFilterId extends string,\n TResult,\n>(\n config: ScopedConfig<TSinkId, TFilterId>,\n callback: () => TResult,\n): Promise<Awaited<TResult>> {\n const contextLocalStorage = getConfiguredContextLocalStorage(\"withConfig()\");\n const scopedConfig = compileScopedConfig(\n config,\n true,\n (message) => new ConfigError(message),\n );\n\n let result: Awaited<TResult>;\n let callbackError: unknown;\n let callbackFailed = false;\n activeScopedConfigCount++;\n activeScopedConfigs.add(scopedConfig);\n try {\n result = await runWithScopedConfig(\n contextLocalStorage,\n scopedConfig,\n callback,\n );\n } catch (error) {\n callbackFailed = true;\n callbackError = error;\n }\n\n try {\n await disposeScopedConfig(\n scopedConfig,\n getRetainedDisposables(scopedConfig),\n );\n } catch (disposeError) {\n if (callbackFailed) {\n throwCombinedErrors(callbackError, disposeError);\n }\n throw disposeError;\n } finally {\n activeScopedConfigs.delete(scopedConfig);\n activeScopedConfigCount--;\n }\n\n if (callbackFailed) throw callbackError;\n return result!;\n}\n\n/**\n * Runs a synchronous callback with a LogTape configuration scoped to the\n * current execution context.\n *\n * The scoped configuration must not contain async disposable sinks or filters.\n *\n * @param config The scoped configuration.\n * @param callback The callback to run.\n * @returns The callback's return value.\n * @since 2.3.0\n */\nexport function withConfigSync<\n TSinkId extends string,\n TFilterId extends string,\n TResult,\n>(\n config: ScopedConfig<TSinkId, TFilterId>,\n callback: () => SyncCallbackResult<TResult>,\n): SyncCallbackResult<TResult> {\n const contextLocalStorage = getConfiguredContextLocalStorage(\n \"withConfigSync()\",\n );\n const scopedConfig = compileScopedConfig(\n config,\n false,\n (message) => new ConfigError(message),\n );\n\n let result: SyncCallbackResult<TResult>;\n let callbackError: unknown;\n let callbackFailed = false;\n activeScopedConfigCount++;\n activeScopedConfigs.add(scopedConfig);\n try {\n result = runWithScopedConfig(contextLocalStorage, scopedConfig, callback);\n if (isThenable(result)) {\n void Promise.resolve(result).catch(() => {});\n callbackFailed = true;\n callbackError = new ConfigError(\n \"withConfigSync() callback must not return a promise. \" +\n \"Use withConfig() for async callbacks.\",\n );\n }\n } catch (error) {\n callbackFailed = true;\n callbackError = error;\n }\n\n try {\n disposeScopedConfigSync(scopedConfig, getRetainedDisposables(scopedConfig));\n } catch (disposeError) {\n if (callbackFailed) {\n throwCombinedErrors(callbackError, disposeError);\n }\n throw disposeError;\n } finally {\n activeScopedConfigs.delete(scopedConfig);\n activeScopedConfigCount--;\n }\n\n if (callbackFailed) throw callbackError;\n return result!;\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return value != null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"then\" in value &&\n typeof value.then === \"function\";\n}\n\nfunction getGlobalDisposables(): ReadonlySet<Disposable | AsyncDisposable> {\n return new Set<Disposable | AsyncDisposable>([\n ...filterDisposables,\n ...asyncFilterDisposables,\n ...sinkDisposables,\n ...asyncSinkDisposables,\n ]);\n}\n\nfunction getRetainedDisposables(\n scopedConfig: CompiledScopedConfig,\n): ReadonlySet<Disposable | AsyncDisposable> {\n const disposables = new Set<Disposable | AsyncDisposable>(\n getGlobalDisposables(),\n );\n for (const activeScopedConfig of activeScopedConfigs) {\n if (activeScopedConfig === scopedConfig || activeScopedConfig.disposed) {\n continue;\n }\n addScopedConfigDisposables(disposables, activeScopedConfig);\n }\n return disposables;\n}\n\nfunction addScopedConfigDisposables(\n disposables: Set<Disposable | AsyncDisposable>,\n scopedConfig: CompiledScopedConfig,\n): void {\n for (const disposable of scopedConfig.syncFilters) {\n disposables.add(disposable);\n }\n for (const disposable of scopedConfig.asyncFilters) {\n disposables.add(disposable);\n }\n for (const disposable of scopedConfig.syncSinks) disposables.add(disposable);\n for (const disposable of scopedConfig.asyncSinks) disposables.add(disposable);\n}\n\nfunction configureInternal<\n TSinkId extends string,\n TFilterId extends string,\n>(config: Config<TSinkId, TFilterId>, allowAsync: boolean): void {\n currentConfig = config;\n\n let metaConfigured = false;\n const configuredCategories = new Set<string>();\n\n for (const cfg of config.loggers) {\n if (isLoggerConfigMeta(cfg)) {\n metaConfigured = true;\n }\n\n // Check for duplicate logger categories\n const categoryKey = Array.isArray(cfg.category)\n ? JSON.stringify(cfg.category)\n : JSON.stringify([cfg.category]);\n if (configuredCategories.has(categoryKey)) {\n throw new ConfigError(\n `Duplicate logger configuration for category: ${categoryKey}. ` +\n `Each category can only be configured once.`,\n );\n }\n configuredCategories.add(categoryKey);\n\n const logger = LoggerImpl.getLogger(cfg.category);\n for (const sinkId of cfg.sinks ?? []) {\n const sink = config.sinks[sinkId];\n if (!sink) {\n throw new ConfigError(`Sink not found: ${sinkId}.`);\n }\n logger.sinks.push(sink);\n }\n logger.parentSinks = cfg.parentSinks ?? \"inherit\";\n if (cfg.lowestLevel !== undefined) {\n logger.lowestLevel = cfg.lowestLevel;\n }\n for (const filterId of cfg.filters ?? []) {\n const filter = config.filters?.[filterId];\n if (filter === undefined) {\n throw new ConfigError(`Filter not found: ${filterId}.`);\n }\n logger.filters.push(toFilter(filter));\n }\n strongRefs.add(logger);\n }\n\n LoggerImpl.getLogger().contextLocalStorage = config.contextLocalStorage;\n\n for (const sink of Object.values<Sink>(config.sinks)) {\n if (Symbol.asyncDispose in sink) {\n if (allowAsync) asyncSinkDisposables.add(sink as AsyncDisposable);\n else {\n throw new ConfigError(\n \"Async disposables cannot be used with configureSync().\",\n );\n }\n }\n if (Symbol.dispose in sink) sinkDisposables.add(sink as Disposable);\n }\n\n for (const filter of Object.values<FilterLike>(config.filters ?? {})) {\n if (filter == null || typeof filter === \"string\") continue;\n if (Symbol.asyncDispose in filter) {\n if (allowAsync) asyncFilterDisposables.add(filter as AsyncDisposable);\n else {\n throw new ConfigError(\n \"Async disposables cannot be used with configureSync().\",\n );\n }\n asyncSinkDisposables.delete(filter as AsyncDisposable);\n }\n if (Symbol.dispose in filter) {\n filterDisposables.add(filter as Disposable);\n sinkDisposables.delete(filter as Disposable);\n }\n }\n\n registerDisposeHook(allowAsync);\n const meta = LoggerImpl.getLogger([\"logtape\", \"meta\"]);\n if (!metaConfigured) {\n meta.sinks.push(getConsoleSink());\n }\n\n meta.info(\n \"LogTape loggers are configured. Note that LogTape itself uses the meta \" +\n \"logger, which has category {metaLoggerCategory}. The meta logger is \" +\n \"used to log internal diagnostics such as sink exceptions. \" +\n \"It's recommended to configure the meta logger with a separate sink \" +\n \"so that you can easily notice if logging itself fails or is \" +\n \"misconfigured. To turn off this message, configure the meta logger \" +\n \"with higher log levels than {dismissLevel}. See also \" +\n \"<https://logtape.org/manual/categories#meta-logger>.\",\n { metaLoggerCategory: [\"logtape\", \"meta\"], dismissLevel: \"info\" },\n );\n}\n\n/**\n * Get the current configuration, if any. Otherwise, `null`.\n * @returns The current configuration, if any. Otherwise, `null`.\n */\nexport function getConfig(): Config<string, string> | null {\n return currentConfig;\n}\n\n/**\n * Reset the configuration. Mostly for testing purposes.\n */\nexport async function reset(): Promise<void> {\n await runGlobalConfigMutation(\"reset()\", async () => {\n await disposeInternal();\n resetInternal();\n });\n}\n\n/**\n * Reset the configuration. Mostly for testing purposes. Will not clear async\n * sinks, only use with sync sinks. Use {@link reset} if you have async sinks.\n * @since 0.9.0\n */\nexport function resetSync(): void {\n runGlobalConfigMutationSync(\"resetSync()\", () => {\n disposeSyncInternal();\n resetInternal();\n });\n}\n\nfunction resetInternal(): void {\n unregisterDisposeHook?.();\n unregisterDisposeHook = undefined;\n const rootLogger = LoggerImpl.getLogger([]);\n rootLogger.resetDescendants();\n delete rootLogger.contextLocalStorage;\n strongRefs.clear();\n currentConfig = null;\n}\n\n/**\n * Dispose of the disposables.\n */\nexport async function dispose(): Promise<void> {\n await runGlobalConfigMutation(\"dispose()\", disposeInternal);\n}\n\nasync function disposeInternal(): Promise<void> {\n const errors: unknown[] = [];\n try {\n disposeSyncFilters();\n } catch (error) {\n errors.push(error);\n }\n try {\n await disposeAsyncFilters();\n } catch (error) {\n errors.push(error);\n }\n try {\n disposeSyncSinks();\n } catch (error) {\n errors.push(error);\n }\n try {\n await disposeAsyncSinks();\n } catch (error) {\n errors.push(error);\n }\n throwDisposeErrors(errors);\n}\n\n/**\n * Dispose of the sync disposables. Async disposables will be untouched,\n * use {@link dispose} if you have async sinks.\n * @since 0.9.0\n */\nexport function disposeSync(): void {\n runGlobalConfigMutationSync(\"disposeSync()\", disposeSyncInternal);\n}\n\nfunction disposeSyncInternal(): void {\n const errors: unknown[] = [];\n try {\n disposeSyncFilters();\n } catch (error) {\n errors.push(error);\n }\n try {\n disposeSyncSinks();\n } catch (error) {\n errors.push(error);\n }\n throwDisposeErrors(errors);\n}\n\nfunction getConfiguredContextLocalStorage(\n functionName: string,\n): ContextLocalStorage<Record<string, unknown>> {\n if (globalConfigMutationInProgress) {\n throw new ConfigError(\n `${functionName} cannot be called while LogTape is being reconfigured.`,\n );\n }\n if (currentConfig == null) {\n throw new ConfigError(\n `${functionName} requires LogTape to be configured first.`,\n );\n }\n const contextLocalStorage = LoggerImpl.getLogger().contextLocalStorage;\n if (contextLocalStorage == null) {\n throw new ConfigError(\n `${functionName} requires Config.contextLocalStorage to be configured.`,\n );\n }\n return contextLocalStorage;\n}\n\nasync function runGlobalConfigMutation<T>(\n functionName: string,\n callback: () => Promise<T>,\n): Promise<T> {\n assertCanMutateGlobalConfig(functionName);\n globalConfigMutationInProgress = true;\n try {\n return await callback();\n } finally {\n globalConfigMutationInProgress = false;\n }\n}\n\nfunction runGlobalConfigMutationSync<T>(\n functionName: string,\n callback: () => T,\n): T {\n assertCanMutateGlobalConfig(functionName);\n globalConfigMutationInProgress = true;\n try {\n return callback();\n } finally {\n globalConfigMutationInProgress = false;\n }\n}\n\nfunction assertCanMutateGlobalConfig(functionName: string): void {\n if (globalConfigMutationInProgress) {\n throw new ConfigError(\n `${functionName} cannot be called while LogTape is being reconfigured.`,\n );\n }\n assertNoScopedConfig(functionName);\n}\n\nfunction assertNoScopedConfig(functionName: string): void {\n if (activeScopedConfigCount > 0) {\n throw new ConfigError(\n `${functionName} cannot be called while a scoped configuration is ` +\n \"active. Use nested withConfig() instead.\",\n );\n }\n}\n\nfunction disposeSyncFilters(): void {\n disposeSyncDisposables(filterDisposables);\n}\n\nfunction disposeSyncSinks(): void {\n disposeSyncDisposables(sinkDisposables);\n}\n\nfunction disposeSyncDisposables(disposables: Set<Disposable>): void {\n const errors: unknown[] = [];\n try {\n for (const disposable of disposables) {\n try {\n disposable[Symbol.dispose]();\n } catch (error) {\n errors.push(error);\n } finally {\n disposables.delete(disposable);\n }\n }\n } finally {\n disposables.clear();\n }\n throwDisposeErrors(errors);\n}\n\nasync function disposeAsyncFilters(): Promise<void> {\n await disposeAsyncDisposables(asyncFilterDisposables);\n}\n\nasync function disposeAsyncSinks(): Promise<void> {\n await disposeAsyncDisposables(asyncSinkDisposables);\n}\n\nasync function disposeAsyncDisposables(\n disposables: Set<AsyncDisposable>,\n): Promise<void> {\n const promises: PromiseLike<void>[] = [];\n try {\n for (const disposable of disposables) {\n try {\n promises.push(Promise.resolve(disposable[Symbol.asyncDispose]()));\n } catch (error) {\n promises.push(Promise.reject(error));\n } finally {\n disposables.delete(disposable);\n }\n }\n } finally {\n disposables.clear();\n }\n await settleDisposePromises(promises);\n}\n\nasync function settleDisposePromises(\n promises: readonly PromiseLike<void>[],\n): Promise<void> {\n const results = await Promise.allSettled(promises);\n throwDisposeErrors(\n results\n .filter((result): result is PromiseRejectedResult =>\n result.status === \"rejected\"\n )\n .map((result) => result.reason),\n );\n}\n\nfunction throwDisposeErrors(errors: readonly unknown[]): void {\n if (errors.length < 1) return;\n if (errors.length === 1) throw errors[0];\n throw new AggregateError(\n errors,\n \"Multiple errors occurred while disposing LogTape resources.\",\n );\n}\n\n/**\n * A configuration error.\n */\nexport class ConfigError extends Error {\n /**\n * Constructs a new configuration error.\n * @param message The error message.\n */\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n"],"mappings":";;;;;;;;;AAgHA,IAAIA,gBAA+C;AACnD,IAAI,0BAA0B;AAC9B,MAAMC,sCAAiD,IAAI;AAC3D,IAAI,iCAAiC;;;;;;AAOrC,MAAMC,6BAA8B,IAAI;;;;AAKxC,MAAMC,oCAAqC,IAAI;;;;AAK/C,MAAMC,kCAAmC,IAAI;;;;AAK7C,MAAMC,yCAA+C,IAAI;;;;AAKzD,MAAMC,uCAA6C,IAAI;AAEvD,IAAIC;;;;AAKJ,SAAS,mBACPC,KACS;CACT,MAAM,WAAW,MAAM,QAAQ,IAAI,SAAS,GAAG,IAAI,WAAW,CAAC,IAAI,QAAS;AAC5E,QAAO,SAAS,WAAW,KACxB,SAAS,WAAW,KAAK,SAAS,OAAO,aACzC,SAAS,WAAW,KACnB,SAAS,OAAO,aAChB,SAAS,OAAO;AACrB;AAED,SAAS,oBAAoBC,YAA2B;AACtD,0BAAyB;AACzB;CAEA,MAAM,UAAU,aAAa,kBAAkB;AAE/C,YAEU,WAAmB,gBAAgB,YAC3C,aAAa,gBACX,UAAU,aACZ;EAEA,MAAM,OAAQ,WAAmB;EAEjC,MAAM,WAAW,OAAO;AACxB,aAAW,aAAa,YAAY;AAClC,YAAS,KAAK,MAAM,QAAQ,QAAQ;AACpC,2BAAwB,MAAM;IAC5B,MAAM,YAAY,OAAO,UAAU,OAAO;AAC1C,eAAW,cAAc,WACvB,WAAU,KAAK,MAAM,QAAQ,QAAQ;GAExC;AACD;EACD;CACF;CAKD,MAAM,yBAA0B,WAAmB;AACnD,YAAW,2BAA2B,WAAY;CAElD,MAAM,4BAA6B,WAAmB;AAEtD,KAAI,UAAU,YAAY;AACxB,yBAAuB,KAAK,YAAY,UAAU,QAAQ;AAC1D,aAAW,8BAA8B,WACvC,yBAAwB,MAAM;AAC5B,6BAA0B,KAAK,YAAY,UAAU,QAAQ;EAC9D;CAEJ,OAAM;AACL,yBAAuB,KAAK,YAAY,YAAY,QAAQ;AAC5D,aAAW,8BAA8B,WACvC,yBAAwB,MAAM;AAC5B,6BAA0B,KAAK,YAAY,YAAY,QAAQ;EAChE;CAEJ;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyCD,eAAsB,UAGpBC,QAAmD;AACnD,OAAM,wBAAwB,eAAe,YAAY;AACvD,MAAI,iBAAiB,SAAS,OAAO,MACnC,OAAM,IAAI,YACR;AAGJ,QAAM,iBAAiB;AACvB,iBAAe;AACf,MAAI;AACF,qBAAkB,QAAQ,KAAK;EAChC,SAAQ,GAAG;AACV,OAAI,aAAa,aAAa;AAC5B,UAAM,iBAAiB;AACvB,mBAAe;GAChB;AACD,SAAM;EACP;CACF,EAAC;AACH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCD,SAAgB,cACdA,QACM;AACN,6BAA4B,mBAAmB,MAAM;AACnD,MAAI,iBAAiB,SAAS,OAAO,MACnC,OAAM,IAAI,YACR;AAGJ,MAAI,uBAAuB,OAAO,KAAK,qBAAqB,OAAO,EACjE,OAAM,IAAI,YACR;AAIJ,uBAAqB;AACrB,iBAAe;AACf,MAAI;AACF,qBAAkB,QAAQ,MAAM;EACjC,SAAQ,GAAG;AACV,OAAI,aAAa,aAAa;AAC5B,yBAAqB;AACrB,mBAAe;GAChB;AACD,SAAM;EACP;CACF,EAAC;AACH;;;;;;;;;;;;;;AAeD,eAAsB,WAKpBC,QACAC,UAC2B;CAC3B,MAAM,sBAAsB,iCAAiC,eAAe;CAC5E,MAAM,eAAe,oBACnB,QACA,MACA,CAAC,YAAY,IAAI,YAAY,SAC9B;CAED,IAAIC;CACJ,IAAIC;CACJ,IAAI,iBAAiB;AACrB;AACA,qBAAoB,IAAI,aAAa;AACrC,KAAI;AACF,WAAS,MAAM,oBACb,qBACA,cACA,SACD;CACF,SAAQ,OAAO;AACd,mBAAiB;AACjB,kBAAgB;CACjB;AAED,KAAI;AACF,QAAM,oBACJ,cACA,uBAAuB,aAAa,CACrC;CACF,SAAQ,cAAc;AACrB,MAAI,eACF,qBAAoB,eAAe,aAAa;AAElD,QAAM;CACP,UAAS;AACR,sBAAoB,OAAO,aAAa;AACxC;CACD;AAED,KAAI,eAAgB,OAAM;AAC1B,QAAO;AACR;;;;;;;;;;;;AAaD,SAAgB,eAKdH,QACAI,UAC6B;CAC7B,MAAM,sBAAsB,iCAC1B,mBACD;CACD,MAAM,eAAe,oBACnB,QACA,OACA,CAAC,YAAY,IAAI,YAAY,SAC9B;CAED,IAAIC;CACJ,IAAIF;CACJ,IAAI,iBAAiB;AACrB;AACA,qBAAoB,IAAI,aAAa;AACrC,KAAI;AACF,WAAS,oBAAoB,qBAAqB,cAAc,SAAS;AACzE,MAAI,WAAW,OAAO,EAAE;AACtB,GAAK,QAAQ,QAAQ,OAAO,CAAC,MAAM,MAAM,CAAE,EAAC;AAC5C,oBAAiB;AACjB,mBAAgB,IAAI,YAClB;EAGH;CACF,SAAQ,OAAO;AACd,mBAAiB;AACjB,kBAAgB;CACjB;AAED,KAAI;AACF,0BAAwB,cAAc,uBAAuB,aAAa,CAAC;CAC5E,SAAQ,cAAc;AACrB,MAAI,eACF,qBAAoB,eAAe,aAAa;AAElD,QAAM;CACP,UAAS;AACR,sBAAoB,OAAO,aAAa;AACxC;CACD;AAED,KAAI,eAAgB,OAAM;AAC1B,QAAO;AACR;AAED,SAAS,WAAWG,OAA+C;AACjE,QAAO,SAAS,gBACN,UAAU,mBAAmB,UAAU,eAC/C,UAAU,gBACH,MAAM,SAAS;AACzB;AAED,SAAS,uBAAkE;AACzE,QAAO,IAAI,IAAkC;EAC3C,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;CACJ;AACF;AAED,SAAS,uBACPC,cAC2C;CAC3C,MAAM,cAAc,IAAI,IACtB,sBAAsB;AAExB,MAAK,MAAM,sBAAsB,qBAAqB;AACpD,MAAI,uBAAuB,gBAAgB,mBAAmB,SAC5D;AAEF,6BAA2B,aAAa,mBAAmB;CAC5D;AACD,QAAO;AACR;AAED,SAAS,2BACPC,aACAD,cACM;AACN,MAAK,MAAM,cAAc,aAAa,YACpC,aAAY,IAAI,WAAW;AAE7B,MAAK,MAAM,cAAc,aAAa,aACpC,aAAY,IAAI,WAAW;AAE7B,MAAK,MAAM,cAAc,aAAa,UAAW,aAAY,IAAI,WAAW;AAC5E,MAAK,MAAM,cAAc,aAAa,WAAY,aAAY,IAAI,WAAW;AAC9E;AAED,SAAS,kBAGPR,QAAoCD,YAA2B;AAC/D,iBAAgB;CAEhB,IAAI,iBAAiB;CACrB,MAAM,uCAAuB,IAAI;AAEjC,MAAK,MAAM,OAAO,OAAO,SAAS;AAChC,MAAI,mBAAmB,IAAI,CACzB,kBAAiB;EAInB,MAAM,cAAc,MAAM,QAAQ,IAAI,SAAS,GAC3C,KAAK,UAAU,IAAI,SAAS,GAC5B,KAAK,UAAU,CAAC,IAAI,QAAS,EAAC;AAClC,MAAI,qBAAqB,IAAI,YAAY,CACvC,OAAM,IAAI,aACP,+CAA+C,YAAY;AAIhE,uBAAqB,IAAI,YAAY;EAErC,MAAM,SAAS,WAAW,UAAU,IAAI,SAAS;AACjD,OAAK,MAAM,UAAU,IAAI,SAAS,CAAE,GAAE;GACpC,MAAM,OAAO,OAAO,MAAM;AAC1B,QAAK,KACH,OAAM,IAAI,aAAa,kBAAkB,OAAO;AAElD,UAAO,MAAM,KAAK,KAAK;EACxB;AACD,SAAO,cAAc,IAAI,eAAe;AACxC,MAAI,IAAI,uBACN,QAAO,cAAc,IAAI;AAE3B,OAAK,MAAM,YAAY,IAAI,WAAW,CAAE,GAAE;GACxC,MAAM,SAAS,OAAO,UAAU;AAChC,OAAI,kBACF,OAAM,IAAI,aAAa,oBAAoB,SAAS;AAEtD,UAAO,QAAQ,KAAK,SAAS,OAAO,CAAC;EACtC;AACD,aAAW,IAAI,OAAO;CACvB;AAED,YAAW,WAAW,CAAC,sBAAsB,OAAO;AAEpD,MAAK,MAAM,QAAQ,OAAO,OAAa,OAAO,MAAM,EAAE;AACpD,MAAI,OAAO,gBAAgB,KACzB,KAAI,WAAY,sBAAqB,IAAI,KAAwB;MAE/D,OAAM,IAAI,YACR;AAIN,MAAI,OAAO,WAAW,KAAM,iBAAgB,IAAI,KAAmB;CACpE;AAED,MAAK,MAAM,UAAU,OAAO,OAAmB,OAAO,WAAW,CAAE,EAAC,EAAE;AACpE,MAAI,UAAU,eAAe,WAAW,SAAU;AAClD,MAAI,OAAO,gBAAgB,QAAQ;AACjC,OAAI,WAAY,wBAAuB,IAAI,OAA0B;OAEnE,OAAM,IAAI,YACR;AAGJ,wBAAqB,OAAO,OAA0B;EACvD;AACD,MAAI,OAAO,WAAW,QAAQ;AAC5B,qBAAkB,IAAI,OAAqB;AAC3C,mBAAgB,OAAO,OAAqB;EAC7C;CACF;AAED,qBAAoB,WAAW;CAC/B,MAAM,OAAO,WAAW,UAAU,CAAC,WAAW,MAAO,EAAC;AACtD,MAAK,eACH,MAAK,MAAM,KAAK,gBAAgB,CAAC;AAGnC,MAAK,KACH,yfAQA;EAAE,oBAAoB,CAAC,WAAW,MAAO;EAAE,cAAc;CAAQ,EAClE;AACF;;;;;AAMD,SAAgB,YAA2C;AACzD,QAAO;AACR;;;;AAKD,eAAsB,QAAuB;AAC3C,OAAM,wBAAwB,WAAW,YAAY;AACnD,QAAM,iBAAiB;AACvB,iBAAe;CAChB,EAAC;AACH;;;;;;AAOD,SAAgB,YAAkB;AAChC,6BAA4B,eAAe,MAAM;AAC/C,uBAAqB;AACrB,iBAAe;CAChB,EAAC;AACH;AAED,SAAS,gBAAsB;AAC7B,0BAAyB;AACzB;CACA,MAAM,aAAa,WAAW,UAAU,CAAE,EAAC;AAC3C,YAAW,kBAAkB;AAC7B,QAAO,WAAW;AAClB,YAAW,OAAO;AAClB,iBAAgB;AACjB;;;;AAKD,eAAsB,UAAyB;AAC7C,OAAM,wBAAwB,aAAa,gBAAgB;AAC5D;AAED,eAAe,kBAAiC;CAC9C,MAAMW,SAAoB,CAAE;AAC5B,KAAI;AACF,sBAAoB;CACrB,SAAQ,OAAO;AACd,SAAO,KAAK,MAAM;CACnB;AACD,KAAI;AACF,QAAM,qBAAqB;CAC5B,SAAQ,OAAO;AACd,SAAO,KAAK,MAAM;CACnB;AACD,KAAI;AACF,oBAAkB;CACnB,SAAQ,OAAO;AACd,SAAO,KAAK,MAAM;CACnB;AACD,KAAI;AACF,QAAM,mBAAmB;CAC1B,SAAQ,OAAO;AACd,SAAO,KAAK,MAAM;CACnB;AACD,oBAAmB,OAAO;AAC3B;;;;;;AAOD,SAAgB,cAAoB;AAClC,6BAA4B,iBAAiB,oBAAoB;AAClE;AAED,SAAS,sBAA4B;CACnC,MAAMA,SAAoB,CAAE;AAC5B,KAAI;AACF,sBAAoB;CACrB,SAAQ,OAAO;AACd,SAAO,KAAK,MAAM;CACnB;AACD,KAAI;AACF,oBAAkB;CACnB,SAAQ,OAAO;AACd,SAAO,KAAK,MAAM;CACnB;AACD,oBAAmB,OAAO;AAC3B;AAED,SAAS,iCACPC,cAC8C;AAC9C,KAAI,+BACF,OAAM,IAAI,aACP,EAAE,aAAa;AAGpB,KAAI,iBAAiB,KACnB,OAAM,IAAI,aACP,EAAE,aAAa;CAGpB,MAAM,sBAAsB,WAAW,WAAW,CAAC;AACnD,KAAI,uBAAuB,KACzB,OAAM,IAAI,aACP,EAAE,aAAa;AAGpB,QAAO;AACR;AAED,eAAe,wBACbA,cACAC,UACY;AACZ,6BAA4B,aAAa;AACzC,kCAAiC;AACjC,KAAI;AACF,SAAO,MAAM,UAAU;CACxB,UAAS;AACR,mCAAiC;CAClC;AACF;AAED,SAAS,4BACPD,cACAE,UACG;AACH,6BAA4B,aAAa;AACzC,kCAAiC;AACjC,KAAI;AACF,SAAO,UAAU;CAClB,UAAS;AACR,mCAAiC;CAClC;AACF;AAED,SAAS,4BAA4BF,cAA4B;AAC/D,KAAI,+BACF,OAAM,IAAI,aACP,EAAE,aAAa;AAGpB,sBAAqB,aAAa;AACnC;AAED,SAAS,qBAAqBA,cAA4B;AACxD,KAAI,0BAA0B,EAC5B,OAAM,IAAI,aACP,EAAE,aAAa;AAIrB;AAED,SAAS,qBAA2B;AAClC,wBAAuB,kBAAkB;AAC1C;AAED,SAAS,mBAAyB;AAChC,wBAAuB,gBAAgB;AACxC;AAED,SAAS,uBAAuBG,aAAoC;CAClE,MAAMJ,SAAoB,CAAE;AAC5B,KAAI;AACF,OAAK,MAAM,cAAc,YACvB,KAAI;AACF,cAAW,OAAO,UAAU;EAC7B,SAAQ,OAAO;AACd,UAAO,KAAK,MAAM;EACnB,UAAS;AACR,eAAY,OAAO,WAAW;EAC/B;CAEJ,UAAS;AACR,cAAY,OAAO;CACpB;AACD,oBAAmB,OAAO;AAC3B;AAED,eAAe,sBAAqC;AAClD,OAAM,wBAAwB,uBAAuB;AACtD;AAED,eAAe,oBAAmC;AAChD,OAAM,wBAAwB,qBAAqB;AACpD;AAED,eAAe,wBACbK,aACe;CACf,MAAMC,WAAgC,CAAE;AACxC,KAAI;AACF,OAAK,MAAM,cAAc,YACvB,KAAI;AACF,YAAS,KAAK,QAAQ,QAAQ,WAAW,OAAO,eAAe,CAAC,CAAC;EAClE,SAAQ,OAAO;AACd,YAAS,KAAK,QAAQ,OAAO,MAAM,CAAC;EACrC,UAAS;AACR,eAAY,OAAO,WAAW;EAC/B;CAEJ,UAAS;AACR,cAAY,OAAO;CACpB;AACD,OAAM,sBAAsB,SAAS;AACtC;AAED,eAAe,sBACbC,UACe;CACf,MAAM,UAAU,MAAM,QAAQ,WAAW,SAAS;AAClD,oBACE,QACG,OAAO,CAAC,WACP,OAAO,WAAW,WACnB,CACA,IAAI,CAAC,WAAW,OAAO,OAAO,CAClC;AACF;AAED,SAAS,mBAAmBC,QAAkC;AAC5D,KAAI,OAAO,SAAS,EAAG;AACvB,KAAI,OAAO,WAAW,EAAG,OAAM,OAAO;AACtC,OAAM,IAAI,eACR,QACA;AAEH;;;;AAKD,IAAa,cAAb,cAAiC,MAAM;;;;;CAKrC,YAAYC,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO;CACb;AACF"}
1
+ {"version":3,"file":"config.js","names":["currentConfig: Config<string, string> | null","activeScopedConfigs: Set<CompiledScopedConfig>","strongRefs: Set<LoggerImpl>","filterDisposables: Set<Disposable>","sinkDisposables: Set<Disposable>","asyncFilterDisposables: Set<AsyncDisposable>","asyncSinkDisposables: Set<AsyncDisposable>","unregisterDisposeHook: (() => void) | undefined","cfg: LoggerConfig<TSinkId, TFilterId>","allowAsync: boolean","config: Config<TSinkId, TFilterId>","config: ScopedConfig<TSinkId, TFilterId>","callback: () => TResult","result: Awaited<TResult>","callbackError: unknown","callback: () => SyncCallbackResult<TResult>","result: SyncCallbackResult<TResult>","value: unknown","scopedConfig: CompiledScopedConfig","disposables: Set<Disposable | AsyncDisposable>","errors: unknown[]","functionName: string","callback: () => Promise<T>","callback: () => T","disposables: Set<Disposable>","disposables: Set<AsyncDisposable>","promises: PromiseLike<void>[]","promises: readonly PromiseLike<void>[]","errors: readonly unknown[]","message: string"],"sources":["../src/config.ts"],"sourcesContent":["import type { ContextLocalStorage } from \"./context.ts\";\nimport { type FilterLike, toFilter } from \"./filter.ts\";\nimport type { LogLevel } from \"./level.ts\";\nimport { LoggerImpl } from \"./logger.ts\";\nimport {\n type CompiledScopedConfig,\n compileScopedConfig,\n disposeScopedConfig,\n disposeScopedConfigSync,\n runWithScopedConfig,\n type ScopedConfigLike,\n throwCombinedErrors,\n} from \"./scoped-config.ts\";\nimport { getConsoleSink, type Sink } from \"./sink.ts\";\n\n/**\n * A configuration for the loggers.\n */\nexport interface Config<TSinkId extends string, TFilterId extends string> {\n /**\n * The sinks to use. The keys are the sink identifiers, and the values are\n * {@link Sink}s.\n */\n sinks: Record<TSinkId, Sink>;\n /**\n * The filters to use. The keys are the filter identifiers, and the values\n * are either {@link Filter}s or {@link LogLevel}s.\n */\n filters?: Record<TFilterId, FilterLike>;\n\n /**\n * The loggers to configure.\n */\n loggers: LoggerConfig<TSinkId, TFilterId>[];\n\n /**\n * The context-local storage to use for implicit contexts.\n * @since 0.7.0\n */\n contextLocalStorage?: ContextLocalStorage<Record<string, unknown>>;\n\n /**\n * Whether to reset the configuration before applying this one.\n */\n reset?: boolean;\n}\n\n/**\n * A scoped configuration for the current execution context.\n *\n * Unlike {@link Config}, this type does not include `reset` or\n * `contextLocalStorage`. Scoped configuration changes only the logging policy\n * for a callback; the context-local storage must already be initialized by the\n * process-global configuration.\n *\n * @since 2.3.0\n */\nexport type ScopedConfig<TSinkId extends string, TFilterId extends string> =\n ScopedConfigLike<TSinkId, TFilterId>;\n\ntype SyncCallbackResult<TResult> = TResult extends PromiseLike<unknown> ? never\n : TResult;\n\n/**\n * A logger configuration.\n */\nexport interface LoggerConfig<\n TSinkId extends string,\n TFilterId extends string,\n> {\n /**\n * The category of the logger. If a string, it is equivalent to an array\n * with one element.\n */\n category: string | string[];\n\n /**\n * The sink identifiers to use.\n */\n sinks?: TSinkId[];\n\n /**\n * How to combine the logger's sinks with its ancestors' sinks.\n *\n * If `inherit`, the sinks that the parent would use for a record's level\n * are used along with the specified sinks. The parent's `lowestLevel`\n * continues to apply to the inherited sinks.\n *\n * If `override`, only the specified sinks are used.\n *\n * If `forward`, every ancestor's configured sinks are used along with the\n * specified sinks, ignoring each ancestor's `lowestLevel` (including\n * `null`); only this logger's own `lowestLevel` applies. An ancestor\n * configured with `parentSinks: \"override\"` forms a boundary: its own\n * sinks are still inherited, but nothing beyond it. Repeated references\n * to the same sink are not deduplicated. Available since 2.4.0.\n *\n * The default is `inherit`.\n * @default \"inherit\"\n * @since 0.6.0\n */\n parentSinks?: \"inherit\" | \"override\" | \"forward\";\n\n /**\n * The filter identifiers to use. If no filters are specified, the logger\n * uses the filters from the nearest ancestor that has them. Specifying one\n * or more filters replaces the inherited filters instead of combining with\n * them.\n */\n filters?: TFilterId[];\n\n /**\n * The lowest log level to accept. If `null`, the logger will reject all\n * records.\n * @since 0.8.0\n */\n lowestLevel?: LogLevel | null;\n}\n\n/**\n * The current configuration, if any. Otherwise, `null`.\n */\nlet currentConfig: Config<string, string> | null = null;\nlet activeScopedConfigCount = 0;\nconst activeScopedConfigs: Set<CompiledScopedConfig> = new Set();\nlet globalConfigMutationInProgress = false;\n\n/**\n * Strong references to the loggers.\n * This is to prevent the loggers from being garbage collected so that their\n * sinks and filters are not removed.\n */\nconst strongRefs: Set<LoggerImpl> = new Set();\n\n/**\n * Sync filter disposables to dispose when resetting the configuration.\n */\nconst filterDisposables: Set<Disposable> = new Set();\n\n/**\n * Sync sink disposables to dispose when resetting the configuration.\n */\nconst sinkDisposables: Set<Disposable> = new Set();\n\n/**\n * Async filter disposables to dispose when resetting the configuration.\n */\nconst asyncFilterDisposables: Set<AsyncDisposable> = new Set();\n\n/**\n * Async sink disposables to dispose when resetting the configuration.\n */\nconst asyncSinkDisposables: Set<AsyncDisposable> = new Set();\n\nlet unregisterDisposeHook: (() => void) | undefined;\n\n/**\n * Check if a config is for the meta logger.\n */\nfunction isLoggerConfigMeta<TSinkId extends string, TFilterId extends string>(\n cfg: LoggerConfig<TSinkId, TFilterId>,\n): boolean {\n const category = Array.isArray(cfg.category) ? cfg.category : [cfg.category];\n return category.length === 0 ||\n (category.length === 1 && category[0] === \"logtape\") ||\n (category.length === 2 &&\n category[0] === \"logtape\" &&\n category[1] === \"meta\");\n}\n\nfunction registerDisposeHook(allowAsync: boolean): void {\n unregisterDisposeHook?.();\n unregisterDisposeHook = undefined;\n\n const handler = allowAsync ? disposeInternal : disposeSyncInternal;\n\n if (\n // deno-lint-ignore no-explicit-any\n typeof (globalThis as any).EdgeRuntime !== \"string\" &&\n \"process\" in globalThis &&\n !(\"Deno\" in globalThis)\n ) {\n // deno-lint-ignore no-explicit-any\n const proc = (globalThis as any).process;\n // Use bracket notation to avoid static analysis detection in Edge Runtime.\n const onMethod = proc?.[\"on\"];\n if (typeof onMethod === \"function\") {\n onMethod.call(proc, \"exit\", handler);\n unregisterDisposeHook = () => {\n const offMethod = proc?.[\"off\"] ?? proc?.[\"removeListener\"];\n if (typeof offMethod === \"function\") {\n offMethod.call(proc, \"exit\", handler);\n }\n };\n return;\n }\n }\n\n // Some edge runtimes expose neither process.on() nor addEventListener().\n // In those environments users can still call dispose()/disposeSync() manually.\n // deno-lint-ignore no-explicit-any\n const addEventListenerMethod = (globalThis as any).addEventListener;\n if (typeof addEventListenerMethod !== \"function\") return;\n // deno-lint-ignore no-explicit-any\n const removeEventListenerMethod = (globalThis as any).removeEventListener;\n\n if (\"Deno\" in globalThis) {\n addEventListenerMethod.call(globalThis, \"unload\", handler);\n if (typeof removeEventListenerMethod === \"function\") {\n unregisterDisposeHook = () => {\n removeEventListenerMethod.call(globalThis, \"unload\", handler);\n };\n }\n } else {\n addEventListenerMethod.call(globalThis, \"pagehide\", handler);\n if (typeof removeEventListenerMethod === \"function\") {\n unregisterDisposeHook = () => {\n removeEventListenerMethod.call(globalThis, \"pagehide\", handler);\n };\n }\n }\n}\n\n/**\n * Configure the loggers with the specified configuration.\n *\n * Note that if the given sinks or filters are disposable, they will be\n * disposed when the configuration is reset, or when the process exits.\n *\n * @example\n * ```typescript\n * await configure({\n * sinks: {\n * console: getConsoleSink(),\n * },\n * filters: {\n * slow: (log) =>\n * \"duration\" in log.properties &&\n * log.properties.duration as number > 1000,\n * },\n * loggers: [\n * {\n * category: \"my-app\",\n * sinks: [\"console\"],\n * lowestLevel: \"info\",\n * },\n * {\n * category: [\"my-app\", \"sql\"],\n * filters: [\"slow\"],\n * lowestLevel: \"debug\",\n * },\n * {\n * category: \"logtape\",\n * sinks: [\"console\"],\n * lowestLevel: \"error\",\n * },\n * ],\n * });\n * ```\n *\n * @param config The configuration.\n */\nexport async function configure<\n TSinkId extends string,\n TFilterId extends string,\n>(config: Config<TSinkId, TFilterId>): Promise<void> {\n await runGlobalConfigMutation(\"configure()\", async () => {\n if (currentConfig != null && !config.reset) {\n throw new ConfigError(\n \"Already configured; if you want to reset, turn on the reset flag.\",\n );\n }\n await disposeInternal();\n resetInternal();\n try {\n configureInternal(config, true);\n } catch (e) {\n if (e instanceof ConfigError) {\n await disposeInternal();\n resetInternal();\n }\n throw e;\n }\n });\n}\n\n/**\n * Configure sync loggers with the specified configuration.\n *\n * Note that if the given sinks or filters are disposable, they will be\n * disposed when the configuration is reset, or when the process exits.\n *\n * Also note that passing async sinks or filters will throw. If\n * necessary use {@link resetSync} or {@link disposeSync}.\n *\n * @example\n * ```typescript\n * configureSync({\n * sinks: {\n * console: getConsoleSink(),\n * },\n * loggers: [\n * {\n * category: \"my-app\",\n * sinks: [\"console\"],\n * lowestLevel: \"info\",\n * },\n * {\n * category: \"logtape\",\n * sinks: [\"console\"],\n * lowestLevel: \"error\",\n * },\n * ],\n * });\n * ```\n *\n * @param config The configuration.\n * @since 0.9.0\n */\nexport function configureSync<TSinkId extends string, TFilterId extends string>(\n config: Config<TSinkId, TFilterId>,\n): void {\n runGlobalConfigMutationSync(\"configureSync()\", () => {\n if (currentConfig != null && !config.reset) {\n throw new ConfigError(\n \"Already configured; if you want to reset, turn on the reset flag.\",\n );\n }\n if (asyncFilterDisposables.size > 0 || asyncSinkDisposables.size > 0) {\n throw new ConfigError(\n \"Previously configured async disposables are still active. \" +\n \"Use configure() instead or explicitly dispose them using dispose().\",\n );\n }\n disposeSyncInternal();\n resetInternal();\n try {\n configureInternal(config, false);\n } catch (e) {\n if (e instanceof ConfigError) {\n disposeSyncInternal();\n resetInternal();\n }\n throw e;\n }\n });\n}\n\n/**\n * Runs a callback with a LogTape configuration scoped to the current execution\n * context.\n *\n * The process-global configuration must already provide\n * `contextLocalStorage`. The scoped configuration fully overrides global\n * logger routing while the callback and its async work run.\n *\n * @param config The scoped configuration.\n * @param callback The callback to run.\n * @returns The callback's resolved return value.\n * @since 2.3.0\n */\nexport async function withConfig<\n TSinkId extends string,\n TFilterId extends string,\n TResult,\n>(\n config: ScopedConfig<TSinkId, TFilterId>,\n callback: () => TResult,\n): Promise<Awaited<TResult>> {\n const contextLocalStorage = getConfiguredContextLocalStorage(\"withConfig()\");\n const scopedConfig = compileScopedConfig(\n config,\n true,\n (message) => new ConfigError(message),\n );\n\n let result: Awaited<TResult>;\n let callbackError: unknown;\n let callbackFailed = false;\n activeScopedConfigCount++;\n activeScopedConfigs.add(scopedConfig);\n try {\n result = await runWithScopedConfig(\n contextLocalStorage,\n scopedConfig,\n callback,\n );\n } catch (error) {\n callbackFailed = true;\n callbackError = error;\n }\n\n try {\n await disposeScopedConfig(\n scopedConfig,\n getRetainedDisposables(scopedConfig),\n );\n } catch (disposeError) {\n if (callbackFailed) {\n throwCombinedErrors(callbackError, disposeError);\n }\n throw disposeError;\n } finally {\n activeScopedConfigs.delete(scopedConfig);\n activeScopedConfigCount--;\n }\n\n if (callbackFailed) throw callbackError;\n return result!;\n}\n\n/**\n * Runs a synchronous callback with a LogTape configuration scoped to the\n * current execution context.\n *\n * The scoped configuration must not contain async disposable sinks or filters.\n *\n * @param config The scoped configuration.\n * @param callback The callback to run.\n * @returns The callback's return value.\n * @since 2.3.0\n */\nexport function withConfigSync<\n TSinkId extends string,\n TFilterId extends string,\n TResult,\n>(\n config: ScopedConfig<TSinkId, TFilterId>,\n callback: () => SyncCallbackResult<TResult>,\n): SyncCallbackResult<TResult> {\n const contextLocalStorage = getConfiguredContextLocalStorage(\n \"withConfigSync()\",\n );\n const scopedConfig = compileScopedConfig(\n config,\n false,\n (message) => new ConfigError(message),\n );\n\n let result: SyncCallbackResult<TResult>;\n let callbackError: unknown;\n let callbackFailed = false;\n activeScopedConfigCount++;\n activeScopedConfigs.add(scopedConfig);\n try {\n result = runWithScopedConfig(contextLocalStorage, scopedConfig, callback);\n if (isThenable(result)) {\n void Promise.resolve(result).catch(() => {});\n callbackFailed = true;\n callbackError = new ConfigError(\n \"withConfigSync() callback must not return a promise. \" +\n \"Use withConfig() for async callbacks.\",\n );\n }\n } catch (error) {\n callbackFailed = true;\n callbackError = error;\n }\n\n try {\n disposeScopedConfigSync(scopedConfig, getRetainedDisposables(scopedConfig));\n } catch (disposeError) {\n if (callbackFailed) {\n throwCombinedErrors(callbackError, disposeError);\n }\n throw disposeError;\n } finally {\n activeScopedConfigs.delete(scopedConfig);\n activeScopedConfigCount--;\n }\n\n if (callbackFailed) throw callbackError;\n return result!;\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n return value != null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n \"then\" in value &&\n typeof value.then === \"function\";\n}\n\nfunction getGlobalDisposables(): ReadonlySet<Disposable | AsyncDisposable> {\n return new Set<Disposable | AsyncDisposable>([\n ...filterDisposables,\n ...asyncFilterDisposables,\n ...sinkDisposables,\n ...asyncSinkDisposables,\n ]);\n}\n\nfunction getRetainedDisposables(\n scopedConfig: CompiledScopedConfig,\n): ReadonlySet<Disposable | AsyncDisposable> {\n const disposables = new Set<Disposable | AsyncDisposable>(\n getGlobalDisposables(),\n );\n for (const activeScopedConfig of activeScopedConfigs) {\n if (activeScopedConfig === scopedConfig || activeScopedConfig.disposed) {\n continue;\n }\n addScopedConfigDisposables(disposables, activeScopedConfig);\n }\n return disposables;\n}\n\nfunction addScopedConfigDisposables(\n disposables: Set<Disposable | AsyncDisposable>,\n scopedConfig: CompiledScopedConfig,\n): void {\n for (const disposable of scopedConfig.syncFilters) {\n disposables.add(disposable);\n }\n for (const disposable of scopedConfig.asyncFilters) {\n disposables.add(disposable);\n }\n for (const disposable of scopedConfig.syncSinks) disposables.add(disposable);\n for (const disposable of scopedConfig.asyncSinks) disposables.add(disposable);\n}\n\nfunction configureInternal<\n TSinkId extends string,\n TFilterId extends string,\n>(config: Config<TSinkId, TFilterId>, allowAsync: boolean): void {\n currentConfig = config;\n\n let metaConfigured = false;\n const configuredCategories = new Set<string>();\n\n for (const cfg of config.loggers) {\n if (isLoggerConfigMeta(cfg)) {\n metaConfigured = true;\n }\n\n // Check for duplicate logger categories\n const categoryKey = Array.isArray(cfg.category)\n ? JSON.stringify(cfg.category)\n : JSON.stringify([cfg.category]);\n if (configuredCategories.has(categoryKey)) {\n throw new ConfigError(\n `Duplicate logger configuration for category: ${categoryKey}. ` +\n `Each category can only be configured once.`,\n );\n }\n configuredCategories.add(categoryKey);\n\n const logger = LoggerImpl.getLogger(cfg.category);\n for (const sinkId of cfg.sinks ?? []) {\n const sink = config.sinks[sinkId];\n if (!sink) {\n throw new ConfigError(`Sink not found: ${sinkId}.`);\n }\n logger.sinks.push(sink);\n }\n logger.parentSinks = cfg.parentSinks ?? \"inherit\";\n if (cfg.lowestLevel !== undefined) {\n logger.lowestLevel = cfg.lowestLevel;\n }\n for (const filterId of cfg.filters ?? []) {\n const filter = config.filters?.[filterId];\n if (filter === undefined) {\n throw new ConfigError(`Filter not found: ${filterId}.`);\n }\n logger.filters.push(toFilter(filter));\n }\n strongRefs.add(logger);\n }\n\n LoggerImpl.getLogger().contextLocalStorage = config.contextLocalStorage;\n\n for (const sink of Object.values<Sink>(config.sinks)) {\n if (Symbol.asyncDispose in sink) {\n if (allowAsync) asyncSinkDisposables.add(sink as AsyncDisposable);\n else {\n throw new ConfigError(\n \"Async disposables cannot be used with configureSync().\",\n );\n }\n }\n if (Symbol.dispose in sink) sinkDisposables.add(sink as Disposable);\n }\n\n for (const filter of Object.values<FilterLike>(config.filters ?? {})) {\n if (filter == null || typeof filter === \"string\") continue;\n if (Symbol.asyncDispose in filter) {\n if (allowAsync) asyncFilterDisposables.add(filter as AsyncDisposable);\n else {\n throw new ConfigError(\n \"Async disposables cannot be used with configureSync().\",\n );\n }\n asyncSinkDisposables.delete(filter as AsyncDisposable);\n }\n if (Symbol.dispose in filter) {\n filterDisposables.add(filter as Disposable);\n sinkDisposables.delete(filter as Disposable);\n }\n }\n\n registerDisposeHook(allowAsync);\n const meta = LoggerImpl.getLogger([\"logtape\", \"meta\"]);\n if (!metaConfigured) {\n meta.sinks.push(getConsoleSink());\n }\n\n meta.info(\n \"LogTape loggers are configured. Note that LogTape itself uses the meta \" +\n \"logger, which has category {metaLoggerCategory}. The meta logger is \" +\n \"used to log internal diagnostics such as sink exceptions. \" +\n \"It's recommended to configure the meta logger with a separate sink \" +\n \"so that you can easily notice if logging itself fails or is \" +\n \"misconfigured. To turn off this message, configure the meta logger \" +\n \"with higher log levels than {dismissLevel}. See also \" +\n \"<https://logtape.org/manual/categories#meta-logger>.\",\n { metaLoggerCategory: [\"logtape\", \"meta\"], dismissLevel: \"info\" },\n );\n}\n\n/**\n * Get the current configuration, if any. Otherwise, `null`.\n * @returns The current configuration, if any. Otherwise, `null`.\n */\nexport function getConfig(): Config<string, string> | null {\n return currentConfig;\n}\n\n/**\n * Reset the configuration. Mostly for testing purposes.\n */\nexport async function reset(): Promise<void> {\n await runGlobalConfigMutation(\"reset()\", async () => {\n await disposeInternal();\n resetInternal();\n });\n}\n\n/**\n * Reset the configuration. Mostly for testing purposes. Will not clear async\n * sinks, only use with sync sinks. Use {@link reset} if you have async sinks.\n * @since 0.9.0\n */\nexport function resetSync(): void {\n runGlobalConfigMutationSync(\"resetSync()\", () => {\n disposeSyncInternal();\n resetInternal();\n });\n}\n\nfunction resetInternal(): void {\n unregisterDisposeHook?.();\n unregisterDisposeHook = undefined;\n const rootLogger = LoggerImpl.getLogger([]);\n rootLogger.resetDescendants();\n delete rootLogger.contextLocalStorage;\n strongRefs.clear();\n currentConfig = null;\n}\n\n/**\n * Dispose of the disposables.\n */\nexport async function dispose(): Promise<void> {\n await runGlobalConfigMutation(\"dispose()\", disposeInternal);\n}\n\nasync function disposeInternal(): Promise<void> {\n const errors: unknown[] = [];\n try {\n disposeSyncFilters();\n } catch (error) {\n errors.push(error);\n }\n try {\n await disposeAsyncFilters();\n } catch (error) {\n errors.push(error);\n }\n try {\n disposeSyncSinks();\n } catch (error) {\n errors.push(error);\n }\n try {\n await disposeAsyncSinks();\n } catch (error) {\n errors.push(error);\n }\n throwDisposeErrors(errors);\n}\n\n/**\n * Dispose of the sync disposables. Async disposables will be untouched,\n * use {@link dispose} if you have async sinks.\n * @since 0.9.0\n */\nexport function disposeSync(): void {\n runGlobalConfigMutationSync(\"disposeSync()\", disposeSyncInternal);\n}\n\nfunction disposeSyncInternal(): void {\n const errors: unknown[] = [];\n try {\n disposeSyncFilters();\n } catch (error) {\n errors.push(error);\n }\n try {\n disposeSyncSinks();\n } catch (error) {\n errors.push(error);\n }\n throwDisposeErrors(errors);\n}\n\nfunction getConfiguredContextLocalStorage(\n functionName: string,\n): ContextLocalStorage<Record<string, unknown>> {\n if (globalConfigMutationInProgress) {\n throw new ConfigError(\n `${functionName} cannot be called while LogTape is being reconfigured.`,\n );\n }\n if (currentConfig == null) {\n throw new ConfigError(\n `${functionName} requires LogTape to be configured first.`,\n );\n }\n const contextLocalStorage = LoggerImpl.getLogger().contextLocalStorage;\n if (contextLocalStorage == null) {\n throw new ConfigError(\n `${functionName} requires Config.contextLocalStorage to be configured.`,\n );\n }\n return contextLocalStorage;\n}\n\nasync function runGlobalConfigMutation<T>(\n functionName: string,\n callback: () => Promise<T>,\n): Promise<T> {\n assertCanMutateGlobalConfig(functionName);\n globalConfigMutationInProgress = true;\n try {\n return await callback();\n } finally {\n globalConfigMutationInProgress = false;\n }\n}\n\nfunction runGlobalConfigMutationSync<T>(\n functionName: string,\n callback: () => T,\n): T {\n assertCanMutateGlobalConfig(functionName);\n globalConfigMutationInProgress = true;\n try {\n return callback();\n } finally {\n globalConfigMutationInProgress = false;\n }\n}\n\nfunction assertCanMutateGlobalConfig(functionName: string): void {\n if (globalConfigMutationInProgress) {\n throw new ConfigError(\n `${functionName} cannot be called while LogTape is being reconfigured.`,\n );\n }\n assertNoScopedConfig(functionName);\n}\n\nfunction assertNoScopedConfig(functionName: string): void {\n if (activeScopedConfigCount > 0) {\n throw new ConfigError(\n `${functionName} cannot be called while a scoped configuration is ` +\n \"active. Use nested withConfig() instead.\",\n );\n }\n}\n\nfunction disposeSyncFilters(): void {\n disposeSyncDisposables(filterDisposables);\n}\n\nfunction disposeSyncSinks(): void {\n disposeSyncDisposables(sinkDisposables);\n}\n\nfunction disposeSyncDisposables(disposables: Set<Disposable>): void {\n const errors: unknown[] = [];\n try {\n for (const disposable of disposables) {\n try {\n disposable[Symbol.dispose]();\n } catch (error) {\n errors.push(error);\n } finally {\n disposables.delete(disposable);\n }\n }\n } finally {\n disposables.clear();\n }\n throwDisposeErrors(errors);\n}\n\nasync function disposeAsyncFilters(): Promise<void> {\n await disposeAsyncDisposables(asyncFilterDisposables);\n}\n\nasync function disposeAsyncSinks(): Promise<void> {\n await disposeAsyncDisposables(asyncSinkDisposables);\n}\n\nasync function disposeAsyncDisposables(\n disposables: Set<AsyncDisposable>,\n): Promise<void> {\n const promises: PromiseLike<void>[] = [];\n try {\n for (const disposable of disposables) {\n try {\n promises.push(Promise.resolve(disposable[Symbol.asyncDispose]()));\n } catch (error) {\n promises.push(Promise.reject(error));\n } finally {\n disposables.delete(disposable);\n }\n }\n } finally {\n disposables.clear();\n }\n await settleDisposePromises(promises);\n}\n\nasync function settleDisposePromises(\n promises: readonly PromiseLike<void>[],\n): Promise<void> {\n const results = await Promise.allSettled(promises);\n throwDisposeErrors(\n results\n .filter((result): result is PromiseRejectedResult =>\n result.status === \"rejected\"\n )\n .map((result) => result.reason),\n );\n}\n\nfunction throwDisposeErrors(errors: readonly unknown[]): void {\n if (errors.length < 1) return;\n if (errors.length === 1) throw errors[0];\n throw new AggregateError(\n errors,\n \"Multiple errors occurred while disposing LogTape resources.\",\n );\n}\n\n/**\n * A configuration error.\n */\nexport class ConfigError extends Error {\n /**\n * Constructs a new configuration error.\n * @param message The error message.\n */\n constructor(message: string) {\n super(message);\n this.name = \"ConfigError\";\n }\n}\n"],"mappings":"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"}
package/dist/logger.cjs CHANGED
@@ -129,6 +129,41 @@ function getLogger(category = []) {
129
129
  return LoggerImpl.getLogger(category);
130
130
  }
131
131
  /**
132
+ * Enumerate every logger in the category tree rooted at the given logger,
133
+ * including the given logger itself, in depth-first pre-order.
134
+ *
135
+ * ```typescript
136
+ * const all = getLoggers(); // the whole tree, from the root down
137
+ * const mine = getLoggers("my-app"); // "my-app" and its descendants only
138
+ * ```
139
+ *
140
+ * This only reflects loggers that have actually been *materialized* by a
141
+ * `getLogger()` call somewhere in the running program. A category that has
142
+ * been configured via `configure()` but never reached by a `getLogger()`
143
+ * call (e.g. inside an unexecuted code path) will not appear.
144
+ *
145
+ * @param logger The logger (or its category, as a string or array of
146
+ * strings) to start from. Defaults to the root logger.
147
+ * @returns Every logger in the subtree, starting with the resolved logger
148
+ * itself, in depth-first pre-order.
149
+ * @since 2.4.0
150
+ */
151
+ function getLoggers(logger) {
152
+ const category = logger == null ? [] : isCategory(logger) ? logger : logger.category;
153
+ return collectDescendants(LoggerImpl.getLogger(category));
154
+ }
155
+ function isCategory(value) {
156
+ return typeof value === "string" || Array.isArray(value);
157
+ }
158
+ function collectDescendants(logger) {
159
+ const loggers = [logger];
160
+ for (const childRef of Object.values(logger.children)) {
161
+ const child = childRef instanceof LoggerImpl ? childRef : childRef.deref();
162
+ if (child != null) loggers.push(...collectDescendants(child));
163
+ }
164
+ return loggers;
165
+ }
166
+ /**
132
167
  * The symbol for the global root logger.
133
168
  */
134
169
  const globalRootLoggerSymbol = Symbol.for("logtape.rootLogger");
@@ -149,6 +184,7 @@ var LoggerImpl = class LoggerImpl {
149
184
  #parentSinks = "inherit";
150
185
  #lowestLevel = "trace";
151
186
  #sinkPlanCache = {};
187
+ #forwardPlanCache = void 0;
152
188
  static getLogger(category = []) {
153
189
  let rootLogger = globalRootLoggerSymbol in globalThis ? globalThis[globalRootLoggerSymbol] ?? null : null;
154
190
  if (rootLogger == null) {
@@ -244,17 +280,46 @@ var LoggerImpl = class LoggerImpl {
244
280
  getSinkDispatchPlan(level) {
245
281
  const cached = this.#sinkPlanCache[level];
246
282
  if (cached != null && this.isSinkDispatchPlanFresh(level, cached)) return cached;
247
- const parentPlan = this.parent != null && this.parentSinks === "inherit" ? this.parent.getSinkDispatchPlan(level) : void 0;
248
- const plan = this.createSinkDispatchPlan(level, parentPlan);
283
+ const plan = this.createSinkDispatchPlan(level, this.resolveParentPlan(level));
249
284
  this.#sinkPlanCache[level] = plan;
250
285
  return plan;
251
286
  }
287
+ resolveParentPlan(level) {
288
+ if (this.parent == null) return void 0;
289
+ if (this.parentSinks === "inherit") return this.parent.getSinkDispatchPlan(level);
290
+ if (this.parentSinks === "forward") return this.parent.getForwardSinkPlan();
291
+ return void 0;
292
+ }
252
293
  isSinkDispatchPlanFresh(level, plan) {
253
294
  if (plan.lowestLevel !== this.lowestLevel || plan.parentSinks !== this.parentSinks || plan.localSinks.length !== this.sinks.length) return false;
254
295
  for (let i = 0; i < plan.localSinks.length; i++) if (plan.localSinks[i] !== this.sinks[i]) return false;
255
- const parentPlan = this.parent != null && this.parentSinks === "inherit" ? this.parent.getSinkDispatchPlan(level) : void 0;
296
+ return plan.parentPlan === this.resolveParentPlan(level);
297
+ }
298
+ getForwardSinkPlan() {
299
+ const cached = this.#forwardPlanCache;
300
+ if (cached != null && this.isForwardSinkPlanFresh(cached)) return cached;
301
+ const parentPlan = this.parent != null && this.parentSinks !== "override" ? this.parent.getForwardSinkPlan() : void 0;
302
+ const plan = this.createForwardSinkPlan(parentPlan);
303
+ this.#forwardPlanCache = plan;
304
+ return plan;
305
+ }
306
+ isForwardSinkPlanFresh(plan) {
307
+ if (plan.parentSinks !== this.parentSinks || plan.localSinks.length !== this.sinks.length) return false;
308
+ for (let i = 0; i < plan.localSinks.length; i++) if (plan.localSinks[i] !== this.sinks[i]) return false;
309
+ const parentPlan = this.parent != null && this.parentSinks !== "override" ? this.parent.getForwardSinkPlan() : void 0;
256
310
  return plan.parentPlan === parentPlan;
257
311
  }
312
+ createForwardSinkPlan(parentPlan) {
313
+ const localSinks = [...this.sinks];
314
+ const sinks = parentPlan == null || parentPlan.sinks.length < 1 ? localSinks : [...parentPlan.sinks, ...localSinks];
315
+ return {
316
+ kind: "forward",
317
+ localSinks,
318
+ parentSinks: this.parentSinks,
319
+ parentPlan,
320
+ sinks
321
+ };
322
+ }
258
323
  createSinkDispatchPlan(level, parentPlan) {
259
324
  const state = {
260
325
  localSinks: [...this.sinks],
@@ -280,6 +345,10 @@ var LoggerImpl = class LoggerImpl {
280
345
  if (parentPlan != null) {
281
346
  if (parentPlan.kind === "one") firstSink = parentPlan.sink;
282
347
  else if (parentPlan.kind === "many") sinks = [...parentPlan.sinks];
348
+ else if (parentPlan.kind === "forward") {
349
+ if (parentPlan.sinks.length === 1) firstSink = parentPlan.sinks[0];
350
+ else if (parentPlan.sinks.length > 1) sinks = [...parentPlan.sinks];
351
+ }
283
352
  }
284
353
  for (const sink of state.localSinks) appendSink(sink);
285
354
  if (sinks != null) return {
@@ -980,5 +1049,6 @@ function renderMessage(template, values) {
980
1049
  //#endregion
981
1050
  exports.LoggerImpl = LoggerImpl;
982
1051
  exports.getLogger = getLogger;
1052
+ exports.getLoggers = getLoggers;
983
1053
  exports.isLazy = isLazy;
984
1054
  exports.lazy = lazy;
package/dist/logger.d.cts CHANGED
@@ -1180,10 +1180,31 @@ interface LogMethod {
1180
1180
  * @returns The logger.
1181
1181
  */
1182
1182
  declare function getLogger(category?: string | readonly string[]): Logger;
1183
+ /**
1184
+ * Enumerate every logger in the category tree rooted at the given logger,
1185
+ * including the given logger itself, in depth-first pre-order.
1186
+ *
1187
+ * ```typescript
1188
+ * const all = getLoggers(); // the whole tree, from the root down
1189
+ * const mine = getLoggers("my-app"); // "my-app" and its descendants only
1190
+ * ```
1191
+ *
1192
+ * This only reflects loggers that have actually been *materialized* by a
1193
+ * `getLogger()` call somewhere in the running program. A category that has
1194
+ * been configured via `configure()` but never reached by a `getLogger()`
1195
+ * call (e.g. inside an unexecuted code path) will not appear.
1196
+ *
1197
+ * @param logger The logger (or its category, as a string or array of
1198
+ * strings) to start from. Defaults to the root logger.
1199
+ * @returns Every logger in the subtree, starting with the resolved logger
1200
+ * itself, in depth-first pre-order.
1201
+ * @since 2.4.0
1202
+ */
1203
+ declare function getLoggers(logger?: Logger | string | readonly string[]): readonly Logger[];
1183
1204
  /**
1184
1205
  * A logger implementation. Do not use this directly; use {@link getLogger}
1185
1206
  * instead. This class is exported for testing purposes.
1186
1207
  */
1187
1208
  //#endregion
1188
- export { Lazy, LogMethod, Logger, getLogger, isLazy, lazy };
1209
+ export { Lazy, LogMethod, Logger, getLogger, getLoggers, isLazy, lazy };
1189
1210
  //# sourceMappingURL=logger.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.cts","names":[],"sources":["../src/logger.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.d.cts","names":[],"sources":["../src/logger.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/logger.d.ts CHANGED
@@ -1180,10 +1180,31 @@ interface LogMethod {
1180
1180
  * @returns The logger.
1181
1181
  */
1182
1182
  declare function getLogger(category?: string | readonly string[]): Logger;
1183
+ /**
1184
+ * Enumerate every logger in the category tree rooted at the given logger,
1185
+ * including the given logger itself, in depth-first pre-order.
1186
+ *
1187
+ * ```typescript
1188
+ * const all = getLoggers(); // the whole tree, from the root down
1189
+ * const mine = getLoggers("my-app"); // "my-app" and its descendants only
1190
+ * ```
1191
+ *
1192
+ * This only reflects loggers that have actually been *materialized* by a
1193
+ * `getLogger()` call somewhere in the running program. A category that has
1194
+ * been configured via `configure()` but never reached by a `getLogger()`
1195
+ * call (e.g. inside an unexecuted code path) will not appear.
1196
+ *
1197
+ * @param logger The logger (or its category, as a string or array of
1198
+ * strings) to start from. Defaults to the root logger.
1199
+ * @returns Every logger in the subtree, starting with the resolved logger
1200
+ * itself, in depth-first pre-order.
1201
+ * @since 2.4.0
1202
+ */
1203
+ declare function getLoggers(logger?: Logger | string | readonly string[]): readonly Logger[];
1183
1204
  /**
1184
1205
  * A logger implementation. Do not use this directly; use {@link getLogger}
1185
1206
  * instead. This class is exported for testing purposes.
1186
1207
  */
1187
1208
  //#endregion
1188
- export { Lazy, LogMethod, Logger, getLogger, isLazy, lazy };
1209
+ export { Lazy, LogMethod, Logger, getLogger, getLoggers, isLazy, lazy };
1189
1210
  //# sourceMappingURL=logger.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","names":[],"sources":["../src/logger.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.d.ts","names":[],"sources":["../src/logger.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/logger.js CHANGED
@@ -129,6 +129,41 @@ function getLogger(category = []) {
129
129
  return LoggerImpl.getLogger(category);
130
130
  }
131
131
  /**
132
+ * Enumerate every logger in the category tree rooted at the given logger,
133
+ * including the given logger itself, in depth-first pre-order.
134
+ *
135
+ * ```typescript
136
+ * const all = getLoggers(); // the whole tree, from the root down
137
+ * const mine = getLoggers("my-app"); // "my-app" and its descendants only
138
+ * ```
139
+ *
140
+ * This only reflects loggers that have actually been *materialized* by a
141
+ * `getLogger()` call somewhere in the running program. A category that has
142
+ * been configured via `configure()` but never reached by a `getLogger()`
143
+ * call (e.g. inside an unexecuted code path) will not appear.
144
+ *
145
+ * @param logger The logger (or its category, as a string or array of
146
+ * strings) to start from. Defaults to the root logger.
147
+ * @returns Every logger in the subtree, starting with the resolved logger
148
+ * itself, in depth-first pre-order.
149
+ * @since 2.4.0
150
+ */
151
+ function getLoggers(logger) {
152
+ const category = logger == null ? [] : isCategory(logger) ? logger : logger.category;
153
+ return collectDescendants(LoggerImpl.getLogger(category));
154
+ }
155
+ function isCategory(value) {
156
+ return typeof value === "string" || Array.isArray(value);
157
+ }
158
+ function collectDescendants(logger) {
159
+ const loggers = [logger];
160
+ for (const childRef of Object.values(logger.children)) {
161
+ const child = childRef instanceof LoggerImpl ? childRef : childRef.deref();
162
+ if (child != null) loggers.push(...collectDescendants(child));
163
+ }
164
+ return loggers;
165
+ }
166
+ /**
132
167
  * The symbol for the global root logger.
133
168
  */
134
169
  const globalRootLoggerSymbol = Symbol.for("logtape.rootLogger");
@@ -149,6 +184,7 @@ var LoggerImpl = class LoggerImpl {
149
184
  #parentSinks = "inherit";
150
185
  #lowestLevel = "trace";
151
186
  #sinkPlanCache = {};
187
+ #forwardPlanCache = void 0;
152
188
  static getLogger(category = []) {
153
189
  let rootLogger = globalRootLoggerSymbol in globalThis ? globalThis[globalRootLoggerSymbol] ?? null : null;
154
190
  if (rootLogger == null) {
@@ -244,17 +280,46 @@ var LoggerImpl = class LoggerImpl {
244
280
  getSinkDispatchPlan(level) {
245
281
  const cached = this.#sinkPlanCache[level];
246
282
  if (cached != null && this.isSinkDispatchPlanFresh(level, cached)) return cached;
247
- const parentPlan = this.parent != null && this.parentSinks === "inherit" ? this.parent.getSinkDispatchPlan(level) : void 0;
248
- const plan = this.createSinkDispatchPlan(level, parentPlan);
283
+ const plan = this.createSinkDispatchPlan(level, this.resolveParentPlan(level));
249
284
  this.#sinkPlanCache[level] = plan;
250
285
  return plan;
251
286
  }
287
+ resolveParentPlan(level) {
288
+ if (this.parent == null) return void 0;
289
+ if (this.parentSinks === "inherit") return this.parent.getSinkDispatchPlan(level);
290
+ if (this.parentSinks === "forward") return this.parent.getForwardSinkPlan();
291
+ return void 0;
292
+ }
252
293
  isSinkDispatchPlanFresh(level, plan) {
253
294
  if (plan.lowestLevel !== this.lowestLevel || plan.parentSinks !== this.parentSinks || plan.localSinks.length !== this.sinks.length) return false;
254
295
  for (let i = 0; i < plan.localSinks.length; i++) if (plan.localSinks[i] !== this.sinks[i]) return false;
255
- const parentPlan = this.parent != null && this.parentSinks === "inherit" ? this.parent.getSinkDispatchPlan(level) : void 0;
296
+ return plan.parentPlan === this.resolveParentPlan(level);
297
+ }
298
+ getForwardSinkPlan() {
299
+ const cached = this.#forwardPlanCache;
300
+ if (cached != null && this.isForwardSinkPlanFresh(cached)) return cached;
301
+ const parentPlan = this.parent != null && this.parentSinks !== "override" ? this.parent.getForwardSinkPlan() : void 0;
302
+ const plan = this.createForwardSinkPlan(parentPlan);
303
+ this.#forwardPlanCache = plan;
304
+ return plan;
305
+ }
306
+ isForwardSinkPlanFresh(plan) {
307
+ if (plan.parentSinks !== this.parentSinks || plan.localSinks.length !== this.sinks.length) return false;
308
+ for (let i = 0; i < plan.localSinks.length; i++) if (plan.localSinks[i] !== this.sinks[i]) return false;
309
+ const parentPlan = this.parent != null && this.parentSinks !== "override" ? this.parent.getForwardSinkPlan() : void 0;
256
310
  return plan.parentPlan === parentPlan;
257
311
  }
312
+ createForwardSinkPlan(parentPlan) {
313
+ const localSinks = [...this.sinks];
314
+ const sinks = parentPlan == null || parentPlan.sinks.length < 1 ? localSinks : [...parentPlan.sinks, ...localSinks];
315
+ return {
316
+ kind: "forward",
317
+ localSinks,
318
+ parentSinks: this.parentSinks,
319
+ parentPlan,
320
+ sinks
321
+ };
322
+ }
258
323
  createSinkDispatchPlan(level, parentPlan) {
259
324
  const state = {
260
325
  localSinks: [...this.sinks],
@@ -280,6 +345,10 @@ var LoggerImpl = class LoggerImpl {
280
345
  if (parentPlan != null) {
281
346
  if (parentPlan.kind === "one") firstSink = parentPlan.sink;
282
347
  else if (parentPlan.kind === "many") sinks = [...parentPlan.sinks];
348
+ else if (parentPlan.kind === "forward") {
349
+ if (parentPlan.sinks.length === 1) firstSink = parentPlan.sinks[0];
350
+ else if (parentPlan.sinks.length > 1) sinks = [...parentPlan.sinks];
351
+ }
283
352
  }
284
353
  for (const sink of state.localSinks) appendSink(sink);
285
354
  if (sinks != null) return {
@@ -978,5 +1047,5 @@ function renderMessage(template, values) {
978
1047
  }
979
1048
 
980
1049
  //#endregion
981
- export { LoggerImpl, getLogger, isLazy, lazy };
1050
+ export { LoggerImpl, getLogger, getLoggers, isLazy, lazy };
982
1051
  //# sourceMappingURL=logger.js.map