@eventuras/logger 0.8.0 → 0.9.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.
@@ -1,48 +1,209 @@
1
- import { a as e } from "./chunk-NnHqS4_Y.js";
2
- import { t } from "./Logger-CcNEmm6u.js";
1
+ import { i as setLogLineSink, r as PinoTransport, t as Logger } from "./Logger-B22dX10w.js";
2
+ import { logs } from "@opentelemetry/api-logs";
3
3
  //#region src/opentelemetry.ts
4
- async function n() {
4
+ /**
5
+ * OpenTelemetry integration for @eventuras/logger
6
+ *
7
+ * Sends logs to any OpenTelemetry-compatible backend (Sentry, Grafana, the
8
+ * Aspire dashboard, etc.) without vendor lock-in.
9
+ *
10
+ * Every line the Pino transport writes — after redaction, from every logger,
11
+ * including ones created before setup — is also emitted as an OpenTelemetry
12
+ * log record. The logger bridges this itself rather than through
13
+ * `@opentelemetry/instrumentation-pino`, which only patches Pino when it is
14
+ * loaded through an import-in-the-middle loader hook, and so never saw this
15
+ * package's ESM import of Pino.
16
+ *
17
+ * `@opentelemetry/sdk-logs` is an optional peer dependency, needed only when
18
+ * passing `logRecordProcessor` — which comes from that package anyway, so the
19
+ * app already has it and the logger uses the app's copy.
20
+ *
21
+ * Setup never throws or rejects: if it can't start, it logs an error and
22
+ * leaves logging to stdout untouched.
23
+ *
24
+ * @example
25
+ * // In your app's instrumentation.ts or main entry point
26
+ * import { setupOpenTelemetryLogger } from '@eventuras/logger/opentelemetry';
27
+ * import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
28
+ * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
29
+ *
30
+ * await setupOpenTelemetryLogger({
31
+ * logRecordProcessor: new BatchLogRecordProcessor({
32
+ * exporter: new OTLPLogExporter(), // reads OTEL_EXPORTER_OTLP_* env vars
33
+ * }),
34
+ * });
35
+ *
36
+ * @example
37
+ * // Then use logger as normal
38
+ * import { Logger } from '@eventuras/logger';
39
+ *
40
+ * const logger = Logger.create({ namespace: 'MyService' });
41
+ * logger.error({ error: err }, 'Something failed'); // Sent to OpenTelemetry backend
42
+ */
43
+ var NAMESPACE = "logger:otel";
44
+ var INSTRUMENTATION_SCOPE = "@eventuras/logger";
45
+ /** OpenTelemetry severity numbers for each level (logs data model). */
46
+ var SEVERITY_NUMBERS = {
47
+ trace: 1,
48
+ debug: 5,
49
+ info: 9,
50
+ warn: 13,
51
+ error: 17,
52
+ fatal: 21
53
+ };
54
+ /** Pino's numeric levels, for when `formatters.level` has been overridden. */
55
+ var PINO_LEVEL_LABELS = {
56
+ 10: "trace",
57
+ 20: "debug",
58
+ 30: "info",
59
+ 40: "warn",
60
+ 50: "error",
61
+ 60: "fatal"
62
+ };
63
+ var loggerProvider = null;
64
+ /** Whether `loggerProvider` was created here — only then is it ours to shut down. */
65
+ var ownsLoggerProvider = false;
66
+ async function loadPeer(name, load) {
5
67
  try {
6
- let [t, n] = await Promise.all([import("./src-15l0SmY8.js").then((t) => /* @__PURE__ */ e(t.default, 1)), import("./esm-CIhYjsQQ.js")]);
68
+ return await load();
69
+ } catch (cause) {
70
+ const reason = cause instanceof Error ? cause.message : String(cause);
71
+ throw new Error(`${name} could not be loaded (${reason}). Install it to export logs with OpenTelemetry.`, { cause });
72
+ }
73
+ }
74
+ async function resolveLoggerProvider(options) {
75
+ if (options.loggerProvider) return {
76
+ provider: options.loggerProvider,
77
+ owned: false
78
+ };
79
+ if (options.logRecordProcessor) {
80
+ const { LoggerProvider } = await loadPeer("@opentelemetry/sdk-logs", () => import("@opentelemetry/sdk-logs"));
7
81
  return {
8
- PinoInstrumentation: t.PinoInstrumentation,
9
- LoggerProvider: n.LoggerProvider
82
+ provider: new LoggerProvider({ processors: [options.logRecordProcessor] }),
83
+ owned: true
10
84
  };
11
- } catch {
12
- return null;
13
85
  }
86
+ return {
87
+ provider: logs.getLoggerProvider(),
88
+ owned: false
89
+ };
90
+ }
91
+ function formatBody(msg) {
92
+ if (Array.isArray(msg)) return msg.map((part) => typeof part === "string" ? part : JSON.stringify(part)).join(" ");
93
+ return msg;
94
+ }
95
+ /** Map a serialized Pino line to an OpenTelemetry log record. */
96
+ function toLogRecord(line, serviceName) {
97
+ const { level, time, msg, ...attributes } = JSON.parse(line);
98
+ delete attributes.pid;
99
+ delete attributes.hostname;
100
+ const label = typeof level === "number" ? PINO_LEVEL_LABELS[level] : String(level);
101
+ const timestamp = new Date(typeof time === "string" || typeof time === "number" ? time : Date.now());
102
+ return {
103
+ timestamp: Number.isNaN(timestamp.getTime()) ? /* @__PURE__ */ new Date() : timestamp,
104
+ severityNumber: label ? SEVERITY_NUMBERS[label] : void 0,
105
+ severityText: label,
106
+ body: formatBody(msg),
107
+ attributes: {
108
+ ...attributes,
109
+ "service.name": serviceName
110
+ }
111
+ };
14
112
  }
15
- var r = null, i = null;
16
- async function a(e = {}) {
17
- if (typeof window < "u") {
18
- t.warn({ namespace: "logger:otel" }, "OpenTelemetry integration is server-side only, skipping");
113
+ /**
114
+ * Set up OpenTelemetry integration for the logger.
115
+ *
116
+ * Call once at application startup. Loggers created before the call are
117
+ * exported too. Calling again replaces the previous setup.
118
+ *
119
+ * @param options - Configuration options
120
+ *
121
+ * @example
122
+ * // Send to Sentry via OTLP
123
+ * import { setupOpenTelemetryLogger } from '@eventuras/logger/opentelemetry';
124
+ * import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
125
+ * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
126
+ *
127
+ * await setupOpenTelemetryLogger({
128
+ * logRecordProcessor: new BatchLogRecordProcessor({
129
+ * exporter: new OTLPLogExporter({
130
+ * url: process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
131
+ * headers: {
132
+ * 'x-sentry-auth': `sentry sentry_key=${process.env.SENTRY_KEY}`
133
+ * }
134
+ * })
135
+ * })
136
+ * });
137
+ *
138
+ * @example
139
+ * // Use a provider your app already registered globally (e.g. via NodeSDK)
140
+ * await setupOpenTelemetryLogger();
141
+ */
142
+ async function setupOpenTelemetryLogger(options = {}) {
143
+ if (typeof window !== "undefined") {
144
+ Logger.warn({ namespace: NAMESPACE }, "OpenTelemetry integration is server-side only, skipping");
19
145
  return;
20
146
  }
21
- let { logRecordProcessor: a, loggerProvider: o, serviceName: s, enabled: c = !0 } = e;
22
- if (!c) {
23
- t.debug({ namespace: "logger:otel" }, "OpenTelemetry integration disabled");
147
+ const { serviceName, enabled = true } = options;
148
+ if (!enabled) {
149
+ Logger.debug({ namespace: NAMESPACE }, "OpenTelemetry integration disabled");
24
150
  return;
25
151
  }
26
- let l = await n();
27
- if (!l) {
28
- t.warn({ namespace: "logger:otel" }, "OpenTelemetry packages not available — integration disabled. Install @opentelemetry/api, @opentelemetry/api-logs, @opentelemetry/instrumentation-pino, and @opentelemetry/sdk-logs to enable.");
29
- return;
152
+ try {
153
+ const { provider, owned } = await resolveLoggerProvider(options);
154
+ const otelLogger = provider.getLogger(INSTRUMENTATION_SCOPE);
155
+ setLogLineSink(void 0);
156
+ if (loggerProvider && ownsLoggerProvider && loggerProvider !== provider) await loggerProvider.shutdown?.();
157
+ loggerProvider = provider;
158
+ ownsLoggerProvider = owned;
159
+ const resolvedServiceName = serviceName ?? (typeof process !== "undefined" ? process.env?.OTEL_SERVICE_NAME : void 0) ?? "unknown-service";
160
+ setLogLineSink((line) => otelLogger.emit(toLogRecord(line, resolvedServiceName)));
161
+ if (!(Logger.getTransport() instanceof PinoTransport)) Logger.warn({ namespace: NAMESPACE }, "The active transport is not PinoTransport — only PinoTransport output is exported to OpenTelemetry");
162
+ const source = options.loggerProvider ? "loggerProvider" : options.logRecordProcessor ? "logRecordProcessor" : "global";
163
+ Logger.info({
164
+ namespace: NAMESPACE,
165
+ context: { source }
166
+ }, "OpenTelemetry integration enabled");
167
+ } catch (error) {
168
+ Logger.error({
169
+ namespace: NAMESPACE,
170
+ error
171
+ }, "OpenTelemetry integration failed to start — logs are not exported");
30
172
  }
31
- let { PinoInstrumentation: u, LoggerProvider: d } = l;
32
- r &&= (r.disable(), null), i = o ?? new d(), a && i && i.addLogRecordProcessor(a);
33
- let f = s ?? (typeof process < "u" ? process.env?.OTEL_SERVICE_NAME : void 0) ?? "unknown-service";
34
- r = new u({ logHook: (e, t) => {
35
- t["service.name"] = f;
36
- } }), r.enable(), t.info({
37
- namespace: "logger:otel",
38
- context: { hasProcessor: !!a }
39
- }, "OpenTelemetry integration enabled");
40
173
  }
41
- async function o() {
42
- typeof window < "u" || (r &&= (r.disable(), null), i &&= (await i.shutdown(), null), t.info({ namespace: "logger:otel" }, "OpenTelemetry integration shut down"));
174
+ /**
175
+ * Shut down the OpenTelemetry logger integration.
176
+ * Call this when your application is shutting down to flush any pending logs.
177
+ *
178
+ * A provider created from `logRecordProcessor` is shut down. One passed as
179
+ * `loggerProvider`, or the global one, belongs to your app — it is flushed,
180
+ * not shut down.
181
+ *
182
+ * @example
183
+ * process.on('SIGTERM', async () => {
184
+ * await shutdownOpenTelemetryLogger();
185
+ * process.exit(0);
186
+ * });
187
+ */
188
+ async function shutdownOpenTelemetryLogger() {
189
+ if (typeof window !== "undefined") return;
190
+ setLogLineSink(void 0);
191
+ if (loggerProvider) {
192
+ const provider = loggerProvider;
193
+ loggerProvider = null;
194
+ await (ownsLoggerProvider ? provider.shutdown?.() : provider.forceFlush?.());
195
+ }
196
+ Logger.info({ namespace: NAMESPACE }, "OpenTelemetry integration shut down");
43
197
  }
44
- function s() {
45
- return typeof window < "u" ? null : i;
198
+ /**
199
+ * Get the active LoggerProvider instance, if any.
200
+ * Useful for advanced use cases or debugging.
201
+ */
202
+ function getLoggerProvider() {
203
+ if (typeof window !== "undefined") return null;
204
+ return loggerProvider;
46
205
  }
47
206
  //#endregion
48
- export { s as getLoggerProvider, a as setupOpenTelemetryLogger, o as shutdownOpenTelemetryLogger };
207
+ export { getLoggerProvider, setupOpenTelemetryLogger, shutdownOpenTelemetryLogger };
208
+
209
+ //# sourceMappingURL=opentelemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opentelemetry.js","names":[],"sources":["../src/opentelemetry.ts"],"sourcesContent":["/**\n * OpenTelemetry integration for @eventuras/logger\n *\n * Sends logs to any OpenTelemetry-compatible backend (Sentry, Grafana, the\n * Aspire dashboard, etc.) without vendor lock-in.\n *\n * Every line the Pino transport writes — after redaction, from every logger,\n * including ones created before setup — is also emitted as an OpenTelemetry\n * log record. The logger bridges this itself rather than through\n * `@opentelemetry/instrumentation-pino`, which only patches Pino when it is\n * loaded through an import-in-the-middle loader hook, and so never saw this\n * package's ESM import of Pino.\n *\n * `@opentelemetry/sdk-logs` is an optional peer dependency, needed only when\n * passing `logRecordProcessor` — which comes from that package anyway, so the\n * app already has it and the logger uses the app's copy.\n *\n * Setup never throws or rejects: if it can't start, it logs an error and\n * leaves logging to stdout untouched.\n *\n * @example\n * // In your app's instrumentation.ts or main entry point\n * import { setupOpenTelemetryLogger } from '@eventuras/logger/opentelemetry';\n * import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\n * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\n *\n * await setupOpenTelemetryLogger({\n * logRecordProcessor: new BatchLogRecordProcessor({\n * exporter: new OTLPLogExporter(), // reads OTEL_EXPORTER_OTLP_* env vars\n * }),\n * });\n *\n * @example\n * // Then use logger as normal\n * import { Logger } from '@eventuras/logger';\n *\n * const logger = Logger.create({ namespace: 'MyService' });\n * logger.error({ error: err }, 'Something failed'); // Sent to OpenTelemetry backend\n */\n\nimport { logs } from '@opentelemetry/api-logs';\nimport { Logger } from './Logger';\nimport { setLogLineSink } from './sink';\nimport { PinoTransport } from './transports/pino';\n\n/**\n * Minimal interface for an OpenTelemetry LogRecordProcessor.\n * Compatible with `@opentelemetry/sdk-logs` `LogRecordProcessor`.\n * Defined locally to avoid requiring OTel types at compile time.\n */\nexport interface LogRecordProcessor {\n onEmit(logRecord: unknown, context?: unknown): void;\n shutdown(): Promise<void>;\n forceFlush(): Promise<void>;\n}\n\n/**\n * Minimal shape of an OpenTelemetry log record, as emitted by this package.\n * Loosely typed so the SDK's own `LogRecord` type is assignable to it.\n */\nexport type OTelLogRecord = {\n timestamp?: unknown;\n severityNumber?: number;\n severityText?: string;\n body?: unknown;\n attributes?: Record<string, unknown>;\n};\n\n/**\n * Minimal interface for an OpenTelemetry Logger.\n * Compatible with `@opentelemetry/api-logs` `Logger`.\n */\nexport interface OTelLogger {\n emit(record: OTelLogRecord): void;\n}\n\n/**\n * Minimal interface for an OpenTelemetry LoggerProvider.\n * Compatible with `@opentelemetry/sdk-logs` `LoggerProvider` and the global\n * provider from `@opentelemetry/api-logs`.\n */\nexport interface OTelLoggerProvider {\n getLogger(name: string, version?: string): OTelLogger;\n shutdown?(): Promise<void>;\n forceFlush?(): Promise<void>;\n}\n\n/**\n * Options for OpenTelemetry logger integration\n */\nexport type OpenTelemetryLoggerOptions = {\n /**\n * Log record processor (e.g., BatchLogRecordProcessor with an exporter).\n * A LoggerProvider is created for it. Requires `@opentelemetry/sdk-logs`.\n */\n logRecordProcessor?: LogRecordProcessor;\n\n /**\n * Logger provider to emit to, e.g. one your app already configured with a\n * resource and processors. Takes precedence over `logRecordProcessor`.\n *\n * With neither option, the globally registered provider is used (as set up\n * by `@opentelemetry/sdk-node`, for instance).\n */\n loggerProvider?: OTelLoggerProvider;\n\n /**\n * Service name attached to every log record as the `service.name` attribute.\n * Defaults to the `OTEL_SERVICE_NAME` environment variable, or `'unknown-service'`.\n */\n serviceName?: string;\n\n /**\n * Whether to enable the integration. Default: true\n */\n enabled?: boolean;\n};\n\nconst NAMESPACE = 'logger:otel';\nconst INSTRUMENTATION_SCOPE = '@eventuras/logger';\n\n/** OpenTelemetry severity numbers for each level (logs data model). */\nconst SEVERITY_NUMBERS: Record<string, number> = {\n trace: 1,\n debug: 5,\n info: 9,\n warn: 13,\n error: 17,\n fatal: 21,\n};\n\n/** Pino's numeric levels, for when `formatters.level` has been overridden. */\nconst PINO_LEVEL_LABELS: Record<number, string> = {\n 10: 'trace',\n 20: 'debug',\n 30: 'info',\n 40: 'warn',\n 50: 'error',\n 60: 'fatal',\n};\n\nlet loggerProvider: OTelLoggerProvider | null = null;\n/** Whether `loggerProvider` was created here — only then is it ours to shut down. */\nlet ownsLoggerProvider = false;\n\nasync function loadPeer<T>(name: string, load: () => Promise<T>): Promise<T> {\n try {\n return await load();\n } catch (cause) {\n const reason = cause instanceof Error ? cause.message : String(cause);\n throw new Error(`${name} could not be loaded (${reason}). Install it to export logs with OpenTelemetry.`, {\n cause,\n });\n }\n}\n\nasync function resolveLoggerProvider(\n options: OpenTelemetryLoggerOptions,\n): Promise<{ provider: OTelLoggerProvider; owned: boolean }> {\n if (options.loggerProvider) {\n return { provider: options.loggerProvider, owned: false };\n }\n\n if (options.logRecordProcessor) {\n const { LoggerProvider } = await loadPeer('@opentelemetry/sdk-logs', () => import('@opentelemetry/sdk-logs'));\n return { provider: new LoggerProvider({ processors: [options.logRecordProcessor] }), owned: true };\n }\n\n return { provider: logs.getLoggerProvider(), owned: false };\n}\n\nfunction formatBody(msg: unknown): unknown {\n // Static methods (`Logger.info(options, 'a', 'b')`) log `msg` as an array.\n if (Array.isArray(msg)) {\n return msg.map((part) => (typeof part === 'string' ? part : JSON.stringify(part))).join(' ');\n }\n return msg;\n}\n\n/** Map a serialized Pino line to an OpenTelemetry log record. */\nfunction toLogRecord(line: string, serviceName: string): OTelLogRecord {\n const { level, time, msg, ...attributes } = JSON.parse(line) as Record<string, unknown>;\n\n // Redundant with the `host.name` and `process.pid` resource attributes.\n delete attributes.pid;\n delete attributes.hostname;\n\n const label = typeof level === 'number' ? PINO_LEVEL_LABELS[level] : String(level);\n const timestamp = new Date(typeof time === 'string' || typeof time === 'number' ? time : Date.now());\n\n return {\n timestamp: Number.isNaN(timestamp.getTime()) ? new Date() : timestamp,\n severityNumber: label ? SEVERITY_NUMBERS[label] : undefined,\n severityText: label,\n body: formatBody(msg),\n attributes: { ...attributes, 'service.name': serviceName },\n };\n}\n\n/**\n * Set up OpenTelemetry integration for the logger.\n *\n * Call once at application startup. Loggers created before the call are\n * exported too. Calling again replaces the previous setup.\n *\n * @param options - Configuration options\n *\n * @example\n * // Send to Sentry via OTLP\n * import { setupOpenTelemetryLogger } from '@eventuras/logger/opentelemetry';\n * import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\n * import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\n *\n * await setupOpenTelemetryLogger({\n * logRecordProcessor: new BatchLogRecordProcessor({\n * exporter: new OTLPLogExporter({\n * url: process.env.OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,\n * headers: {\n * 'x-sentry-auth': `sentry sentry_key=${process.env.SENTRY_KEY}`\n * }\n * })\n * })\n * });\n *\n * @example\n * // Use a provider your app already registered globally (e.g. via NodeSDK)\n * await setupOpenTelemetryLogger();\n */\nexport async function setupOpenTelemetryLogger(\n options: OpenTelemetryLoggerOptions = {}\n): Promise<void> {\n // Check if we're running in a browser environment\n if (typeof window !== 'undefined') {\n Logger.warn({ namespace: NAMESPACE }, 'OpenTelemetry integration is server-side only, skipping');\n return;\n }\n\n const { serviceName, enabled = true } = options;\n\n if (!enabled) {\n Logger.debug({ namespace: NAMESPACE }, 'OpenTelemetry integration disabled');\n return;\n }\n\n try {\n const { provider, owned } = await resolveLoggerProvider(options);\n const otelLogger = provider.getLogger(INSTRUMENTATION_SCOPE);\n\n // Replace any previous setup, releasing a provider created here.\n setLogLineSink(undefined);\n if (loggerProvider && ownsLoggerProvider && loggerProvider !== provider) {\n await loggerProvider.shutdown?.();\n }\n loggerProvider = provider;\n ownsLoggerProvider = owned;\n\n const resolvedServiceName =\n serviceName ??\n (typeof process !== 'undefined' ? process.env?.OTEL_SERVICE_NAME : undefined) ??\n 'unknown-service';\n\n setLogLineSink((line) => otelLogger.emit(toLogRecord(line, resolvedServiceName)));\n\n if (!(Logger.getTransport() instanceof PinoTransport)) {\n Logger.warn(\n { namespace: NAMESPACE },\n 'The active transport is not PinoTransport — only PinoTransport output is exported to OpenTelemetry',\n );\n }\n\n const source = options.loggerProvider\n ? 'loggerProvider'\n : options.logRecordProcessor\n ? 'logRecordProcessor'\n : 'global';\n Logger.info({ namespace: NAMESPACE, context: { source } }, 'OpenTelemetry integration enabled');\n } catch (error) {\n Logger.error(\n { namespace: NAMESPACE, error },\n 'OpenTelemetry integration failed to start — logs are not exported',\n );\n }\n}\n\n/**\n * Shut down the OpenTelemetry logger integration.\n * Call this when your application is shutting down to flush any pending logs.\n *\n * A provider created from `logRecordProcessor` is shut down. One passed as\n * `loggerProvider`, or the global one, belongs to your app — it is flushed,\n * not shut down.\n *\n * @example\n * process.on('SIGTERM', async () => {\n * await shutdownOpenTelemetryLogger();\n * process.exit(0);\n * });\n */\nexport async function shutdownOpenTelemetryLogger(): Promise<void> {\n // Check if we're running in a browser environment\n if (typeof window !== 'undefined') {\n return;\n }\n\n setLogLineSink(undefined);\n\n if (loggerProvider) {\n const provider = loggerProvider;\n loggerProvider = null;\n await (ownsLoggerProvider ? provider.shutdown?.() : provider.forceFlush?.());\n }\n\n Logger.info({ namespace: NAMESPACE }, 'OpenTelemetry integration shut down');\n}\n\n/**\n * Get the active LoggerProvider instance, if any.\n * Useful for advanced use cases or debugging.\n */\nexport function getLoggerProvider(): OTelLoggerProvider | null {\n // Return null if in browser environment\n if (typeof window !== 'undefined') {\n return null;\n }\n\n return loggerProvider;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsHA,IAAM,YAAY;AAClB,IAAM,wBAAwB;;AAG9B,IAAM,mBAA2C;CAC/C,OAAO;CACP,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;CACP,OAAO;AACT;;AAGA,IAAM,oBAA4C;CAChD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,IAAI,iBAA4C;;AAEhD,IAAI,qBAAqB;AAEzB,eAAe,SAAY,MAAc,MAAoC;CAC3E,IAAI;EACF,OAAO,MAAM,KAAK;CACpB,SAAS,OAAO;EACd,MAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACpE,MAAM,IAAI,MAAM,GAAG,KAAK,wBAAwB,OAAO,mDAAmD,EACxG,MACF,CAAC;CACH;AACF;AAEA,eAAe,sBACb,SAC2D;CAC3D,IAAI,QAAQ,gBACV,OAAO;EAAE,UAAU,QAAQ;EAAgB,OAAO;CAAM;CAG1D,IAAI,QAAQ,oBAAoB;EAC9B,MAAM,EAAE,mBAAmB,MAAM,SAAS,iCAAiC,OAAO,0BAA0B;EAC5G,OAAO;GAAE,UAAU,IAAI,eAAe,EAAE,YAAY,CAAC,QAAQ,kBAAkB,EAAE,CAAC;GAAG,OAAO;EAAK;CACnG;CAEA,OAAO;EAAE,UAAU,KAAK,kBAAkB;EAAG,OAAO;CAAM;AAC5D;AAEA,SAAS,WAAW,KAAuB;CAEzC,IAAI,MAAM,QAAQ,GAAG,GACnB,OAAO,IAAI,KAAK,SAAU,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI,CAAE,CAAC,CAAC,KAAK,GAAG;CAE7F,OAAO;AACT;;AAGA,SAAS,YAAY,MAAc,aAAoC;CACrE,MAAM,EAAE,OAAO,MAAM,KAAK,GAAG,eAAe,KAAK,MAAM,IAAI;CAG3D,OAAO,WAAW;CAClB,OAAO,WAAW;CAElB,MAAM,QAAQ,OAAO,UAAU,WAAW,kBAAkB,SAAS,OAAO,KAAK;CACjF,MAAM,YAAY,IAAI,KAAK,OAAO,SAAS,YAAY,OAAO,SAAS,WAAW,OAAO,KAAK,IAAI,CAAC;CAEnG,OAAO;EACL,WAAW,OAAO,MAAM,UAAU,QAAQ,CAAC,oBAAI,IAAI,KAAK,IAAI;EAC5D,gBAAgB,QAAQ,iBAAiB,SAAS,KAAA;EAClD,cAAc;EACd,MAAM,WAAW,GAAG;EACpB,YAAY;GAAE,GAAG;GAAY,gBAAgB;EAAY;CAC3D;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,eAAsB,yBACpB,UAAsC,CAAC,GACxB;CAEf,IAAI,OAAO,WAAW,aAAa;EACjC,OAAO,KAAK,EAAE,WAAW,UAAU,GAAG,yDAAyD;EAC/F;CACF;CAEA,MAAM,EAAE,aAAa,UAAU,SAAS;CAExC,IAAI,CAAC,SAAS;EACZ,OAAO,MAAM,EAAE,WAAW,UAAU,GAAG,oCAAoC;EAC3E;CACF;CAEA,IAAI;EACF,MAAM,EAAE,UAAU,UAAU,MAAM,sBAAsB,OAAO;EAC/D,MAAM,aAAa,SAAS,UAAU,qBAAqB;EAG3D,eAAe,KAAA,CAAS;EACxB,IAAI,kBAAkB,sBAAsB,mBAAmB,UAC7D,MAAM,eAAe,WAAW;EAElC,iBAAiB;EACjB,qBAAqB;EAErB,MAAM,sBACJ,gBACC,OAAO,YAAY,cAAc,QAAQ,KAAK,oBAAoB,KAAA,MACnE;EAEF,gBAAgB,SAAS,WAAW,KAAK,YAAY,MAAM,mBAAmB,CAAC,CAAC;EAEhF,IAAI,EAAE,OAAO,aAAa,aAAa,gBACrC,OAAO,KACL,EAAE,WAAW,UAAU,GACvB,oGACF;EAGF,MAAM,SAAS,QAAQ,iBACnB,mBACA,QAAQ,qBACN,uBACA;EACN,OAAO,KAAK;GAAE,WAAW;GAAW,SAAS,EAAE,OAAO;EAAE,GAAG,mCAAmC;CAChG,SAAS,OAAO;EACd,OAAO,MACL;GAAE,WAAW;GAAW;EAAM,GAC9B,mEACF;CACF;AACF;;;;;;;;;;;;;;;AAgBA,eAAsB,8BAA6C;CAEjE,IAAI,OAAO,WAAW,aACpB;CAGF,eAAe,KAAA,CAAS;CAExB,IAAI,gBAAgB;EAClB,MAAM,WAAW;EACjB,iBAAiB;EACjB,OAAO,qBAAqB,SAAS,WAAW,IAAI,SAAS,aAAa;CAC5E;CAEA,OAAO,KAAK,EAAE,WAAW,UAAU,GAAG,qCAAqC;AAC7E;;;;;AAMA,SAAgB,oBAA+C;CAE7D,IAAI,OAAO,WAAW,aACpB,OAAO;CAGT,OAAO;AACT"}
package/dist/sink.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Process-wide hook for the serialized log lines Pino writes.
3
+ *
4
+ * `PinoTransport` hands every line (after redaction) to the sink, and
5
+ * `@eventuras/logger/opentelemetry` sets the sink to forward lines as
6
+ * OpenTelemetry log records.
7
+ *
8
+ * The sink lives on `globalThis` rather than in module state because a
9
+ * bundler can load this package more than once in one process — Next.js
10
+ * compiles `instrumentation.ts` into its own layer — and the copy that sets
11
+ * the sink up is not necessarily the one whose loggers write the lines.
12
+ */
13
+ export type LogLineSink = (line: string) => void;
14
+ export declare function setLogLineSink(sink: LogLineSink | undefined): void;
15
+ /** Forward a line to the sink, if any. Never throws — telemetry must not break logging. */
16
+ export declare function forwardLogLine(line: string): void;
17
+ //# sourceMappingURL=sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sink.d.ts","sourceRoot":"","sources":["../src/sink.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAMjD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,GAAG,IAAI,CAElE;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CASjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"pino.d.ts","sourceRoot":"","sources":["../../src/transports/pino.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAa,EAAE,KAAK,MAAM,IAAI,UAAU,EAAE,KAAK,aAAa,IAAI,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;CAC5C;AAED,4CAA4C;AAC5C,MAAM,MAAM,oBAAoB,GAAG;IACjC,+CAA+C;IAC/C,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,6EAA6E;IAC7E,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAEF,qBAAa,aAAc,YAAW,YAAY;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;gBAEd,OAAO,GAAE,oBAAyB;IA2B9C,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvE,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY;IAKhD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
1
+ {"version":3,"file":"pino.d.ts","sourceRoot":"","sources":["../../src/transports/pino.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAa,EAAE,KAAK,MAAM,IAAI,UAAU,EAAE,KAAK,aAAa,IAAI,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAEhG,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;CAC5C;AAED,4CAA4C;AAC5C,MAAM,MAAM,oBAAoB,GAAG;IACjC,+CAA+C;IAC/C,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,qBAAqB,CAAC;IAC1C,6EAA6E;IAC7E,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC,CAAC;AAEF,qBAAa,aAAc,YAAW,YAAY;IAChD,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;gBAEd,OAAO,GAAE,oBAAyB;IAwC9C,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAQvE,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY;IAKhD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventuras/logger",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Structured logging with Pino and optional OpenTelemetry integration",
5
5
  "keywords": [
6
6
  "logger",
@@ -10,14 +10,14 @@
10
10
  "opentelemetry",
11
11
  "otel"
12
12
  ],
13
- "homepage": "https://github.com/losol/eventuras/tree/main/libs/logger#readme",
13
+ "homepage": "https://github.com/losol/origo/tree/main/packages/logger#readme",
14
14
  "bugs": {
15
- "url": "https://github.com/losol/eventuras/issues"
15
+ "url": "https://github.com/losol/origo/issues"
16
16
  },
17
17
  "repository": {
18
18
  "type": "git",
19
- "url": "https://github.com/losol/eventuras.git",
20
- "directory": "libs/logger"
19
+ "url": "https://github.com/losol/origo.git",
20
+ "directory": "packages/logger"
21
21
  },
22
22
  "license": "Apache-2.0",
23
23
  "type": "module",
@@ -41,33 +41,22 @@
41
41
  "dist"
42
42
  ],
43
43
  "dependencies": {
44
+ "@opentelemetry/api-logs": ">=0.200.0 <1.0.0",
44
45
  "pino": "^10.3.1"
45
46
  },
46
47
  "devDependencies": {
47
48
  "@opentelemetry/api": "^1.9.1",
48
- "@opentelemetry/api-logs": "^0.214.0",
49
- "@opentelemetry/instrumentation-pino": "^0.60.0",
50
- "@opentelemetry/sdk-logs": "^0.214.0",
51
- "vite": "^8.0.8",
52
- "vitest": "^4.1.4",
53
- "@eventuras/vite-config": "0.2.1"
49
+ "@opentelemetry/sdk-logs": "^0.222.0",
50
+ "vite": "^8.1.0",
51
+ "vitest": "^5.0.0",
52
+ "@eventuras/eslint-config": "1.0.5",
53
+ "@eventuras/typescript-config": "1.0.0",
54
+ "@eventuras/vite-config": "0.3.1"
54
55
  },
55
56
  "peerDependencies": {
56
- "@opentelemetry/api": "^1.9.0",
57
- "@opentelemetry/api-logs": ">=0.200.0 <1.0.0",
58
- "@opentelemetry/instrumentation-pino": ">=0.50.0 <1.0.0",
59
57
  "@opentelemetry/sdk-logs": ">=0.200.0 <1.0.0"
60
58
  },
61
59
  "peerDependenciesMeta": {
62
- "@opentelemetry/api": {
63
- "optional": true
64
- },
65
- "@opentelemetry/api-logs": {
66
- "optional": true
67
- },
68
- "@opentelemetry/instrumentation-pino": {
69
- "optional": true
70
- },
71
60
  "@opentelemetry/sdk-logs": {
72
61
  "optional": true
73
62
  }