@bymax-one/nest-logger 1.2.0 → 1.2.2

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.
@@ -25,6 +25,99 @@ interface ServiceMetadata {
25
25
  readonly name: string;
26
26
  /** OTel attribute `service.version` — semver, commit SHA, or build tag. */
27
27
  readonly version: string;
28
+ /**
29
+ * OTel attribute `service.namespace` (**Stable**) — the group the service
30
+ * belongs to, e.g. a team, a bounded context or a tenant of the platform.
31
+ * Two services may share a `name` as long as their namespaces differ.
32
+ */
33
+ readonly namespace?: string;
34
+ /**
35
+ * OTel attribute `service.instance.id` (**Stable**) — identifies ONE running
36
+ * instance, so the triplet (namespace, name, instanceId) is globally unique.
37
+ *
38
+ * The library never generates this. A value minted here would be the logger's
39
+ * rather than the OpenTelemetry Resource's, so logs and traces would disagree
40
+ * about which instance served a request, and it would change on every restart
41
+ * while looking authoritative. Supply it from the platform — the Kubernetes
42
+ * pod UID, the ECS task ARN, the VM instance id — or through
43
+ * `OTEL_RESOURCE_ATTRIBUTES`, which is the same source the SDK reads.
44
+ *
45
+ * Treat it as HIGH cardinality: fine as a log field, not as a metric label.
46
+ */
47
+ readonly instanceId?: string;
48
+ /**
49
+ * OTel attribute `deployment.environment.name` (**Stable**) — `production`,
50
+ * `staging`, and so on. Falls back to `NODE_ENV` when omitted.
51
+ *
52
+ * The older `deployment.environment` spelling is **Deprecated** in the
53
+ * semantic conventions and is never emitted.
54
+ */
55
+ readonly environment?: string;
56
+ }
57
+ /**
58
+ * Service identity after precedence has been applied.
59
+ *
60
+ * Distinct from {@link ServiceMetadata} because the optional fields here mean
61
+ * "resolved to nothing" rather than "not configured": every source — options,
62
+ * `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES`, `NODE_ENV` — has already been
63
+ * consulted, and a field still absent will not appear on any entry.
64
+ */
65
+ interface ResolvedServiceMetadata {
66
+ /** `service.name`, always present. */
67
+ name: string;
68
+ /** `service.version`, always present. */
69
+ version: string;
70
+ /** `service.namespace`, when any source supplied one. */
71
+ namespace?: string;
72
+ /** `service.instance.id`, when any source supplied one. */
73
+ instanceId?: string;
74
+ /** `deployment.environment.name`, when any source supplied one. */
75
+ environment?: string;
76
+ }
77
+ /**
78
+ * The `service` block as it appears in an EMITTED record, under the default
79
+ * `resourceFormat: 'nested'`.
80
+ *
81
+ * Distinct from {@link ServiceMetadata} on purpose, and the distinction is the
82
+ * kind of defect this library has already been bitten by once: a published type
83
+ * that describes something the runtime never emits. `ServiceMetadata` is what a
84
+ * consumer CONFIGURES — flat option names like `instanceId` and `environment`.
85
+ * What comes out is the flattened OTel attribute path: `service.instance.id`
86
+ * nests as `service: { instance: { id } }`, and the environment is not under
87
+ * `service` at all, it is `deployment.environment.name`. Typing the emitted
88
+ * record with the configuration interface would advertise `entry.service.instanceId`
89
+ * to every consumer, and that property does not exist on any entry.
90
+ *
91
+ * Under `resourceFormat: 'flat'` these values appear as dotted top-level keys
92
+ * (`"service.instance.id"`), which {@link LogEntry}'s index signature already
93
+ * admits — a flat record simply has no `service` object.
94
+ */
95
+ interface EmittedServiceResource {
96
+ /** OTel `service.name`. */
97
+ readonly name: string;
98
+ /** OTel `service.version`. */
99
+ readonly version: string;
100
+ /** OTel `service.namespace`, when resolved. */
101
+ readonly namespace?: string;
102
+ /** OTel `service.instance.id`, nested as the attribute path spells it. */
103
+ readonly instance?: {
104
+ readonly id: string;
105
+ };
106
+ /** Consumer-supplied extras carried through from the `service` option. */
107
+ readonly [key: string]: unknown;
108
+ }
109
+ /**
110
+ * The `deployment` block as it appears in an EMITTED record under
111
+ * `resourceFormat: 'nested'`, carrying `deployment.environment.name`.
112
+ *
113
+ * Absent entirely when no source resolved an environment. The deprecated
114
+ * `deployment.environment` spelling is never emitted.
115
+ */
116
+ interface EmittedDeploymentResource {
117
+ /** OTel `deployment.environment.name`, flattened from its attribute path. */
118
+ readonly environment: {
119
+ readonly name: string;
120
+ };
28
121
  }
29
122
 
30
123
  /**
@@ -59,8 +152,25 @@ interface LogEntry {
59
152
  msg: string;
60
153
  /** Convention key — `MODULE_ACTION_RESULT` format. */
61
154
  logKey?: string;
62
- /** Service metadata snapshot — see {@link ServiceMetadata}. */
63
- service?: ServiceMetadata;
155
+ /**
156
+ * OTel event name derived from {@link logKey} (`PAYMENT_FAILED` →
157
+ * `payment.failed`), emitted on structured calls unless `eventNameField` is
158
+ * `false`. Declared explicitly because the index signature below would type
159
+ * it `unknown`: a documented field a consumer cannot read without a cast is
160
+ * not really published.
161
+ *
162
+ * The key is configurable, so a renamed field arrives through the index
163
+ * signature instead — this declaration describes the default only.
164
+ */
165
+ 'event.name'?: string;
166
+ /**
167
+ * Service identity as EMITTED — see {@link EmittedServiceResource}. Not the
168
+ * configuration shape: `service.instance.id` nests, and the environment lives
169
+ * under `deployment`, not here.
170
+ */
171
+ service?: EmittedServiceResource;
172
+ /** Deployment identity as emitted — see {@link EmittedDeploymentResource}. */
173
+ deployment?: EmittedDeploymentResource;
64
174
  /** Optional NestJS context (typically the emitting class name). */
65
175
  context?: string;
66
176
  /** Optional correlation IDs propagated via AsyncLocalStorage. */
@@ -159,4 +269,4 @@ declare const RESERVED_LOG_KEYS_NOT_EMITTED: Readonly<{
159
269
  */
160
270
  type ReservedLogKey = (typeof RESERVED_LOG_KEYS)[keyof typeof RESERVED_LOG_KEYS];
161
271
 
162
- export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ServiceMetadata };
272
+ export { type EmittedDeploymentResource, type EmittedServiceResource, LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ResolvedServiceMetadata, type ServiceMetadata };
@@ -25,6 +25,99 @@ interface ServiceMetadata {
25
25
  readonly name: string;
26
26
  /** OTel attribute `service.version` — semver, commit SHA, or build tag. */
27
27
  readonly version: string;
28
+ /**
29
+ * OTel attribute `service.namespace` (**Stable**) — the group the service
30
+ * belongs to, e.g. a team, a bounded context or a tenant of the platform.
31
+ * Two services may share a `name` as long as their namespaces differ.
32
+ */
33
+ readonly namespace?: string;
34
+ /**
35
+ * OTel attribute `service.instance.id` (**Stable**) — identifies ONE running
36
+ * instance, so the triplet (namespace, name, instanceId) is globally unique.
37
+ *
38
+ * The library never generates this. A value minted here would be the logger's
39
+ * rather than the OpenTelemetry Resource's, so logs and traces would disagree
40
+ * about which instance served a request, and it would change on every restart
41
+ * while looking authoritative. Supply it from the platform — the Kubernetes
42
+ * pod UID, the ECS task ARN, the VM instance id — or through
43
+ * `OTEL_RESOURCE_ATTRIBUTES`, which is the same source the SDK reads.
44
+ *
45
+ * Treat it as HIGH cardinality: fine as a log field, not as a metric label.
46
+ */
47
+ readonly instanceId?: string;
48
+ /**
49
+ * OTel attribute `deployment.environment.name` (**Stable**) — `production`,
50
+ * `staging`, and so on. Falls back to `NODE_ENV` when omitted.
51
+ *
52
+ * The older `deployment.environment` spelling is **Deprecated** in the
53
+ * semantic conventions and is never emitted.
54
+ */
55
+ readonly environment?: string;
56
+ }
57
+ /**
58
+ * Service identity after precedence has been applied.
59
+ *
60
+ * Distinct from {@link ServiceMetadata} because the optional fields here mean
61
+ * "resolved to nothing" rather than "not configured": every source — options,
62
+ * `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES`, `NODE_ENV` — has already been
63
+ * consulted, and a field still absent will not appear on any entry.
64
+ */
65
+ interface ResolvedServiceMetadata {
66
+ /** `service.name`, always present. */
67
+ name: string;
68
+ /** `service.version`, always present. */
69
+ version: string;
70
+ /** `service.namespace`, when any source supplied one. */
71
+ namespace?: string;
72
+ /** `service.instance.id`, when any source supplied one. */
73
+ instanceId?: string;
74
+ /** `deployment.environment.name`, when any source supplied one. */
75
+ environment?: string;
76
+ }
77
+ /**
78
+ * The `service` block as it appears in an EMITTED record, under the default
79
+ * `resourceFormat: 'nested'`.
80
+ *
81
+ * Distinct from {@link ServiceMetadata} on purpose, and the distinction is the
82
+ * kind of defect this library has already been bitten by once: a published type
83
+ * that describes something the runtime never emits. `ServiceMetadata` is what a
84
+ * consumer CONFIGURES — flat option names like `instanceId` and `environment`.
85
+ * What comes out is the flattened OTel attribute path: `service.instance.id`
86
+ * nests as `service: { instance: { id } }`, and the environment is not under
87
+ * `service` at all, it is `deployment.environment.name`. Typing the emitted
88
+ * record with the configuration interface would advertise `entry.service.instanceId`
89
+ * to every consumer, and that property does not exist on any entry.
90
+ *
91
+ * Under `resourceFormat: 'flat'` these values appear as dotted top-level keys
92
+ * (`"service.instance.id"`), which {@link LogEntry}'s index signature already
93
+ * admits — a flat record simply has no `service` object.
94
+ */
95
+ interface EmittedServiceResource {
96
+ /** OTel `service.name`. */
97
+ readonly name: string;
98
+ /** OTel `service.version`. */
99
+ readonly version: string;
100
+ /** OTel `service.namespace`, when resolved. */
101
+ readonly namespace?: string;
102
+ /** OTel `service.instance.id`, nested as the attribute path spells it. */
103
+ readonly instance?: {
104
+ readonly id: string;
105
+ };
106
+ /** Consumer-supplied extras carried through from the `service` option. */
107
+ readonly [key: string]: unknown;
108
+ }
109
+ /**
110
+ * The `deployment` block as it appears in an EMITTED record under
111
+ * `resourceFormat: 'nested'`, carrying `deployment.environment.name`.
112
+ *
113
+ * Absent entirely when no source resolved an environment. The deprecated
114
+ * `deployment.environment` spelling is never emitted.
115
+ */
116
+ interface EmittedDeploymentResource {
117
+ /** OTel `deployment.environment.name`, flattened from its attribute path. */
118
+ readonly environment: {
119
+ readonly name: string;
120
+ };
28
121
  }
29
122
 
30
123
  /**
@@ -59,8 +152,25 @@ interface LogEntry {
59
152
  msg: string;
60
153
  /** Convention key — `MODULE_ACTION_RESULT` format. */
61
154
  logKey?: string;
62
- /** Service metadata snapshot — see {@link ServiceMetadata}. */
63
- service?: ServiceMetadata;
155
+ /**
156
+ * OTel event name derived from {@link logKey} (`PAYMENT_FAILED` →
157
+ * `payment.failed`), emitted on structured calls unless `eventNameField` is
158
+ * `false`. Declared explicitly because the index signature below would type
159
+ * it `unknown`: a documented field a consumer cannot read without a cast is
160
+ * not really published.
161
+ *
162
+ * The key is configurable, so a renamed field arrives through the index
163
+ * signature instead — this declaration describes the default only.
164
+ */
165
+ 'event.name'?: string;
166
+ /**
167
+ * Service identity as EMITTED — see {@link EmittedServiceResource}. Not the
168
+ * configuration shape: `service.instance.id` nests, and the environment lives
169
+ * under `deployment`, not here.
170
+ */
171
+ service?: EmittedServiceResource;
172
+ /** Deployment identity as emitted — see {@link EmittedDeploymentResource}. */
173
+ deployment?: EmittedDeploymentResource;
64
174
  /** Optional NestJS context (typically the emitting class name). */
65
175
  context?: string;
66
176
  /** Optional correlation IDs propagated via AsyncLocalStorage. */
@@ -159,4 +269,4 @@ declare const RESERVED_LOG_KEYS_NOT_EMITTED: Readonly<{
159
269
  */
160
270
  type ReservedLogKey = (typeof RESERVED_LOG_KEYS)[keyof typeof RESERVED_LOG_KEYS];
161
271
 
162
- export { LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ServiceMetadata };
272
+ export { type EmittedDeploymentResource, type EmittedServiceResource, LOG_KEYS_CONVENTION_REGEX, type LogEntry, type LogLevel, RESERVED_LOG_KEYS, RESERVED_LOG_KEYS_NOT_EMITTED, type ReservedLogKey, type ResolvedServiceMetadata, type ServiceMetadata };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bymax-one/nest-logger",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Structured JSON logging for NestJS based on Pino 10, with optional OpenTelemetry correlation.",
5
5
  "author": "Bymax One <support@bymax.one>",
6
6
  "license": "MIT",