@vercube/logger 1.2.1 → 1.3.0

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.
@@ -0,0 +1,2 @@
1
+ export * from "evlog/otlp";
2
+ export * from "evlog/pipeline";
package/dist/Otlp.mjs ADDED
@@ -0,0 +1,3 @@
1
+ export * from "evlog/otlp";
2
+ export * from "evlog/pipeline";
3
+ export {};
package/dist/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
- import { DrainContext, DrainFn, EnvironmentContext, ErrorOptions, EvlogError, Log, LogLevel, LogLevel as LogLevel$1, LoggerConfig, LoggerConfig as LoggerConfig$1, RedactConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, WideEvent, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, initLogger, log, parseError } from "evlog";
1
+ import { DrainContext, DrainFn, EnrichContext, EnvironmentContext, ErrorOptions, EvlogError, EvlogPlugin, EvlogPlugin as EvlogPlugin$1, Log, LogLevel, LogLevel as LogLevel$1, LoggerConfig, LoggerConfig as LoggerConfig$1, RedactConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, WideEvent, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, definePlugin, drainPlugin, enricherPlugin, initLogger, log, parseError } from "evlog";
2
2
  //#region src/Types/LoggerTypes.d.ts
3
3
  /**
4
4
  * Types for the evlog-backed Vercube logger.
5
5
  *
6
6
  * @see https://evlog.dev
7
7
  */
8
- declare namespace LoggerTypes {
8
+ export declare namespace LoggerTypes {
9
9
  /**
10
10
  * Supported severity levels, aligned with evlog.
11
11
  * Order: debug < info < warn < error.
@@ -19,6 +19,15 @@ declare namespace LoggerTypes {
19
19
  * Structured context merged into emitted (wide) events.
20
20
  */
21
21
  type Context = Record<string, unknown>;
22
+ /**
23
+ * Supplies context computed at emit time.
24
+ *
25
+ * Unlike {@link Logger.set}, which stores a fixed object, a provider is
26
+ * called for every event. That is what lets ambient state - the active trace
27
+ * and span, for instance - reach log lines without every call site passing it
28
+ * along. Returning `undefined` contributes nothing.
29
+ */
30
+ type ContextProvider = () => Context | undefined;
22
31
  /**
23
32
  * Logger configuration.
24
33
  *
@@ -42,7 +51,7 @@ declare namespace LoggerTypes {
42
51
  * default implementation ({@link BaseLogger}) is backed by evlog
43
52
  * (https://evlog.dev) and forwards calls to evlog's logging API.
44
53
  */
45
- declare abstract class Logger {
54
+ export declare abstract class Logger {
46
55
  /**
47
56
  * Configures the underlying logger.
48
57
  * Maps to evlog's `initLogger` under the hood.
@@ -50,6 +59,43 @@ declare abstract class Logger {
50
59
  * @param options - Configuration options for the logger
51
60
  */
52
61
  abstract configure(options: LoggerTypes.Options): void;
62
+ /**
63
+ * Registers an evlog plugin without discarding the current configuration.
64
+ *
65
+ * evlog only accepts plugins through `initLogger`, and calling that a second
66
+ * time would replace whatever the application configured for itself. This
67
+ * re-applies the stored configuration with the plugin appended, so framework
68
+ * packages - telemetry, devtools - can attach themselves to the log pipeline
69
+ * instead of wrapping the logger instance.
70
+ *
71
+ * @param plugin - The evlog plugin to register
72
+ */
73
+ abstract addPlugin(plugin: EvlogPlugin$1): void;
74
+ /**
75
+ * Registers a drain: a callback receiving every emitted event.
76
+ *
77
+ * @param name - Stable plugin name, used for de-duplication
78
+ * @param drain - The drain callback
79
+ */
80
+ abstract addDrain(name: string, drain: NonNullable<EvlogPlugin$1['drain']>): void;
81
+ /**
82
+ * Registers an enricher: a callback that may mutate an event before it drains.
83
+ *
84
+ * @param name - Stable plugin name, used for de-duplication
85
+ * @param enrich - The enricher callback
86
+ */
87
+ abstract addEnricher(name: string, enrich: NonNullable<EvlogPlugin$1['enrich']>): void;
88
+ /**
89
+ * Registers a provider consulted for every event this logger emits.
90
+ *
91
+ * evlog's `enrich` hook only runs for request wide events, so it cannot
92
+ * decorate a plain `logger.info()`. A context provider covers that path.
93
+ *
94
+ * @param provider - Called per event; its fields are merged in first, so
95
+ * anything the call site passes wins
96
+ * @returns A function that unregisters the provider
97
+ */
98
+ abstract addContextProvider(provider: LoggerTypes.ContextProvider): () => void;
53
99
  /**
54
100
  * Logs a debug message.
55
101
  * @param args - Values to log (strings, objects, errors)
@@ -108,16 +154,74 @@ declare abstract class Logger {
108
154
  * lifecycle. For request-scoped wide events use the evlog toolkit
109
155
  * (`@vercube/logger/toolkit`) together with the framework's request middleware.
110
156
  */
111
- declare class BaseLogger extends Logger {
157
+ export declare class BaseLogger extends Logger {
112
158
  /**
113
159
  * Accumulated structured context merged into every emitted event.
114
160
  */
115
161
  private fContext;
162
+ /**
163
+ * The last configuration applied, replayed whenever a plugin is added.
164
+ */
165
+ private fOptions;
166
+ /**
167
+ * Plugins registered through {@link BaseLogger.addPlugin}, kept apart from
168
+ * the ones the application passed to {@link BaseLogger.configure} so that
169
+ * reconfiguring never drops them.
170
+ */
171
+ private readonly fPlugins;
172
+ /**
173
+ * Providers consulted for every emitted event. Shared by reference with
174
+ * child loggers, so registering one after `child()` still reaches them.
175
+ */
176
+ private fContextProviders;
116
177
  /**
117
178
  * Configures the underlying evlog logger.
118
179
  * @param options - Configuration options
119
180
  */
120
181
  configure(options: LoggerTypes.Options): void;
182
+ /**
183
+ * Registers an evlog plugin, keeping the current configuration intact.
184
+ *
185
+ * Registering the same name twice replaces the previous registration, which
186
+ * makes attaching a plugin idempotent across hot reloads.
187
+ *
188
+ * @param plugin - The evlog plugin to register
189
+ */
190
+ addPlugin(plugin: EvlogPlugin$1): void;
191
+ /**
192
+ * Registers a drain: a callback receiving every emitted event.
193
+ *
194
+ * @param name - Stable plugin name
195
+ * @param drain - The drain callback
196
+ */
197
+ addDrain(name: string, drain: NonNullable<EvlogPlugin$1['drain']>): void;
198
+ /**
199
+ * Registers an enricher: a callback that may mutate an event before it drains.
200
+ *
201
+ * @param name - Stable plugin name
202
+ * @param enrich - The enricher callback
203
+ */
204
+ addEnricher(name: string, enrich: NonNullable<EvlogPlugin$1['enrich']>): void;
205
+ /**
206
+ * Registers a provider consulted for every event this logger emits.
207
+ *
208
+ * @param provider - Called per event
209
+ * @returns A function that unregisters the provider
210
+ */
211
+ addContextProvider(provider: LoggerTypes.ContextProvider): () => void;
212
+ /**
213
+ * Collects the fields every registered provider contributes.
214
+ *
215
+ * @returns The merged provided context, or null when nothing was contributed
216
+ * @private
217
+ */
218
+ private providedContext;
219
+ /**
220
+ * Pushes the stored configuration and every registered plugin into evlog.
221
+ *
222
+ * @private
223
+ */
224
+ private apply;
121
225
  /**
122
226
  * Logs a debug message.
123
227
  * @param args - Values to log
@@ -173,4 +277,4 @@ declare class BaseLogger extends Logger {
173
277
  private dispatch;
174
278
  }
175
279
  //#endregion
176
- export { BaseLogger, type DrainContext, type DrainFn, type EnvironmentContext, type ErrorOptions, EvlogError, type Log, type LogLevel, Logger, type LoggerConfig, LoggerTypes, type RedactConfig, type RequestLogger, type RequestLoggerOptions, type SamplingConfig, type WideEvent, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, initLogger, log, parseError };
280
+ export { type DrainContext, type DrainFn, type EnrichContext, type EnvironmentContext, type ErrorOptions, EvlogError, type EvlogPlugin, type Log, type LogLevel, type LoggerConfig, type RedactConfig, type RequestLogger, type RequestLoggerOptions, type SamplingConfig, type WideEvent, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, definePlugin, drainPlugin, enricherPlugin, initLogger, log, parseError };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { EvlogError, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, initLogger, initLogger as initLogger$1, log, log as log$1, parseError } from "evlog";
1
+ import { EvlogError, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, definePlugin, drainPlugin, drainPlugin as drainPlugin$1, enricherPlugin, enricherPlugin as enricherPlugin$1, initLogger, initLogger as initLogger$1, log, log as log$1, parseError } from "evlog";
2
2
  //#region src/Common/Logger.ts
3
3
  /**
4
4
  * Abstract base class for the Vercube logger.
@@ -26,14 +26,99 @@ var BaseLogger = class BaseLogger extends Logger {
26
26
  */
27
27
  fContext = {};
28
28
  /**
29
+ * The last configuration applied, replayed whenever a plugin is added.
30
+ */
31
+ fOptions = {};
32
+ /**
33
+ * Plugins registered through {@link BaseLogger.addPlugin}, kept apart from
34
+ * the ones the application passed to {@link BaseLogger.configure} so that
35
+ * reconfiguring never drops them.
36
+ */
37
+ fPlugins = [];
38
+ /**
39
+ * Providers consulted for every emitted event. Shared by reference with
40
+ * child loggers, so registering one after `child()` still reaches them.
41
+ */
42
+ fContextProviders = [];
43
+ /**
29
44
  * Configures the underlying evlog logger.
30
45
  * @param options - Configuration options
31
46
  */
32
47
  configure(options) {
33
- const { logLevel, ...config } = options ?? {};
48
+ this.fOptions = options ?? {};
49
+ this.apply();
50
+ }
51
+ /**
52
+ * Registers an evlog plugin, keeping the current configuration intact.
53
+ *
54
+ * Registering the same name twice replaces the previous registration, which
55
+ * makes attaching a plugin idempotent across hot reloads.
56
+ *
57
+ * @param plugin - The evlog plugin to register
58
+ */
59
+ addPlugin(plugin) {
60
+ const existing = this.fPlugins.findIndex((registered) => registered.name === plugin.name);
61
+ if (existing === -1) this.fPlugins.push(plugin);
62
+ else this.fPlugins[existing] = plugin;
63
+ this.apply();
64
+ }
65
+ /**
66
+ * Registers a drain: a callback receiving every emitted event.
67
+ *
68
+ * @param name - Stable plugin name
69
+ * @param drain - The drain callback
70
+ */
71
+ addDrain(name, drain) {
72
+ this.addPlugin(drainPlugin$1(name, drain));
73
+ }
74
+ /**
75
+ * Registers an enricher: a callback that may mutate an event before it drains.
76
+ *
77
+ * @param name - Stable plugin name
78
+ * @param enrich - The enricher callback
79
+ */
80
+ addEnricher(name, enrich) {
81
+ this.addPlugin(enricherPlugin$1(name, enrich));
82
+ }
83
+ /**
84
+ * Registers a provider consulted for every event this logger emits.
85
+ *
86
+ * @param provider - Called per event
87
+ * @returns A function that unregisters the provider
88
+ */
89
+ addContextProvider(provider) {
90
+ this.fContextProviders.push(provider);
91
+ return () => {
92
+ const index = this.fContextProviders.indexOf(provider);
93
+ if (index !== -1) this.fContextProviders.splice(index, 1);
94
+ };
95
+ }
96
+ /**
97
+ * Collects the fields every registered provider contributes.
98
+ *
99
+ * @returns The merged provided context, or null when nothing was contributed
100
+ * @private
101
+ */
102
+ providedContext() {
103
+ if (this.fContextProviders.length === 0) return null;
104
+ let merged = null;
105
+ for (const provider of this.fContextProviders) {
106
+ const context = provider();
107
+ if (context) merged = merged === null ? { ...context } : Object.assign(merged, context);
108
+ }
109
+ return merged;
110
+ }
111
+ /**
112
+ * Pushes the stored configuration and every registered plugin into evlog.
113
+ *
114
+ * @private
115
+ */
116
+ apply() {
117
+ const { logLevel, plugins, ...config } = this.fOptions;
34
118
  initLogger$1({
35
119
  ...config,
36
- minLevel: logLevel ?? config.minLevel
120
+ minLevel: logLevel ?? config.minLevel,
121
+ plugins: plugins ? [...plugins, ...this.fPlugins] : this.fPlugins
37
122
  });
38
123
  }
39
124
  /**
@@ -87,6 +172,7 @@ var BaseLogger = class BaseLogger extends Logger {
87
172
  ...this.fContext,
88
173
  ...context
89
174
  };
175
+ child.fContextProviders = this.fContextProviders;
90
176
  return child;
91
177
  }
92
178
  /**
@@ -95,6 +181,7 @@ var BaseLogger = class BaseLogger extends Logger {
95
181
  */
96
182
  emit(overrides = {}) {
97
183
  const event = {
184
+ ...this.providedContext(),
98
185
  ...this.fContext,
99
186
  ...overrides
100
187
  };
@@ -116,11 +203,15 @@ var BaseLogger = class BaseLogger extends Logger {
116
203
  * @param args - The raw arguments passed to the log method
117
204
  */
118
205
  dispatch(level, args) {
119
- if (!(Object.keys(this.fContext).length > 0) && args.length === 2 && typeof args[0] === "string" && typeof args[1] === "string") {
206
+ const provided = this.providedContext();
207
+ if (!(provided !== null || Object.keys(this.fContext).length > 0) && args.length === 2 && typeof args[0] === "string" && typeof args[1] === "string") {
120
208
  log$1[level](args[0], args[1]);
121
209
  return;
122
210
  }
123
- const event = { ...this.fContext };
211
+ const event = {
212
+ ...provided,
213
+ ...this.fContext
214
+ };
124
215
  const messageParts = [];
125
216
  let tag;
126
217
  for (const arg of args) if (arg instanceof Error) event.error = {
@@ -140,4 +231,4 @@ var BaseLogger = class BaseLogger extends Logger {
140
231
  }
141
232
  };
142
233
  //#endregion
143
- export { BaseLogger, EvlogError, Logger, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, initLogger, log, parseError };
234
+ export { BaseLogger, EvlogError, Logger, createError, createLogger, createRequestLogger, defineError, defineErrorCatalog, definePlugin, drainPlugin, enricherPlugin, initLogger, log, parseError };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercube/logger",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Logger module for Vercube framework",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,6 +23,11 @@
23
23
  "import": "./dist/Toolkit.mjs",
24
24
  "default": "./dist/Toolkit.mjs"
25
25
  },
26
+ "./otlp": {
27
+ "types": "./dist/Otlp.d.mts",
28
+ "import": "./dist/Otlp.mjs",
29
+ "default": "./dist/Otlp.mjs"
30
+ },
26
31
  "./package.json": "./package.json"
27
32
  },
28
33
  "types": "./dist/index.d.mts",
@@ -31,8 +36,8 @@
31
36
  "README.md"
32
37
  ],
33
38
  "dependencies": {
34
- "evlog": "^2.26.0",
35
- "@vercube/di": "1.2.1"
39
+ "@vercube/di": "1.3.0",
40
+ "evlog": "^2.28.1"
36
41
  },
37
42
  "publishConfig": {
38
43
  "access": "public"