@btravstack/observability 0.30.1 → 0.31.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.
package/README.md CHANGED
@@ -131,9 +131,14 @@ import { pinoSink } from "@btravstack/observability/pino";
131
131
  observability({ sink: pinoSink(pino()) });
132
132
  ```
133
133
 
134
+ The child logger uses a `trace` floor and leaves the supplied logger unchanged.
134
135
  The level filter stays this package's — `LOG_LEVEL`, validated once — so there
135
136
  is one filter in the process rather than two that can disagree.
136
137
 
138
+ Both JSON and Pino sinks retain safe error diagnostics and omit arbitrary
139
+ error payloads. Pino's error serializer is installed on a child logger at
140
+ `trace`, leaving the supplied logger's configuration intact.
141
+
137
142
  ## Traces and metrics
138
143
 
139
144
  The other half of the package's name, behind an optional-peer subpath the way
package/dist/index.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_json_sink = require("./json-sink-CQB0-tTI.cjs");
2
3
  let _btravstack_config = require("@btravstack/config");
3
4
  let _btravstack_core = require("@btravstack/core");
4
5
  let _btravstack_di = require("@btravstack/di");
@@ -22,88 +23,6 @@ const logLevel = (options = {}) => {
22
23
  };
23
24
  };
24
25
  //#endregion
25
- //#region src/json-sink.ts
26
- const DIAGNOSTIC_FIELDS = [
27
- "_tag",
28
- "sqlState",
29
- "constraint",
30
- "table",
31
- "database",
32
- "role",
33
- "bypass",
34
- "port"
35
- ];
36
- /**
37
- * An `Error`'s `message` and `stack` are **non-enumerable**, so
38
- * `JSON.stringify` renders a thrown one as `{}` — the line that exists to carry
39
- * a failure would carry nothing. Walks `cause` chains so a wrapped failure keeps
40
- * its origin.
41
- */
42
- const renderCause = (cause, depth = 0, parents = /* @__PURE__ */ new Set()) => {
43
- if (!(cause instanceof Error)) return depth > 0 && cause !== null && (typeof cause === "object" || typeof cause === "function" || typeof cause === "bigint") ? "[non-error]" : cause;
44
- if (parents.has(cause)) return "[circular]";
45
- const ancestors = new Set(parents).add(cause);
46
- const errors = cause instanceof AggregateError ? Object.getOwnPropertyDescriptor(cause, "errors")?.value : void 0;
47
- return {
48
- name: cause.name,
49
- message: cause.message,
50
- stack: cause.stack,
51
- ...Object.fromEntries(DIAGNOSTIC_FIELDS.flatMap((key) => {
52
- const value = Object.getOwnPropertyDescriptor(cause, key)?.value;
53
- return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? [[key, value]] : [];
54
- })),
55
- ...cause.cause === void 0 || depth >= 4 ? {} : { cause: renderCause(cause.cause, depth + 1, ancestors) },
56
- ...Array.isArray(errors) && depth < 4 ? {
57
- errors: Array.from({ length: Math.min(errors.length, 16) }, (_, index) => {
58
- const member = Object.getOwnPropertyDescriptor(errors, String(index))?.value;
59
- return renderCause(member, depth + 1, ancestors);
60
- }),
61
- ...errors.length > 16 ? { omittedErrors: errors.length - 16 } : {}
62
- } : {}
63
- };
64
- };
65
- /**
66
- * One JSON object per line on `stream`.
67
- *
68
- * The caller's attributes are spread FIRST and the line's own fields after them,
69
- * and that order is the precedence: an `attributes: { level: "info" }` cannot
70
- * rewrite an `error` line's severity, nor its `traceId`.
71
- *
72
- * The unit's ids are spread at the top level rather than nested under `unit`,
73
- * because `traceId` is the field an operator searches.
74
- */
75
- const jsonSink = (stream = process.stdout) => (line) => {
76
- const { level, message, attributes, cause, time, unit } = line;
77
- const rendered = {
78
- ...attributes,
79
- time: new Date(time).toISOString(),
80
- level,
81
- message,
82
- ...unit === void 0 ? {} : unit,
83
- ...cause === void 0 ? {} : { cause: renderCause(cause) }
84
- };
85
- stream.write(`${safeStringify(rendered)}\n`);
86
- };
87
- const serialises = (key, value) => {
88
- try {
89
- JSON.stringify({ [key]: value });
90
- return true;
91
- } catch {
92
- return false;
93
- }
94
- };
95
- const safeStringify = (rendered) => {
96
- try {
97
- return JSON.stringify(rendered);
98
- } catch {
99
- const kept = Object.entries(rendered).filter(([key, value]) => serialises(key, value));
100
- return JSON.stringify({
101
- ...Object.fromEntries(kept),
102
- unserialisable: Object.keys(rendered).filter((key) => !serialises(key, rendered[key]))
103
- });
104
- }
105
- };
106
- //#endregion
107
26
  //#region src/logger.ts
108
27
  const severity = (level) => _btravstack_core.LEVELS.indexOf(level);
109
28
  /**
@@ -182,7 +101,7 @@ const observability = (options = {}) => (0, _btravstack_di.Module)("Observabilit
182
101
  _btravstack_config.Config.provider(LoggerConfig)(_btravstack_config.Config.object({ level: _btravstack_config.Config.pinned(options.level, logLevel()) })),
183
102
  (0, _btravstack_di.Provider)(_btravstack_core.Logger)({
184
103
  inject: { config: LoggerConfig },
185
- sync: ({ config }) => createLogger(options.sink ?? jsonSink(), config.level)
104
+ sync: ({ config }) => createLogger(options.sink ?? require_json_sink.jsonSink(), config.level)
186
105
  }),
187
106
  _btravstack_di.Provider.member(_btravstack_core.Observers)({
188
107
  inject: { logger: _btravstack_core.Logger },
@@ -263,7 +182,7 @@ const kernelEvents = (logger) => (event) => {
263
182
  //#endregion
264
183
  exports.LoggerConfig = LoggerConfig;
265
184
  exports.createLogger = createLogger;
266
- exports.jsonSink = jsonSink;
185
+ exports.jsonSink = require_json_sink.jsonSink;
267
186
  exports.kernelEvents = kernelEvents;
268
187
  exports.logLevel = logLevel;
269
188
  exports.observability = observability;
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { t as jsonSink } from "./json-sink-7PQoEfMj.mjs";
1
2
  import { Config, ConfigFieldInvalid, Env } from "@btravstack/config";
2
3
  import { LEVELS, Logger, Observers, currentUnit } from "@btravstack/core";
3
4
  import { Module, Port, Provider } from "@btravstack/di";
@@ -21,88 +22,6 @@ const logLevel = (options = {}) => {
21
22
  };
22
23
  };
23
24
  //#endregion
24
- //#region src/json-sink.ts
25
- const DIAGNOSTIC_FIELDS = [
26
- "_tag",
27
- "sqlState",
28
- "constraint",
29
- "table",
30
- "database",
31
- "role",
32
- "bypass",
33
- "port"
34
- ];
35
- /**
36
- * An `Error`'s `message` and `stack` are **non-enumerable**, so
37
- * `JSON.stringify` renders a thrown one as `{}` — the line that exists to carry
38
- * a failure would carry nothing. Walks `cause` chains so a wrapped failure keeps
39
- * its origin.
40
- */
41
- const renderCause = (cause, depth = 0, parents = /* @__PURE__ */ new Set()) => {
42
- if (!(cause instanceof Error)) return depth > 0 && cause !== null && (typeof cause === "object" || typeof cause === "function" || typeof cause === "bigint") ? "[non-error]" : cause;
43
- if (parents.has(cause)) return "[circular]";
44
- const ancestors = new Set(parents).add(cause);
45
- const errors = cause instanceof AggregateError ? Object.getOwnPropertyDescriptor(cause, "errors")?.value : void 0;
46
- return {
47
- name: cause.name,
48
- message: cause.message,
49
- stack: cause.stack,
50
- ...Object.fromEntries(DIAGNOSTIC_FIELDS.flatMap((key) => {
51
- const value = Object.getOwnPropertyDescriptor(cause, key)?.value;
52
- return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? [[key, value]] : [];
53
- })),
54
- ...cause.cause === void 0 || depth >= 4 ? {} : { cause: renderCause(cause.cause, depth + 1, ancestors) },
55
- ...Array.isArray(errors) && depth < 4 ? {
56
- errors: Array.from({ length: Math.min(errors.length, 16) }, (_, index) => {
57
- const member = Object.getOwnPropertyDescriptor(errors, String(index))?.value;
58
- return renderCause(member, depth + 1, ancestors);
59
- }),
60
- ...errors.length > 16 ? { omittedErrors: errors.length - 16 } : {}
61
- } : {}
62
- };
63
- };
64
- /**
65
- * One JSON object per line on `stream`.
66
- *
67
- * The caller's attributes are spread FIRST and the line's own fields after them,
68
- * and that order is the precedence: an `attributes: { level: "info" }` cannot
69
- * rewrite an `error` line's severity, nor its `traceId`.
70
- *
71
- * The unit's ids are spread at the top level rather than nested under `unit`,
72
- * because `traceId` is the field an operator searches.
73
- */
74
- const jsonSink = (stream = process.stdout) => (line) => {
75
- const { level, message, attributes, cause, time, unit } = line;
76
- const rendered = {
77
- ...attributes,
78
- time: new Date(time).toISOString(),
79
- level,
80
- message,
81
- ...unit === void 0 ? {} : unit,
82
- ...cause === void 0 ? {} : { cause: renderCause(cause) }
83
- };
84
- stream.write(`${safeStringify(rendered)}\n`);
85
- };
86
- const serialises = (key, value) => {
87
- try {
88
- JSON.stringify({ [key]: value });
89
- return true;
90
- } catch {
91
- return false;
92
- }
93
- };
94
- const safeStringify = (rendered) => {
95
- try {
96
- return JSON.stringify(rendered);
97
- } catch {
98
- const kept = Object.entries(rendered).filter(([key, value]) => serialises(key, value));
99
- return JSON.stringify({
100
- ...Object.fromEntries(kept),
101
- unserialisable: Object.keys(rendered).filter((key) => !serialises(key, rendered[key]))
102
- });
103
- }
104
- };
105
- //#endregion
106
25
  //#region src/logger.ts
107
26
  const severity = (level) => LEVELS.indexOf(level);
108
27
  /**
@@ -0,0 +1,83 @@
1
+ //#region src/json-sink.ts
2
+ const DIAGNOSTIC_FIELDS = [
3
+ "_tag",
4
+ "sqlState",
5
+ "constraint",
6
+ "table",
7
+ "database",
8
+ "role",
9
+ "bypass",
10
+ "port"
11
+ ];
12
+ /**
13
+ * An `Error`'s `message` and `stack` are **non-enumerable**, so
14
+ * `JSON.stringify` renders a thrown one as `{}` — the line that exists to carry
15
+ * a failure would carry nothing. Walks `cause` chains so a wrapped failure keeps
16
+ * its origin.
17
+ */
18
+ const renderCause = (cause, depth = 0, parents = /* @__PURE__ */ new Set()) => {
19
+ if (!(cause instanceof Error)) return depth > 0 && cause !== null && (typeof cause === "object" || typeof cause === "function" || typeof cause === "bigint") ? "[non-error]" : cause;
20
+ if (parents.has(cause)) return "[circular]";
21
+ const ancestors = new Set(parents).add(cause);
22
+ const errors = cause instanceof AggregateError ? Object.getOwnPropertyDescriptor(cause, "errors")?.value : void 0;
23
+ return {
24
+ name: cause.name,
25
+ message: cause.message,
26
+ stack: cause.stack,
27
+ ...Object.fromEntries(DIAGNOSTIC_FIELDS.flatMap((key) => {
28
+ const value = Object.getOwnPropertyDescriptor(cause, key)?.value;
29
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? [[key, value]] : [];
30
+ })),
31
+ ...cause.cause === void 0 || depth >= 4 ? {} : { cause: renderCause(cause.cause, depth + 1, ancestors) },
32
+ ...Array.isArray(errors) && depth < 4 ? {
33
+ errors: Array.from({ length: Math.min(errors.length, 16) }, (_, index) => {
34
+ const member = Object.getOwnPropertyDescriptor(errors, String(index))?.value;
35
+ return renderCause(member, depth + 1, ancestors);
36
+ }),
37
+ ...errors.length > 16 ? { omittedErrors: errors.length - 16 } : {}
38
+ } : {}
39
+ };
40
+ };
41
+ /**
42
+ * One JSON object per line on `stream`.
43
+ *
44
+ * The caller's attributes are spread FIRST and the line's own fields after them,
45
+ * and that order is the precedence: an `attributes: { level: "info" }` cannot
46
+ * rewrite an `error` line's severity, nor its `traceId`.
47
+ *
48
+ * The unit's ids are spread at the top level rather than nested under `unit`,
49
+ * because `traceId` is the field an operator searches.
50
+ */
51
+ const jsonSink = (stream = process.stdout) => (line) => {
52
+ const { level, message, attributes, cause, time, unit } = line;
53
+ const rendered = {
54
+ ...attributes,
55
+ time: new Date(time).toISOString(),
56
+ level,
57
+ message,
58
+ ...unit === void 0 ? {} : unit,
59
+ ...cause === void 0 ? {} : { cause: renderCause(cause) }
60
+ };
61
+ stream.write(`${safeStringify(rendered)}\n`);
62
+ };
63
+ const serialises = (key, value) => {
64
+ try {
65
+ JSON.stringify({ [key]: value });
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ };
71
+ const safeStringify = (rendered) => {
72
+ try {
73
+ return JSON.stringify(rendered);
74
+ } catch {
75
+ const kept = Object.entries(rendered).filter(([key, value]) => serialises(key, value));
76
+ return JSON.stringify({
77
+ ...Object.fromEntries(kept),
78
+ unserialisable: Object.keys(rendered).filter((key) => !serialises(key, rendered[key]))
79
+ });
80
+ }
81
+ };
82
+ //#endregion
83
+ export { renderCause as n, jsonSink as t };
@@ -0,0 +1,94 @@
1
+ //#region src/json-sink.ts
2
+ const DIAGNOSTIC_FIELDS = [
3
+ "_tag",
4
+ "sqlState",
5
+ "constraint",
6
+ "table",
7
+ "database",
8
+ "role",
9
+ "bypass",
10
+ "port"
11
+ ];
12
+ /**
13
+ * An `Error`'s `message` and `stack` are **non-enumerable**, so
14
+ * `JSON.stringify` renders a thrown one as `{}` — the line that exists to carry
15
+ * a failure would carry nothing. Walks `cause` chains so a wrapped failure keeps
16
+ * its origin.
17
+ */
18
+ const renderCause = (cause, depth = 0, parents = /* @__PURE__ */ new Set()) => {
19
+ if (!(cause instanceof Error)) return depth > 0 && cause !== null && (typeof cause === "object" || typeof cause === "function" || typeof cause === "bigint") ? "[non-error]" : cause;
20
+ if (parents.has(cause)) return "[circular]";
21
+ const ancestors = new Set(parents).add(cause);
22
+ const errors = cause instanceof AggregateError ? Object.getOwnPropertyDescriptor(cause, "errors")?.value : void 0;
23
+ return {
24
+ name: cause.name,
25
+ message: cause.message,
26
+ stack: cause.stack,
27
+ ...Object.fromEntries(DIAGNOSTIC_FIELDS.flatMap((key) => {
28
+ const value = Object.getOwnPropertyDescriptor(cause, key)?.value;
29
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? [[key, value]] : [];
30
+ })),
31
+ ...cause.cause === void 0 || depth >= 4 ? {} : { cause: renderCause(cause.cause, depth + 1, ancestors) },
32
+ ...Array.isArray(errors) && depth < 4 ? {
33
+ errors: Array.from({ length: Math.min(errors.length, 16) }, (_, index) => {
34
+ const member = Object.getOwnPropertyDescriptor(errors, String(index))?.value;
35
+ return renderCause(member, depth + 1, ancestors);
36
+ }),
37
+ ...errors.length > 16 ? { omittedErrors: errors.length - 16 } : {}
38
+ } : {}
39
+ };
40
+ };
41
+ /**
42
+ * One JSON object per line on `stream`.
43
+ *
44
+ * The caller's attributes are spread FIRST and the line's own fields after them,
45
+ * and that order is the precedence: an `attributes: { level: "info" }` cannot
46
+ * rewrite an `error` line's severity, nor its `traceId`.
47
+ *
48
+ * The unit's ids are spread at the top level rather than nested under `unit`,
49
+ * because `traceId` is the field an operator searches.
50
+ */
51
+ const jsonSink = (stream = process.stdout) => (line) => {
52
+ const { level, message, attributes, cause, time, unit } = line;
53
+ const rendered = {
54
+ ...attributes,
55
+ time: new Date(time).toISOString(),
56
+ level,
57
+ message,
58
+ ...unit === void 0 ? {} : unit,
59
+ ...cause === void 0 ? {} : { cause: renderCause(cause) }
60
+ };
61
+ stream.write(`${safeStringify(rendered)}\n`);
62
+ };
63
+ const serialises = (key, value) => {
64
+ try {
65
+ JSON.stringify({ [key]: value });
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ };
71
+ const safeStringify = (rendered) => {
72
+ try {
73
+ return JSON.stringify(rendered);
74
+ } catch {
75
+ const kept = Object.entries(rendered).filter(([key, value]) => serialises(key, value));
76
+ return JSON.stringify({
77
+ ...Object.fromEntries(kept),
78
+ unserialisable: Object.keys(rendered).filter((key) => !serialises(key, rendered[key]))
79
+ });
80
+ }
81
+ };
82
+ //#endregion
83
+ Object.defineProperty(exports, "jsonSink", {
84
+ enumerable: true,
85
+ get: function() {
86
+ return jsonSink;
87
+ }
88
+ });
89
+ Object.defineProperty(exports, "renderCause", {
90
+ enumerable: true,
91
+ get: function() {
92
+ return renderCause;
93
+ }
94
+ });
package/dist/pino.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_json_sink = require("./json-sink-CQB0-tTI.cjs");
2
3
  //#region src/pino.ts
3
4
  /**
4
5
  * A {@link Sink} over a pino logger — the subpath a deployment reaches for
@@ -16,19 +17,29 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
16
17
  * ```
17
18
  *
18
19
  * The level filter stays **ours**: `createLogger` has already decided the
19
- * line is worth writing by the time a sink sees it, so pino is configured at
20
- * `trace` here — one filter in the process, and it is the one `LOG_LEVEL`
21
- * validated at startup. `fatal` and `trace` map to pino's own; the ambient
22
- * unit's ids ride as fields, not as a message prefix, so they stay indexable.
20
+ * line is worth writing by the time a sink sees it, so the child logger has a
21
+ * `trace` floor — one filter in the process, and it is the one `LOG_LEVEL`
22
+ * validated at startup. The supplied logger is left unchanged. `fatal` and
23
+ * `trace` map to pino's own; the ambient unit's ids ride as fields, not as a
24
+ * message prefix, so they stay indexable.
23
25
  */
24
- const pinoSink = (logger) => (line) => {
25
- const { level, message, attributes, cause, unit } = line;
26
- const fields = {
27
- ...attributes,
28
- ...unit === void 0 ? {} : unit,
29
- ...cause === void 0 ? {} : { err: cause }
26
+ const pinoSink = (logger) => {
27
+ const safeLogger = logger.child({}, {
28
+ level: "trace",
29
+ serializers: { err: (cause) => cause instanceof Error ? {
30
+ type: cause.name,
31
+ ...require_json_sink.renderCause(cause)
32
+ } : require_json_sink.renderCause(cause) }
33
+ });
34
+ return (line) => {
35
+ const { level, message, attributes, cause, unit } = line;
36
+ const fields = {
37
+ ...attributes,
38
+ ...unit === void 0 ? {} : unit,
39
+ ...cause === void 0 ? {} : { err: cause }
40
+ };
41
+ safeLogger[level](fields, message);
30
42
  };
31
- logger[level](fields, message);
32
43
  };
33
44
  //#endregion
34
45
  exports.pinoSink = pinoSink;
package/dist/pino.d.cts CHANGED
@@ -17,10 +17,11 @@ import { Logger } from "pino";
17
17
  * ```
18
18
  *
19
19
  * The level filter stays **ours**: `createLogger` has already decided the
20
- * line is worth writing by the time a sink sees it, so pino is configured at
21
- * `trace` here — one filter in the process, and it is the one `LOG_LEVEL`
22
- * validated at startup. `fatal` and `trace` map to pino's own; the ambient
23
- * unit's ids ride as fields, not as a message prefix, so they stay indexable.
20
+ * line is worth writing by the time a sink sees it, so the child logger has a
21
+ * `trace` floor — one filter in the process, and it is the one `LOG_LEVEL`
22
+ * validated at startup. The supplied logger is left unchanged. `fatal` and
23
+ * `trace` map to pino's own; the ambient unit's ids ride as fields, not as a
24
+ * message prefix, so they stay indexable.
24
25
  */
25
26
  export declare const pinoSink: (logger: Logger) => Sink;
26
27
  //#endregion
package/dist/pino.d.mts CHANGED
@@ -17,10 +17,11 @@ import { Logger } from "pino";
17
17
  * ```
18
18
  *
19
19
  * The level filter stays **ours**: `createLogger` has already decided the
20
- * line is worth writing by the time a sink sees it, so pino is configured at
21
- * `trace` here — one filter in the process, and it is the one `LOG_LEVEL`
22
- * validated at startup. `fatal` and `trace` map to pino's own; the ambient
23
- * unit's ids ride as fields, not as a message prefix, so they stay indexable.
20
+ * line is worth writing by the time a sink sees it, so the child logger has a
21
+ * `trace` floor — one filter in the process, and it is the one `LOG_LEVEL`
22
+ * validated at startup. The supplied logger is left unchanged. `fatal` and
23
+ * `trace` map to pino's own; the ambient unit's ids ride as fields, not as a
24
+ * message prefix, so they stay indexable.
24
25
  */
25
26
  export declare const pinoSink: (logger: Logger) => Sink;
26
27
  //#endregion
package/dist/pino.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { n as renderCause } from "./json-sink-7PQoEfMj.mjs";
1
2
  //#region src/pino.ts
2
3
  /**
3
4
  * A {@link Sink} over a pino logger — the subpath a deployment reaches for
@@ -15,19 +16,29 @@
15
16
  * ```
16
17
  *
17
18
  * The level filter stays **ours**: `createLogger` has already decided the
18
- * line is worth writing by the time a sink sees it, so pino is configured at
19
- * `trace` here — one filter in the process, and it is the one `LOG_LEVEL`
20
- * validated at startup. `fatal` and `trace` map to pino's own; the ambient
21
- * unit's ids ride as fields, not as a message prefix, so they stay indexable.
19
+ * line is worth writing by the time a sink sees it, so the child logger has a
20
+ * `trace` floor — one filter in the process, and it is the one `LOG_LEVEL`
21
+ * validated at startup. The supplied logger is left unchanged. `fatal` and
22
+ * `trace` map to pino's own; the ambient unit's ids ride as fields, not as a
23
+ * message prefix, so they stay indexable.
22
24
  */
23
- const pinoSink = (logger) => (line) => {
24
- const { level, message, attributes, cause, unit } = line;
25
- const fields = {
26
- ...attributes,
27
- ...unit === void 0 ? {} : unit,
28
- ...cause === void 0 ? {} : { err: cause }
25
+ const pinoSink = (logger) => {
26
+ const safeLogger = logger.child({}, {
27
+ level: "trace",
28
+ serializers: { err: (cause) => cause instanceof Error ? {
29
+ type: cause.name,
30
+ ...renderCause(cause)
31
+ } : renderCause(cause) }
32
+ });
33
+ return (line) => {
34
+ const { level, message, attributes, cause, unit } = line;
35
+ const fields = {
36
+ ...attributes,
37
+ ...unit === void 0 ? {} : unit,
38
+ ...cause === void 0 ? {} : { err: cause }
39
+ };
40
+ safeLogger[level](fields, message);
29
41
  };
30
- logger[level](fields, message);
31
42
  };
32
43
  //#endregion
33
44
  export { pinoSink };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btravstack/observability",
3
- "version": "0.30.1",
3
+ "version": "0.31.0",
4
4
  "description": "Observability for @btravstack/core: a strict Logger port correlated with the kernel's units, a dependency-free JSON sink, and the lifecycle events as log lines",
5
5
  "keywords": [
6
6
  "dependency-injection",
@@ -65,10 +65,10 @@
65
65
  "./package.json": "./package.json"
66
66
  },
67
67
  "devDependencies": {
68
- "@btravstack/config": "0.30.1",
69
- "@btravstack/core": "0.30.1",
70
- "@btravstack/di": "0.30.1",
71
- "@btravstack/testing": "0.30.1",
68
+ "@btravstack/config": "0.31.0",
69
+ "@btravstack/core": "0.31.0",
70
+ "@btravstack/di": "0.31.0",
71
+ "@btravstack/testing": "0.31.0",
72
72
  "@btravstack/tsconfig": "0.4.0",
73
73
  "@opentelemetry/api": "1.9.1",
74
74
  "@opentelemetry/sdk-node": "0.222.0",
@@ -83,9 +83,9 @@
83
83
  "vitest": "5.0.3"
84
84
  },
85
85
  "peerDependencies": {
86
- "@btravstack/config": "^0.30.1",
87
- "@btravstack/core": "^0.30.1",
88
- "@btravstack/di": "^0.30.1",
86
+ "@btravstack/config": "^0.31.0",
87
+ "@btravstack/core": "^0.31.0",
88
+ "@btravstack/di": "^0.31.0",
89
89
  "@opentelemetry/api": "^1.9.0",
90
90
  "@opentelemetry/sdk-node": "^0.222.0",
91
91
  "pino": "^10",