autotel 4.1.0 → 4.2.1
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/auto.cjs +5 -3
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.js +3 -3
- package/dist/auto.js.map +1 -1
- package/dist/chunk-C_NdSu1c.cjs +34 -0
- package/dist/correlation-id.cjs +1 -1
- package/dist/correlation-id.d.cts.map +1 -1
- package/dist/correlation-id.d.ts.map +1 -1
- package/dist/correlation-id.js +1 -1
- package/dist/decorators.cjs +1 -1
- package/dist/decorators.js +1 -1
- package/dist/{event-ByBTV9M2.js → event-531asIM6.js} +4 -4
- package/dist/{event-ByBTV9M2.js.map → event-531asIM6.js.map} +1 -1
- package/dist/{event-BhHREDJk.cjs → event-CcZYwp50.cjs} +4 -4
- package/dist/{event-BhHREDJk.cjs.map → event-CcZYwp50.cjs.map} +1 -1
- package/dist/event.cjs +1 -1
- package/dist/event.js +1 -1
- package/dist/{functional-zpzNLhky.cjs → functional-C8B0Qa7o.cjs} +10 -7
- package/dist/functional-C8B0Qa7o.cjs.map +1 -0
- package/dist/{functional-DtI0u4vx.js → functional-r-AUIRy_.js} +9 -9
- package/dist/functional-r-AUIRy_.js.map +1 -0
- package/dist/functional.cjs +1 -1
- package/dist/functional.js +1 -1
- package/dist/http.cjs +1 -1
- package/dist/http.js +1 -1
- package/dist/index.cjs +15 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -14
- package/dist/index.js.map +1 -1
- package/dist/{init-D-jnNMix.js → init-BS2JVkrL.js} +2 -2
- package/dist/{init-D-jnNMix.js.map → init-BS2JVkrL.js.map} +1 -1
- package/dist/{init-BX7AmFRl.cjs → init-BXiuPK6j.cjs} +3 -3
- package/dist/{init-BX7AmFRl.cjs.map → init-BXiuPK6j.cjs.map} +1 -1
- package/dist/instrumentation.cjs +2 -2
- package/dist/instrumentation.js +2 -2
- package/dist/logger.cjs +236 -8
- package/dist/logger.cjs.map +1 -0
- package/dist/messaging.cjs +1 -1
- package/dist/messaging.js +1 -1
- package/dist/{node-require-DF5QBX6z.cjs → node-require-CZ_PU448.cjs} +6 -4
- package/dist/node-require-CZ_PU448.cjs.map +1 -0
- package/dist/{node-require-Db1oDpLj.js → node-require-vROmTeJ8.js} +5 -5
- package/dist/node-require-vROmTeJ8.js.map +1 -0
- package/dist/{operation-context-C-2hmmtP.js → operation-context-CKBoA4Qy.js} +3 -3
- package/dist/operation-context-CKBoA4Qy.js.map +1 -0
- package/dist/{operation-context-n4_obUwq.cjs → operation-context-D6LDf4W_.cjs} +3 -1
- package/dist/operation-context-D6LDf4W_.cjs.map +1 -0
- package/dist/register.cjs +3 -1
- package/dist/register.cjs.map +1 -1
- package/dist/register.js +2 -2
- package/dist/register.js.map +1 -1
- package/dist/semantic-helpers.cjs +1 -1
- package/dist/semantic-helpers.js +1 -1
- package/dist/{stable-hash-Cg5cT34Q.js → stable-hash-ChFBIhNt.js} +3 -3
- package/dist/stable-hash-ChFBIhNt.js.map +1 -0
- package/dist/{stable-hash-BNTMrmdB.cjs → stable-hash-brKISGf1.cjs} +4 -2
- package/dist/stable-hash-brKISGf1.cjs.map +1 -0
- package/dist/trace-context-Cijqoi6e.d.cts.map +1 -1
- package/dist/trace-context-Cijqoi6e.d.ts.map +1 -1
- package/dist/trace-helpers.cjs +1 -1
- package/dist/trace-helpers.js +1 -1
- package/dist/{track-wc0HafS_.js → track-COUuU48p.js} +5 -5
- package/dist/track-COUuU48p.js.map +1 -0
- package/dist/{track-D59FfpL0.cjs → track-Cb3Q4QmS.cjs} +4 -2
- package/dist/track-Cb3Q4QmS.cjs.map +1 -0
- package/dist/validate.cjs +1 -1
- package/dist/validate.js +1 -1
- package/dist/webhook.cjs +1 -1
- package/dist/webhook.js +1 -1
- package/dist/workflow-distributed.cjs +1 -1
- package/dist/workflow-distributed.js +1 -1
- package/dist/workflow.cjs +3 -1
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts.map +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +3 -3
- package/dist/workflow.js.map +1 -1
- package/dist/yaml-config.cjs +233 -4
- package/dist/yaml-config.cjs.map +1 -0
- package/dist/yaml-config.d.cts.map +1 -1
- package/dist/yaml-config.d.ts.map +1 -1
- package/dist/yaml-config.js +8 -7
- package/dist/yaml-config.js.map +1 -1
- package/package.json +1 -2
- package/dist/functional-DtI0u4vx.js.map +0 -1
- package/dist/functional-zpzNLhky.cjs.map +0 -1
- package/dist/logger-thMPLpOG.cjs +0 -487
- package/dist/logger-thMPLpOG.cjs.map +0 -1
- package/dist/node-require-DF5QBX6z.cjs.map +0 -1
- package/dist/node-require-Db1oDpLj.js.map +0 -1
- package/dist/operation-context-C-2hmmtP.js.map +0 -1
- package/dist/operation-context-n4_obUwq.cjs.map +0 -1
- package/dist/stable-hash-BNTMrmdB.cjs.map +0 -1
- package/dist/stable-hash-Cg5cT34Q.js.map +0 -1
- package/dist/track-D59FfpL0.cjs.map +0 -1
- package/dist/track-wc0HafS_.js.map +0 -1
- package/dist/yaml-config-Ck2uB0Dp.cjs +0 -273
- package/dist/yaml-config-Ck2uB0Dp.cjs.map +0 -1
- package/src/attribute-redacting-processor.test.ts +0 -763
- package/src/attribute-redacting-processor.ts +0 -621
- package/src/attributes/attachers.ts +0 -161
- package/src/attributes/builders.ts +0 -529
- package/src/attributes/domains.ts +0 -42
- package/src/attributes/index.ts +0 -81
- package/src/attributes/registry.ts +0 -323
- package/src/attributes/types.ts +0 -211
- package/src/attributes/utils.ts +0 -64
- package/src/attributes/validators.ts +0 -266
- package/src/attributes.test.ts +0 -292
- package/src/auto.ts +0 -67
- package/src/autotel-logger.test.ts +0 -548
- package/src/autotel-logger.ts +0 -364
- package/src/baggage-span-processor.test.ts +0 -202
- package/src/baggage-span-processor.ts +0 -100
- package/src/business-baggage.test.ts +0 -500
- package/src/business-baggage.ts +0 -669
- package/src/circuit-breaker.test.ts +0 -341
- package/src/circuit-breaker.ts +0 -184
- package/src/config.test.ts +0 -94
- package/src/config.ts +0 -172
- package/src/correlated-events.test.ts +0 -151
- package/src/correlated-events.ts +0 -47
- package/src/correlation-id.test.ts +0 -163
- package/src/correlation-id.ts +0 -206
- package/src/db.test.ts +0 -252
- package/src/db.ts +0 -447
- package/src/decorators.test.ts +0 -153
- package/src/decorators.ts +0 -188
- package/src/define-event.test.ts +0 -41
- package/src/define-event.ts +0 -58
- package/src/devtools.ts +0 -60
- package/src/drain-pipeline.test.ts +0 -68
- package/src/drain-pipeline.ts +0 -199
- package/src/drain-toolkit.test.ts +0 -113
- package/src/drain-toolkit.ts +0 -129
- package/src/enricher-toolkit.test.ts +0 -67
- package/src/enricher-toolkit.ts +0 -79
- package/src/enrichers.test.ts +0 -150
- package/src/enrichers.ts +0 -145
- package/src/env-config.test.ts +0 -323
- package/src/env-config.ts +0 -309
- package/src/error-catalog.test.ts +0 -133
- package/src/error-catalog.ts +0 -262
- package/src/event-queue.test.ts +0 -864
- package/src/event-queue.ts +0 -699
- package/src/event-subscriber.ts +0 -262
- package/src/event-testing.ts +0 -197
- package/src/event.test.ts +0 -1104
- package/src/event.ts +0 -988
- package/src/events-config.ts +0 -235
- package/src/exporters.ts +0 -165
- package/src/filtering-span-processor.test.ts +0 -281
- package/src/filtering-span-processor.ts +0 -111
- package/src/flatten-attributes.test.ts +0 -76
- package/src/flatten-attributes.ts +0 -80
- package/src/functional.strict-types.typecheck.ts +0 -53
- package/src/functional.test.ts +0 -1464
- package/src/functional.ts +0 -2539
- package/src/functional.types.test.ts +0 -135
- package/src/hook.mjs +0 -15
- package/src/http.test.ts +0 -485
- package/src/http.ts +0 -424
- package/src/index.ts +0 -433
- package/src/init-auto-redactor.test.ts +0 -53
- package/src/init-redactor.test.ts +0 -8
- package/src/init.customization.test.ts +0 -665
- package/src/init.integrations.test.ts +0 -399
- package/src/init.openllmetry.test.ts +0 -194
- package/src/init.protocol.test.ts +0 -215
- package/src/init.ts +0 -2439
- package/src/instrumentation.test.ts +0 -108
- package/src/instrumentation.ts +0 -319
- package/src/logger.test.ts +0 -125
- package/src/logger.ts +0 -341
- package/src/messaging-adapters.test.ts +0 -595
- package/src/messaging-adapters.ts +0 -583
- package/src/messaging-testing.test.ts +0 -573
- package/src/messaging-testing.ts +0 -935
- package/src/messaging.test.ts +0 -1646
- package/src/messaging.ts +0 -2245
- package/src/metric-helpers.ts +0 -47
- package/src/metric-testing.ts +0 -197
- package/src/metric.ts +0 -446
- package/src/metrics.test.ts +0 -241
- package/src/node-require.ts +0 -123
- package/src/operation-context.ts +0 -93
- package/src/parse-error.test.ts +0 -73
- package/src/parse-error.ts +0 -112
- package/src/posthog-logs.test.ts +0 -115
- package/src/posthog-logs.ts +0 -77
- package/src/pretty-console-exporter.test.ts +0 -545
- package/src/pretty-console-exporter.ts +0 -413
- package/src/pretty-log-formatter.test.ts +0 -123
- package/src/pretty-log-formatter.ts +0 -210
- package/src/processors/canonical-log-line-processor.test.ts +0 -523
- package/src/processors/canonical-log-line-processor.ts +0 -396
- package/src/processors.ts +0 -152
- package/src/rate-limiter.test.ts +0 -199
- package/src/rate-limiter.ts +0 -98
- package/src/redact-values.test.ts +0 -90
- package/src/redact-values.ts +0 -34
- package/src/register.ts +0 -37
- package/src/request-logger.test.ts +0 -545
- package/src/request-logger.ts +0 -342
- package/src/sampling.test.ts +0 -1060
- package/src/sampling.ts +0 -737
- package/src/security-schema.test.ts +0 -45
- package/src/security-schema.ts +0 -107
- package/src/semantic-conventions.ts +0 -15
- package/src/semantic-helpers.test.ts +0 -226
- package/src/semantic-helpers.ts +0 -438
- package/src/shutdown.test.ts +0 -364
- package/src/shutdown.ts +0 -246
- package/src/span-name-normalizer.test.ts +0 -377
- package/src/span-name-normalizer.ts +0 -213
- package/src/stable-hash.ts +0 -27
- package/src/structured-error.test.ts +0 -191
- package/src/structured-error.ts +0 -157
- package/src/stub.integration.test.ts +0 -361
- package/src/tail-sampling-processor.test.ts +0 -230
- package/src/tail-sampling-processor.ts +0 -55
- package/src/test-span-collector.test.ts +0 -234
- package/src/test-span-collector.ts +0 -150
- package/src/testing.ts +0 -705
- package/src/trace-context.test.ts +0 -73
- package/src/trace-context.ts +0 -567
- package/src/trace-helpers.new.test.ts +0 -278
- package/src/trace-helpers.test.ts +0 -290
- package/src/trace-helpers.ts +0 -710
- package/src/trace-hybrid.test.ts +0 -42
- package/src/trace-hybrid.ts +0 -37
- package/src/tracer-provider.test.ts +0 -183
- package/src/tracer-provider.ts +0 -266
- package/src/track.test.ts +0 -154
- package/src/track.ts +0 -216
- package/src/validate.test.ts +0 -287
- package/src/validate.ts +0 -307
- package/src/validation-attributes.ts +0 -43
- package/src/validation.test.ts +0 -330
- package/src/validation.ts +0 -246
- package/src/variable-name-inference.test.ts +0 -178
- package/src/variable-name-inference.ts +0 -242
- package/src/webhook.test.ts +0 -649
- package/src/webhook.ts +0 -637
- package/src/workflow-distributed.test.ts +0 -786
- package/src/workflow-distributed.ts +0 -916
- package/src/workflow.async-safety.integration.test.ts +0 -345
- package/src/workflow.test.ts +0 -647
- package/src/workflow.ts +0 -810
- package/src/yaml-config.test.ts +0 -373
- package/src/yaml-config.ts +0 -351
package/src/request-logger.ts
DELETED
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
-
import { trace as otelTrace } from '@opentelemetry/api';
|
|
3
|
-
import type { TraceContext } from './trace-context';
|
|
4
|
-
import { createTraceContext } from './trace-context';
|
|
5
|
-
import { recordStructuredError } from './structured-error';
|
|
6
|
-
import { flattenToAttributes } from './flatten-attributes';
|
|
7
|
-
import { emitCorrelatedEvent } from './correlated-events';
|
|
8
|
-
|
|
9
|
-
const POST_EMIT_FORK_HINT =
|
|
10
|
-
"For intentional background work tied to this request, use log.fork('label', fn) when available.";
|
|
11
|
-
|
|
12
|
-
function warnPostEmit(method: string, detail: string): void {
|
|
13
|
-
console.warn(
|
|
14
|
-
`[autotel] ${method} called after the wide event was emitted — ${detail} This data will not appear in observability. ${POST_EMIT_FORK_HINT}`,
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function mergeInto(
|
|
19
|
-
target: Record<string, unknown>,
|
|
20
|
-
source: Record<string, unknown>,
|
|
21
|
-
): void {
|
|
22
|
-
for (const key in source) {
|
|
23
|
-
const sourceVal = source[key];
|
|
24
|
-
if (sourceVal === undefined) continue;
|
|
25
|
-
const targetVal = target[key];
|
|
26
|
-
if (
|
|
27
|
-
sourceVal !== null &&
|
|
28
|
-
typeof sourceVal === 'object' &&
|
|
29
|
-
!Array.isArray(sourceVal) &&
|
|
30
|
-
targetVal !== null &&
|
|
31
|
-
typeof targetVal === 'object' &&
|
|
32
|
-
!Array.isArray(targetVal)
|
|
33
|
-
) {
|
|
34
|
-
mergeInto(
|
|
35
|
-
targetVal as Record<string, unknown>,
|
|
36
|
-
sourceVal as Record<string, unknown>,
|
|
37
|
-
);
|
|
38
|
-
} else if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {
|
|
39
|
-
target[key] = [...targetVal, ...sourceVal];
|
|
40
|
-
} else {
|
|
41
|
-
target[key] = sourceVal;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const requestContextStore = new AsyncLocalStorage<TraceContext>();
|
|
47
|
-
|
|
48
|
-
export function runWithRequestContext<T>(ctx: TraceContext, fn: () => T): T {
|
|
49
|
-
return requestContextStore.run(ctx, fn);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface RequestLogger {
|
|
53
|
-
set(fields: Record<string, unknown>): void;
|
|
54
|
-
info(message: string, fields?: Record<string, unknown>): void;
|
|
55
|
-
warn(message: string, fields?: Record<string, unknown>): void;
|
|
56
|
-
error(error: Error | string, fields?: Record<string, unknown>): void;
|
|
57
|
-
getContext(): Record<string, unknown>;
|
|
58
|
-
emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot;
|
|
59
|
-
fork(
|
|
60
|
-
label: string,
|
|
61
|
-
fn: () => void | Promise<void>,
|
|
62
|
-
options?: ForkOptions,
|
|
63
|
-
): void;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface RequestLogSnapshot {
|
|
67
|
-
timestamp: string;
|
|
68
|
-
traceId: string;
|
|
69
|
-
spanId: string;
|
|
70
|
-
correlationId: string;
|
|
71
|
-
context: Record<string, unknown>;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface RequestLoggerOptions {
|
|
75
|
-
/** Callback invoked by emitNow() for manual fan-out. */
|
|
76
|
-
onEmit?: (snapshot: RequestLogSnapshot) => void | Promise<void>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Optional lifecycle hooks for adapters that need to track child loggers
|
|
81
|
-
* spawned by `log.fork()` (e.g. active logger maps in framework integrations).
|
|
82
|
-
*/
|
|
83
|
-
export interface ForkLifecycle {
|
|
84
|
-
/** Called after the child logger is created, before `fn` runs. */
|
|
85
|
-
onChildEnter?: (child: RequestLogger) => void;
|
|
86
|
-
/** Called after the child has finished (emit + drain), success or failure. */
|
|
87
|
-
onChildExit?: (child: RequestLogger) => void;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface ForkOptions {
|
|
91
|
-
lifecycle?: ForkLifecycle;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function resolveContext(ctx?: TraceContext): TraceContext {
|
|
95
|
-
if (ctx) return ctx;
|
|
96
|
-
|
|
97
|
-
const stored = requestContextStore.getStore();
|
|
98
|
-
if (stored) return stored;
|
|
99
|
-
|
|
100
|
-
const span = otelTrace.getActiveSpan();
|
|
101
|
-
if (!span) {
|
|
102
|
-
throw new Error(
|
|
103
|
-
'[autotel] getRequestLogger() requires an active span or runWithRequestContext(). Wrap your handler with trace() or use runWithRequestContext().',
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
return createTraceContext(span);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function getRequestLogger(
|
|
110
|
-
ctx?: TraceContext,
|
|
111
|
-
options?: RequestLoggerOptions,
|
|
112
|
-
): RequestLogger {
|
|
113
|
-
const activeContext = resolveContext(ctx);
|
|
114
|
-
let contextState: Record<string, unknown> = {};
|
|
115
|
-
let emitted = false;
|
|
116
|
-
let lastSnapshot: RequestLogSnapshot | null = null;
|
|
117
|
-
|
|
118
|
-
const addLogEvent = (
|
|
119
|
-
level: 'info' | 'warn' | 'error',
|
|
120
|
-
message: string,
|
|
121
|
-
fields?: Record<string, unknown>,
|
|
122
|
-
) => {
|
|
123
|
-
const attrs = fields ? flattenToAttributes(fields) : undefined;
|
|
124
|
-
emitCorrelatedEvent(activeContext, `log.${level}`, {
|
|
125
|
-
message,
|
|
126
|
-
...(attrs ?? {}),
|
|
127
|
-
});
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const sealCheck = (method: string, keys: string[]): void => {
|
|
131
|
-
if (emitted) {
|
|
132
|
-
warnPostEmit(
|
|
133
|
-
method,
|
|
134
|
-
`Keys dropped: ${keys.length ? keys.join(', ') : '(empty)'}.`,
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
set(fields: Record<string, unknown>) {
|
|
141
|
-
sealCheck('log.set()', Object.keys(fields));
|
|
142
|
-
if (emitted) return;
|
|
143
|
-
mergeInto(contextState, fields);
|
|
144
|
-
activeContext.setAttributes(flattenToAttributes(fields));
|
|
145
|
-
},
|
|
146
|
-
|
|
147
|
-
info(message: string, fields?: Record<string, unknown>) {
|
|
148
|
-
const keys = fields
|
|
149
|
-
? ['message', ...Object.keys(fields).filter((k) => k !== 'requestLogs')]
|
|
150
|
-
: ['message'];
|
|
151
|
-
sealCheck('log.info()', keys);
|
|
152
|
-
if (emitted) return;
|
|
153
|
-
addLogEvent('info', message, fields);
|
|
154
|
-
if (fields) {
|
|
155
|
-
mergeInto(contextState, fields);
|
|
156
|
-
activeContext.setAttributes(flattenToAttributes(fields));
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
|
|
160
|
-
warn(message: string, fields?: Record<string, unknown>) {
|
|
161
|
-
const keys = fields
|
|
162
|
-
? ['message', ...Object.keys(fields).filter((k) => k !== 'requestLogs')]
|
|
163
|
-
: ['message'];
|
|
164
|
-
sealCheck('log.warn()', keys);
|
|
165
|
-
if (emitted) return;
|
|
166
|
-
addLogEvent('warn', message, fields);
|
|
167
|
-
activeContext.setAttribute('autotel.log.level', 'warn');
|
|
168
|
-
if (fields) {
|
|
169
|
-
mergeInto(contextState, fields);
|
|
170
|
-
activeContext.setAttributes(flattenToAttributes(fields));
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
error(error: Error | string, fields?: Record<string, unknown>) {
|
|
175
|
-
const keys = fields ? [...Object.keys(fields), 'error'] : ['error'];
|
|
176
|
-
sealCheck('log.error()', keys);
|
|
177
|
-
if (emitted) return;
|
|
178
|
-
const err = typeof error === 'string' ? new Error(error) : error;
|
|
179
|
-
recordStructuredError(activeContext, err);
|
|
180
|
-
addLogEvent('error', err.message, fields);
|
|
181
|
-
|
|
182
|
-
if (fields) {
|
|
183
|
-
mergeInto(contextState, fields);
|
|
184
|
-
activeContext.setAttributes(flattenToAttributes(fields));
|
|
185
|
-
}
|
|
186
|
-
activeContext.setAttribute('autotel.log.level', 'error');
|
|
187
|
-
},
|
|
188
|
-
|
|
189
|
-
getContext() {
|
|
190
|
-
return { ...contextState };
|
|
191
|
-
},
|
|
192
|
-
|
|
193
|
-
emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot {
|
|
194
|
-
if (emitted) {
|
|
195
|
-
warnPostEmit('log.emitNow()', 'Ignoring duplicate emit.');
|
|
196
|
-
return lastSnapshot as RequestLogSnapshot;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const mergedContext = {
|
|
200
|
-
...contextState,
|
|
201
|
-
...(overrides ?? {}),
|
|
202
|
-
};
|
|
203
|
-
const flattened = flattenToAttributes(mergedContext);
|
|
204
|
-
activeContext.setAttributes(flattened);
|
|
205
|
-
|
|
206
|
-
const snapshot: RequestLogSnapshot = {
|
|
207
|
-
timestamp: new Date().toISOString(),
|
|
208
|
-
traceId: activeContext.traceId,
|
|
209
|
-
spanId: activeContext.spanId,
|
|
210
|
-
correlationId: activeContext.correlationId,
|
|
211
|
-
context: mergedContext,
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
emitCorrelatedEvent(activeContext, 'log.emit.manual', {
|
|
215
|
-
...flattened,
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
if (options?.onEmit) {
|
|
219
|
-
Promise.resolve(options.onEmit(snapshot)).catch((error) => {
|
|
220
|
-
console.warn('[autotel] request logger onEmit failed:', error);
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
emitted = true;
|
|
225
|
-
lastSnapshot = snapshot;
|
|
226
|
-
return snapshot;
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
fork(
|
|
230
|
-
label: string,
|
|
231
|
-
fn: () => void | Promise<void>,
|
|
232
|
-
forkOptions?: ForkOptions,
|
|
233
|
-
): void {
|
|
234
|
-
const parentRequestId = activeContext.correlationId;
|
|
235
|
-
if (typeof parentRequestId !== 'string' || parentRequestId.length === 0) {
|
|
236
|
-
throw new Error(
|
|
237
|
-
'[autotel] log.fork() requires the parent logger to have a correlationId. ' +
|
|
238
|
-
'Ensure the request was created by autotel middleware.',
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const tracer = otelTrace.getTracer('autotel.request-logger');
|
|
243
|
-
const lifecycle = forkOptions?.lifecycle;
|
|
244
|
-
void tracer.startActiveSpan(`request.fork:${label}`, (childSpan) => {
|
|
245
|
-
const childContext: TraceContext = {
|
|
246
|
-
...createTraceContext(childSpan),
|
|
247
|
-
correlationId: crypto.randomUUID(),
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
requestContextStore.run(childContext, () => {
|
|
251
|
-
const childLog = getRequestLogger(childContext);
|
|
252
|
-
childLog.set({
|
|
253
|
-
operation: label,
|
|
254
|
-
_parentCorrelationId: parentRequestId,
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
lifecycle?.onChildEnter?.(childLog);
|
|
258
|
-
|
|
259
|
-
void Promise.resolve()
|
|
260
|
-
.then(() => fn())
|
|
261
|
-
.then(() => {
|
|
262
|
-
childLog.emitNow();
|
|
263
|
-
})
|
|
264
|
-
.catch((err: unknown) => {
|
|
265
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
266
|
-
childLog.error(error);
|
|
267
|
-
childLog.emitNow();
|
|
268
|
-
})
|
|
269
|
-
.finally(() => {
|
|
270
|
-
try {
|
|
271
|
-
lifecycle?.onChildExit?.(childLog);
|
|
272
|
-
} catch (hookError) {
|
|
273
|
-
console.warn(
|
|
274
|
-
'[autotel] fork onChildExit hook threw:',
|
|
275
|
-
hookError,
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
childSpan.end();
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
},
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Returns `true` when a request-logger context can be resolved without throwing —
|
|
288
|
-
* i.e. an explicit `ctx` was provided, a `runWithRequestContext()` scope is active,
|
|
289
|
-
* or there is an active OpenTelemetry span.
|
|
290
|
-
*
|
|
291
|
-
* Use this to branch on observability availability instead of wrapping
|
|
292
|
-
* {@link getRequestLogger} in try/catch.
|
|
293
|
-
*/
|
|
294
|
-
export function hasRequestContext(ctx?: TraceContext): boolean {
|
|
295
|
-
if (ctx) return true;
|
|
296
|
-
if (requestContextStore.getStore()) return true;
|
|
297
|
-
return otelTrace.getActiveSpan() != null;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Like {@link getRequestLogger}, but returns `null` instead of throwing when no
|
|
302
|
-
* request context is available. Intended for best-effort instrumentation where a
|
|
303
|
-
* missing telemetry context must never crash business logic.
|
|
304
|
-
*/
|
|
305
|
-
export function getRequestLoggerSafe(
|
|
306
|
-
ctx?: TraceContext,
|
|
307
|
-
options?: RequestLoggerOptions,
|
|
308
|
-
): RequestLogger | null {
|
|
309
|
-
if (!hasRequestContext(ctx)) return null;
|
|
310
|
-
return getRequestLogger(ctx, options);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* A no-op {@link RequestLogger} whose methods do nothing. Used as a fallback by
|
|
315
|
-
* best-effort instrumentation so wrapped handlers can run un-instrumented without
|
|
316
|
-
* branching on logger presence.
|
|
317
|
-
*/
|
|
318
|
-
export function createNoopRequestLogger(): RequestLogger {
|
|
319
|
-
const snapshot = (): RequestLogSnapshot => ({
|
|
320
|
-
timestamp: new Date().toISOString(),
|
|
321
|
-
traceId: '',
|
|
322
|
-
spanId: '',
|
|
323
|
-
correlationId: '',
|
|
324
|
-
context: {},
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
return {
|
|
328
|
-
set() {},
|
|
329
|
-
info() {},
|
|
330
|
-
warn() {},
|
|
331
|
-
error() {},
|
|
332
|
-
getContext() {
|
|
333
|
-
return {};
|
|
334
|
-
},
|
|
335
|
-
emitNow() {
|
|
336
|
-
return snapshot();
|
|
337
|
-
},
|
|
338
|
-
fork(_label, fn) {
|
|
339
|
-
void Promise.resolve().then(() => fn());
|
|
340
|
-
},
|
|
341
|
-
};
|
|
342
|
-
}
|