autotel 2.22.0 → 2.23.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 +112 -6
- package/dist/auto.cjs +3 -3
- package/dist/auto.js +2 -2
- package/dist/{chunk-EWH2542B.js → chunk-3AMR5XLZ.js} +3 -3
- package/dist/{chunk-EWH2542B.js.map → chunk-3AMR5XLZ.js.map} +1 -1
- package/dist/chunk-3QXBFGKP.js +344 -0
- package/dist/chunk-3QXBFGKP.js.map +1 -0
- package/dist/{chunk-VQFF2WMP.cjs → chunk-3ZFDJJWZ.cjs} +37 -29
- package/dist/chunk-3ZFDJJWZ.cjs.map +1 -0
- package/dist/{chunk-CQC6RVLR.cjs → chunk-4RZ4JUBY.cjs} +5 -5
- package/dist/{chunk-CQC6RVLR.cjs.map → chunk-4RZ4JUBY.cjs.map} +1 -1
- package/dist/{chunk-PAVYKPCQ.js → chunk-5XUEHX7J.js} +3 -3
- package/dist/{chunk-PAVYKPCQ.js.map → chunk-5XUEHX7J.js.map} +1 -1
- package/dist/chunk-6S5RUKU3.cjs +347 -0
- package/dist/chunk-6S5RUKU3.cjs.map +1 -0
- package/dist/{chunk-BS757SL2.js → chunk-724XLWR3.js} +9 -4
- package/dist/chunk-724XLWR3.js.map +1 -0
- package/dist/chunk-7EQ4G4SI.cjs +146 -0
- package/dist/chunk-7EQ4G4SI.cjs.map +1 -0
- package/dist/{chunk-CQP5SQT4.cjs → chunk-AXFWWJF3.cjs} +7 -7
- package/dist/{chunk-CQP5SQT4.cjs.map → chunk-AXFWWJF3.cjs.map} +1 -1
- package/dist/{chunk-7NH625MS.cjs → chunk-BSZP4URK.cjs} +5 -5
- package/dist/{chunk-7NH625MS.cjs.map → chunk-BSZP4URK.cjs.map} +1 -1
- package/dist/{chunk-GZFH6P5U.js → chunk-GY4CRZSV.js} +14 -6
- package/dist/chunk-GY4CRZSV.js.map +1 -0
- package/dist/{chunk-QKUGUDXJ.cjs → chunk-HSEIUH7F.cjs} +10 -5
- package/dist/chunk-HSEIUH7F.cjs.map +1 -0
- package/dist/{chunk-DTW3WB7Z.js → chunk-IPKXURBW.js} +3 -3
- package/dist/{chunk-DTW3WB7Z.js.map → chunk-IPKXURBW.js.map} +1 -1
- package/dist/chunk-J7VGRIAJ.js +64 -0
- package/dist/chunk-J7VGRIAJ.js.map +1 -0
- package/dist/chunk-KFOHQK7X.js +144 -0
- package/dist/chunk-KFOHQK7X.js.map +1 -0
- package/dist/{chunk-4UYR46UP.cjs → chunk-MSUHW2I4.cjs} +13 -13
- package/dist/{chunk-4UYR46UP.cjs.map → chunk-MSUHW2I4.cjs.map} +1 -1
- package/dist/chunk-T4B5LB6E.cjs +66 -0
- package/dist/chunk-T4B5LB6E.cjs.map +1 -0
- package/dist/{chunk-QHT4MUED.js → chunk-WCIIFRGL.js} +3 -3
- package/dist/{chunk-QHT4MUED.js.map → chunk-WCIIFRGL.js.map} +1 -1
- package/dist/decorators.cjs +3 -3
- package/dist/decorators.js +3 -3
- package/dist/drain-pipeline.cjs +13 -0
- package/dist/drain-pipeline.cjs.map +1 -0
- package/dist/drain-pipeline.d.cts +37 -0
- package/dist/drain-pipeline.d.ts +37 -0
- package/dist/drain-pipeline.js +4 -0
- package/dist/drain-pipeline.js.map +1 -0
- package/dist/event.cjs +6 -6
- package/dist/event.js +3 -3
- package/dist/functional.cjs +10 -10
- package/dist/functional.js +3 -3
- package/dist/index.cjs +256 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +72 -3
- package/dist/index.d.ts +72 -3
- package/dist/index.js +210 -11
- package/dist/index.js.map +1 -1
- package/dist/{init-BMiXSJNM.d.cts → init-BC5aN8bh.d.cts} +18 -0
- package/dist/{init-ByRbNTRo.d.ts → init-_FG4IbhF.d.ts} +18 -0
- package/dist/instrumentation.cjs +9 -9
- package/dist/instrumentation.js +2 -2
- package/dist/messaging.cjs +7 -7
- package/dist/messaging.js +4 -4
- package/dist/parse-error.cjs +13 -0
- package/dist/parse-error.cjs.map +1 -0
- package/dist/parse-error.d.cts +13 -0
- package/dist/parse-error.d.ts +13 -0
- package/dist/parse-error.js +4 -0
- package/dist/parse-error.js.map +1 -0
- package/dist/processors.cjs +2 -2
- package/dist/processors.d.cts +40 -4
- package/dist/processors.d.ts +40 -4
- package/dist/processors.js +1 -1
- package/dist/semantic-helpers.cjs +8 -8
- package/dist/semantic-helpers.js +4 -4
- package/dist/webhook.cjs +4 -4
- package/dist/webhook.js +3 -3
- package/dist/workflow-distributed.cjs +5 -5
- package/dist/workflow-distributed.js +3 -3
- package/dist/workflow.cjs +8 -8
- package/dist/workflow.js +4 -4
- package/dist/yaml-config.d.cts +2 -1
- package/dist/yaml-config.d.ts +2 -1
- package/package.json +11 -1
- package/src/drain-pipeline.test.ts +68 -0
- package/src/drain-pipeline.ts +199 -0
- package/src/flatten-attributes.test.ts +76 -0
- package/src/flatten-attributes.ts +80 -0
- package/src/functional.test.ts +63 -0
- package/src/functional.ts +11 -3
- package/src/index.ts +33 -0
- package/src/init.ts +22 -0
- package/src/parse-error.test.ts +73 -0
- package/src/parse-error.ts +112 -0
- package/src/pretty-log-formatter.test.ts +123 -0
- package/src/pretty-log-formatter.ts +210 -0
- package/src/processors/canonical-log-line-processor.test.ts +81 -25
- package/src/processors/canonical-log-line-processor.ts +130 -42
- package/src/request-logger.test.ts +124 -0
- package/src/request-logger.ts +140 -0
- package/src/structured-error.test.ts +76 -0
- package/src/structured-error.ts +86 -0
- package/dist/chunk-2RQDNGV3.js +0 -126
- package/dist/chunk-2RQDNGV3.js.map +0 -1
- package/dist/chunk-BS757SL2.js.map +0 -1
- package/dist/chunk-GZFH6P5U.js.map +0 -1
- package/dist/chunk-ONK2Y22L.cjs +0 -128
- package/dist/chunk-ONK2Y22L.cjs.map +0 -1
- package/dist/chunk-QKUGUDXJ.cjs.map +0 -1
- package/dist/chunk-VQFF2WMP.cjs.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AutotelConfig, i as init } from './init-
|
|
1
|
+
export { A as AutotelConfig, i as init } from './init-BC5aN8bh.cjs';
|
|
2
2
|
import { Span, Context } from '@opentelemetry/api';
|
|
3
3
|
export { Context, ROOT_CONTEXT, Span, SpanContext, SpanKind, Link as SpanLink, SpanStatusCode, TextMapGetter, TextMapSetter, Tracer, context, trace as otelTrace, propagation } from '@opentelemetry/api';
|
|
4
4
|
import { SpanProcessor, ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
@@ -9,6 +9,10 @@ export { InstrumentOptions, SpanOptions, WithBaggageOptions, WithNewContextOptio
|
|
|
9
9
|
import { EventSubscriber, EventAttributes, AutotelEventContext } from './event-subscriber.cjs';
|
|
10
10
|
export { FunnelStatus, OutcomeStatus } from './event-subscriber.cjs';
|
|
11
11
|
export { CORRELATION_ID_BAGGAGE_KEY, generateCorrelationId, getCorrelationId, getOrCreateCorrelationId, runWithCorrelationId, setCorrelationId, setCorrelationIdInBaggage } from './correlation-id.cjs';
|
|
12
|
+
import { T as TraceContext, A as AttributeValue } from './trace-context-t5X1AP-e.cjs';
|
|
13
|
+
export { d as defineBaggageSchema } from './trace-context-t5X1AP-e.cjs';
|
|
14
|
+
export { ParsedError, parseError } from './parse-error.cjs';
|
|
15
|
+
export { DrainPipelineOptions, PipelineDrainFn, createDrainPipeline } from './drain-pipeline.cjs';
|
|
12
16
|
export { AdaptiveSampler, AlwaysSampler, NeverSampler, RandomSampler, Sampler, SamplingContext, UserIdSampler, createLinkFromHeaders, extractLinksFromBatch } from './sampling.cjs';
|
|
13
17
|
export { Event, EventsOptions, getEvents, resetEvents } from './event.cjs';
|
|
14
18
|
export { Metric, MetricsOptions, getMetrics, resetMetrics } from './metric.cjs';
|
|
@@ -18,7 +22,6 @@ export { getAutotelTracer, getAutotelTracerProvider, setAutotelTracerProvider }
|
|
|
18
22
|
export { DBConfig, HTTPConfig, LLMConfig, MessagingConfig, traceDB, traceHTTP, traceLLM, traceMessaging } from './semantic-helpers.cjs';
|
|
19
23
|
export { HTTPAttributes, ServiceAttributes, URLAttributes, httpRequestHeaderAttribute, httpResponseHeaderAttribute } from './semantic-conventions.cjs';
|
|
20
24
|
export { p as AttributeGuardrails, A as AttributePolicy, J as ClientAttrs, C as CloudAttrs, Q as CodeAttrs, z as ContainerAttrs, t as DBAttrs, L as DeploymentAttrs, D as DeviceAttrs, E as ErrorAttrs, V as ExceptionAttrs, B as FaaSAttrs, F as FeatureFlagAttrs, G as GenAIAttrs, I as GraphQLAttrs, q as HTTPClientAttrs, H as HTTPServerAttrs, K as K8sAttrs, M as MessagingAttrs, N as NetworkAttrs, O as OTelAttrs, P as PeerAttrs, y as ProcessAttrs, R as RPCAttrs, w as ServerAddressAttrs, u as ServiceAttrs, S as SessionAttrs, W as TLSAttrs, T as ThreadAttrs, x as URLAttrs, U as UserAttrs, a as attrs, n as autoRedactPII, e as dbClient, d as httpClient, h as httpServer, i as identify, j as mergeAttrs, m as mergeServiceResource, r as request, k as safeSetAttributes, c as setDevice, f as setError, g as setException, b as setSession, s as setUser, v as validateAttribute } from './utils-DuNJfXSH.cjs';
|
|
21
|
-
export { T as TraceContext, d as defineBaggageSchema } from './trace-context-t5X1AP-e.cjs';
|
|
22
25
|
export { ConsumerConfig, ConsumerContext, LagMetricsConfig, MessagingOperation, MessagingSystem, ProducerConfig, ProducerContext, traceConsumer, traceProducer } from './messaging.cjs';
|
|
23
26
|
export { BaggageError, BaggageFieldDefinition, BaggageFieldType, BusinessBaggage, BusinessBaggageValues, SafeBaggageOptions, SafeBaggageSchema, createSafeBaggageSchema } from './business-baggage.cjs';
|
|
24
27
|
export { StepConfig, StepContext, StepStatus, WorkflowConfig, WorkflowContext, WorkflowStatus, getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './workflow.cjs';
|
|
@@ -28,6 +31,7 @@ import './logger.cjs';
|
|
|
28
31
|
import 'pino';
|
|
29
32
|
import '@opentelemetry/sdk-metrics';
|
|
30
33
|
import '@opentelemetry/sdk-logs';
|
|
34
|
+
import './processors.cjs';
|
|
31
35
|
import 'node:async_hooks';
|
|
32
36
|
import './event-testing.cjs';
|
|
33
37
|
import './metric-testing.cjs';
|
|
@@ -410,4 +414,69 @@ declare function flush(options?: {
|
|
|
410
414
|
*/
|
|
411
415
|
declare function shutdown(): Promise<void>;
|
|
412
416
|
|
|
413
|
-
|
|
417
|
+
interface RequestLogger {
|
|
418
|
+
set(fields: Record<string, unknown>): void;
|
|
419
|
+
info(message: string, fields?: Record<string, unknown>): void;
|
|
420
|
+
warn(message: string, fields?: Record<string, unknown>): void;
|
|
421
|
+
error(error: Error | string, fields?: Record<string, unknown>): void;
|
|
422
|
+
getContext(): Record<string, unknown>;
|
|
423
|
+
emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot;
|
|
424
|
+
}
|
|
425
|
+
interface RequestLogSnapshot {
|
|
426
|
+
timestamp: string;
|
|
427
|
+
traceId: string;
|
|
428
|
+
spanId: string;
|
|
429
|
+
correlationId: string;
|
|
430
|
+
context: Record<string, unknown>;
|
|
431
|
+
}
|
|
432
|
+
interface RequestLoggerOptions {
|
|
433
|
+
/** Callback invoked by emitNow() for manual fan-out. */
|
|
434
|
+
onEmit?: (snapshot: RequestLogSnapshot) => void | Promise<void>;
|
|
435
|
+
}
|
|
436
|
+
declare function getRequestLogger(ctx?: TraceContext, options?: RequestLoggerOptions): RequestLogger;
|
|
437
|
+
|
|
438
|
+
interface StructuredErrorInput {
|
|
439
|
+
message: string;
|
|
440
|
+
why?: string;
|
|
441
|
+
fix?: string;
|
|
442
|
+
link?: string;
|
|
443
|
+
code?: string | number;
|
|
444
|
+
status?: number;
|
|
445
|
+
cause?: unknown;
|
|
446
|
+
details?: Record<string, unknown>;
|
|
447
|
+
name?: string;
|
|
448
|
+
}
|
|
449
|
+
interface StructuredError extends Error {
|
|
450
|
+
why?: string;
|
|
451
|
+
fix?: string;
|
|
452
|
+
link?: string;
|
|
453
|
+
code?: string | number;
|
|
454
|
+
status?: number;
|
|
455
|
+
details?: Record<string, unknown>;
|
|
456
|
+
}
|
|
457
|
+
declare function createStructuredError(input: StructuredErrorInput): StructuredError;
|
|
458
|
+
declare function getStructuredErrorAttributes(error: Error): Record<string, AttributeValue>;
|
|
459
|
+
declare function recordStructuredError(ctx: Pick<TraceContext, 'recordException' | 'setAttributes' | 'setStatus'>, error: Error): void;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Convert an unknown value to an OTel-compatible AttributeValue.
|
|
463
|
+
* Returns undefined when the value cannot be represented.
|
|
464
|
+
*/
|
|
465
|
+
declare function toAttributeValue(value: unknown): AttributeValue | undefined;
|
|
466
|
+
/**
|
|
467
|
+
* Recursively flatten a nested object into dot-notation OTel attributes.
|
|
468
|
+
* Includes circular reference protection via WeakSet.
|
|
469
|
+
*/
|
|
470
|
+
declare function flattenToAttributes(fields: Record<string, unknown>, prefix?: string): Record<string, AttributeValue>;
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Format milliseconds into a human-readable duration string.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* formatDuration(45) // "45ms"
|
|
477
|
+
* formatDuration(1234) // "1.2s"
|
|
478
|
+
* formatDuration(65000) // "1m 5s"
|
|
479
|
+
*/
|
|
480
|
+
declare function formatDuration(ms: number): string;
|
|
481
|
+
|
|
482
|
+
export { BaggageSpanProcessor, type BaggageSpanProcessorOptions, EventAttributes, EventSubscriber, type OperationContext, type RequestLogSnapshot, type RequestLogger, type RequestLoggerOptions, type StructuredError, type StructuredErrorInput, TraceContext, createStructuredError, flattenToAttributes, flush, formatDuration, getEventQueue, getOperationContext, getRequestLogger, getStructuredErrorAttributes, recordStructuredError, runInOperationContext, shutdown, toAttributeValue, track };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AutotelConfig, i as init } from './init-
|
|
1
|
+
export { A as AutotelConfig, i as init } from './init-_FG4IbhF.js';
|
|
2
2
|
import { Span, Context } from '@opentelemetry/api';
|
|
3
3
|
export { Context, ROOT_CONTEXT, Span, SpanContext, SpanKind, Link as SpanLink, SpanStatusCode, TextMapGetter, TextMapSetter, Tracer, context, trace as otelTrace, propagation } from '@opentelemetry/api';
|
|
4
4
|
import { SpanProcessor, ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
@@ -9,6 +9,10 @@ export { InstrumentOptions, SpanOptions, WithBaggageOptions, WithNewContextOptio
|
|
|
9
9
|
import { EventSubscriber, EventAttributes, AutotelEventContext } from './event-subscriber.js';
|
|
10
10
|
export { FunnelStatus, OutcomeStatus } from './event-subscriber.js';
|
|
11
11
|
export { CORRELATION_ID_BAGGAGE_KEY, generateCorrelationId, getCorrelationId, getOrCreateCorrelationId, runWithCorrelationId, setCorrelationId, setCorrelationIdInBaggage } from './correlation-id.js';
|
|
12
|
+
import { T as TraceContext, A as AttributeValue } from './trace-context-t5X1AP-e.js';
|
|
13
|
+
export { d as defineBaggageSchema } from './trace-context-t5X1AP-e.js';
|
|
14
|
+
export { ParsedError, parseError } from './parse-error.js';
|
|
15
|
+
export { DrainPipelineOptions, PipelineDrainFn, createDrainPipeline } from './drain-pipeline.js';
|
|
12
16
|
export { AdaptiveSampler, AlwaysSampler, NeverSampler, RandomSampler, Sampler, SamplingContext, UserIdSampler, createLinkFromHeaders, extractLinksFromBatch } from './sampling.js';
|
|
13
17
|
export { Event, EventsOptions, getEvents, resetEvents } from './event.js';
|
|
14
18
|
export { Metric, MetricsOptions, getMetrics, resetMetrics } from './metric.js';
|
|
@@ -18,7 +22,6 @@ export { getAutotelTracer, getAutotelTracerProvider, setAutotelTracerProvider }
|
|
|
18
22
|
export { DBConfig, HTTPConfig, LLMConfig, MessagingConfig, traceDB, traceHTTP, traceLLM, traceMessaging } from './semantic-helpers.js';
|
|
19
23
|
export { HTTPAttributes, ServiceAttributes, URLAttributes, httpRequestHeaderAttribute, httpResponseHeaderAttribute } from './semantic-conventions.js';
|
|
20
24
|
export { p as AttributeGuardrails, A as AttributePolicy, J as ClientAttrs, C as CloudAttrs, Q as CodeAttrs, z as ContainerAttrs, t as DBAttrs, L as DeploymentAttrs, D as DeviceAttrs, E as ErrorAttrs, V as ExceptionAttrs, B as FaaSAttrs, F as FeatureFlagAttrs, G as GenAIAttrs, I as GraphQLAttrs, q as HTTPClientAttrs, H as HTTPServerAttrs, K as K8sAttrs, M as MessagingAttrs, N as NetworkAttrs, O as OTelAttrs, P as PeerAttrs, y as ProcessAttrs, R as RPCAttrs, w as ServerAddressAttrs, u as ServiceAttrs, S as SessionAttrs, W as TLSAttrs, T as ThreadAttrs, x as URLAttrs, U as UserAttrs, a as attrs, n as autoRedactPII, e as dbClient, d as httpClient, h as httpServer, i as identify, j as mergeAttrs, m as mergeServiceResource, r as request, k as safeSetAttributes, c as setDevice, f as setError, g as setException, b as setSession, s as setUser, v as validateAttribute } from './utils-D1trOLNm.js';
|
|
21
|
-
export { T as TraceContext, d as defineBaggageSchema } from './trace-context-t5X1AP-e.js';
|
|
22
25
|
export { ConsumerConfig, ConsumerContext, LagMetricsConfig, MessagingOperation, MessagingSystem, ProducerConfig, ProducerContext, traceConsumer, traceProducer } from './messaging.js';
|
|
23
26
|
export { BaggageError, BaggageFieldDefinition, BaggageFieldType, BusinessBaggage, BusinessBaggageValues, SafeBaggageOptions, SafeBaggageSchema, createSafeBaggageSchema } from './business-baggage.js';
|
|
24
27
|
export { StepConfig, StepContext, StepStatus, WorkflowConfig, WorkflowContext, WorkflowStatus, getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './workflow.js';
|
|
@@ -28,6 +31,7 @@ import './logger.js';
|
|
|
28
31
|
import 'pino';
|
|
29
32
|
import '@opentelemetry/sdk-metrics';
|
|
30
33
|
import '@opentelemetry/sdk-logs';
|
|
34
|
+
import './processors.js';
|
|
31
35
|
import 'node:async_hooks';
|
|
32
36
|
import './event-testing.js';
|
|
33
37
|
import './metric-testing.js';
|
|
@@ -410,4 +414,69 @@ declare function flush(options?: {
|
|
|
410
414
|
*/
|
|
411
415
|
declare function shutdown(): Promise<void>;
|
|
412
416
|
|
|
413
|
-
|
|
417
|
+
interface RequestLogger {
|
|
418
|
+
set(fields: Record<string, unknown>): void;
|
|
419
|
+
info(message: string, fields?: Record<string, unknown>): void;
|
|
420
|
+
warn(message: string, fields?: Record<string, unknown>): void;
|
|
421
|
+
error(error: Error | string, fields?: Record<string, unknown>): void;
|
|
422
|
+
getContext(): Record<string, unknown>;
|
|
423
|
+
emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot;
|
|
424
|
+
}
|
|
425
|
+
interface RequestLogSnapshot {
|
|
426
|
+
timestamp: string;
|
|
427
|
+
traceId: string;
|
|
428
|
+
spanId: string;
|
|
429
|
+
correlationId: string;
|
|
430
|
+
context: Record<string, unknown>;
|
|
431
|
+
}
|
|
432
|
+
interface RequestLoggerOptions {
|
|
433
|
+
/** Callback invoked by emitNow() for manual fan-out. */
|
|
434
|
+
onEmit?: (snapshot: RequestLogSnapshot) => void | Promise<void>;
|
|
435
|
+
}
|
|
436
|
+
declare function getRequestLogger(ctx?: TraceContext, options?: RequestLoggerOptions): RequestLogger;
|
|
437
|
+
|
|
438
|
+
interface StructuredErrorInput {
|
|
439
|
+
message: string;
|
|
440
|
+
why?: string;
|
|
441
|
+
fix?: string;
|
|
442
|
+
link?: string;
|
|
443
|
+
code?: string | number;
|
|
444
|
+
status?: number;
|
|
445
|
+
cause?: unknown;
|
|
446
|
+
details?: Record<string, unknown>;
|
|
447
|
+
name?: string;
|
|
448
|
+
}
|
|
449
|
+
interface StructuredError extends Error {
|
|
450
|
+
why?: string;
|
|
451
|
+
fix?: string;
|
|
452
|
+
link?: string;
|
|
453
|
+
code?: string | number;
|
|
454
|
+
status?: number;
|
|
455
|
+
details?: Record<string, unknown>;
|
|
456
|
+
}
|
|
457
|
+
declare function createStructuredError(input: StructuredErrorInput): StructuredError;
|
|
458
|
+
declare function getStructuredErrorAttributes(error: Error): Record<string, AttributeValue>;
|
|
459
|
+
declare function recordStructuredError(ctx: Pick<TraceContext, 'recordException' | 'setAttributes' | 'setStatus'>, error: Error): void;
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Convert an unknown value to an OTel-compatible AttributeValue.
|
|
463
|
+
* Returns undefined when the value cannot be represented.
|
|
464
|
+
*/
|
|
465
|
+
declare function toAttributeValue(value: unknown): AttributeValue | undefined;
|
|
466
|
+
/**
|
|
467
|
+
* Recursively flatten a nested object into dot-notation OTel attributes.
|
|
468
|
+
* Includes circular reference protection via WeakSet.
|
|
469
|
+
*/
|
|
470
|
+
declare function flattenToAttributes(fields: Record<string, unknown>, prefix?: string): Record<string, AttributeValue>;
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Format milliseconds into a human-readable duration string.
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* formatDuration(45) // "45ms"
|
|
477
|
+
* formatDuration(1234) // "1.2s"
|
|
478
|
+
* formatDuration(65000) // "1m 5s"
|
|
479
|
+
*/
|
|
480
|
+
declare function formatDuration(ms: number): string;
|
|
481
|
+
|
|
482
|
+
export { BaggageSpanProcessor, type BaggageSpanProcessorOptions, EventAttributes, EventSubscriber, type OperationContext, type RequestLogSnapshot, type RequestLogger, type RequestLoggerOptions, type StructuredError, type StructuredErrorInput, TraceContext, createStructuredError, flattenToAttributes, flush, formatDuration, getEventQueue, getOperationContext, getRequestLogger, getStructuredErrorAttributes, recordStructuredError, runInOperationContext, shutdown, toAttributeValue, track };
|
package/dist/index.js
CHANGED
|
@@ -1,39 +1,43 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createDrainPipeline } from './chunk-KFOHQK7X.js';
|
|
2
|
+
export { getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './chunk-WCIIFRGL.js';
|
|
2
3
|
export { attrs, autoRedactPII, dbClient, httpClient, httpServer, identify, mergeAttrs, mergeServiceResource, request, safeSetAttributes, setDevice, setError, setException, setSession, setUser, validateAttribute } from './chunk-M4US3P4K.js';
|
|
3
4
|
export { httpRequestHeaderAttribute, httpResponseHeaderAttribute } from './chunk-7552UTQW.js';
|
|
4
5
|
export { HTTPAttributes, ServiceAttributes, URLAttributes } from './chunk-4A53YIAX.js';
|
|
5
|
-
export {
|
|
6
|
+
export { parseError } from './chunk-J7VGRIAJ.js';
|
|
7
|
+
export { traceConsumer, traceProducer } from './chunk-3AMR5XLZ.js';
|
|
6
8
|
export { BusinessBaggage, createSafeBaggageSchema } from './chunk-4IFSYQVX.js';
|
|
7
9
|
import { resetMetrics } from './chunk-7SAWIN74.js';
|
|
8
10
|
export { Metric, getMetrics, resetMetrics } from './chunk-7SAWIN74.js';
|
|
9
11
|
import './chunk-5ZN622AO.js';
|
|
10
12
|
export { createCounter, createHistogram, createObservableGauge, createUpDownCounter, getMeter } from './chunk-TQ5UWA7S.js';
|
|
11
|
-
export { traceDB, traceHTTP, traceLLM, traceMessaging } from './chunk-
|
|
12
|
-
import { getEventQueue, resetEventQueue } from './chunk-
|
|
13
|
-
export { ctx, getEventQueue, instrument, span, trace, track, withBaggage, withNewContext, withTracing } from './chunk-
|
|
13
|
+
export { traceDB, traceHTTP, traceLLM, traceMessaging } from './chunk-IPKXURBW.js';
|
|
14
|
+
import { getEventQueue, resetEventQueue } from './chunk-GY4CRZSV.js';
|
|
15
|
+
export { ctx, getEventQueue, instrument, span, trace, track, withBaggage, withNewContext, withTracing } from './chunk-GY4CRZSV.js';
|
|
16
|
+
import { createTraceContext } from './chunk-SR35DG5A.js';
|
|
14
17
|
export { defineBaggageSchema } from './chunk-SR35DG5A.js';
|
|
15
18
|
export { createDeterministicTraceId, enrichWithTraceContext, finalizeSpan, flattenMetadata, getActiveContext, getActiveSpan, getTraceContext, getTracer, isTracing, resolveTraceUrl, runWithSpan } from './chunk-B3ZHLLMP.js';
|
|
16
|
-
import { resetEvents } from './chunk-
|
|
17
|
-
export { Event, getEvents, resetEvents } from './chunk-
|
|
19
|
+
import { resetEvents } from './chunk-5XUEHX7J.js';
|
|
20
|
+
export { Event, getEvents, resetEvents } from './chunk-5XUEHX7J.js';
|
|
18
21
|
import './chunk-LITNXTTT.js';
|
|
19
22
|
import './chunk-BZHG5IZ4.js';
|
|
20
23
|
export { getOperationContext, runInOperationContext } from './chunk-WD4RP6IV.js';
|
|
21
24
|
export { CORRELATION_ID_BAGGAGE_KEY, generateCorrelationId, getCorrelationId, getOrCreateCorrelationId, runWithCorrelationId, setCorrelationId, setCorrelationIdInBaggage } from './chunk-USSL3D6L.js';
|
|
22
|
-
import { getLogger, getSdk } from './chunk-
|
|
23
|
-
export { BaggageSpanProcessor, init } from './chunk-
|
|
25
|
+
import { getLogger, getSdk } from './chunk-724XLWR3.js';
|
|
26
|
+
export { BaggageSpanProcessor, init } from './chunk-724XLWR3.js';
|
|
24
27
|
import './chunk-YTGF4L2C.js';
|
|
25
28
|
import './chunk-X4RMFFMR.js';
|
|
26
29
|
export { FilteringSpanProcessor } from './chunk-WGWSHJ2N.js';
|
|
27
30
|
export { NORMALIZER_PATTERNS, NORMALIZER_PRESETS, SpanNameNormalizingProcessor } from './chunk-GYR5K654.js';
|
|
28
31
|
export { AttributeRedactingProcessor, REDACTOR_PATTERNS, REDACTOR_PRESETS, createRedactedSpan } from './chunk-SNINLBEE.js';
|
|
29
32
|
import './chunk-6UQRVUN3.js';
|
|
30
|
-
|
|
33
|
+
export { formatDuration } from './chunk-3QXBFGKP.js';
|
|
31
34
|
import './chunk-33WTKH7X.js';
|
|
32
35
|
export { AdaptiveSampler, AlwaysSampler, NeverSampler, RandomSampler, UserIdSampler, createLinkFromHeaders, extractLinksFromBatch } from './chunk-XND7WBVX.js';
|
|
33
36
|
import './chunk-B33XPEKY.js';
|
|
34
37
|
import './chunk-J5QENANM.js';
|
|
35
38
|
export { getAutotelTracer, getAutotelTracerProvider, setAutotelTracerProvider } from './chunk-HA2WBOGQ.js';
|
|
36
39
|
import './chunk-DGUM43GV.js';
|
|
40
|
+
import { SpanStatusCode, trace } from '@opentelemetry/api';
|
|
37
41
|
export { ROOT_CONTEXT, SpanKind, SpanStatusCode, context, trace as otelTrace, propagation } from '@opentelemetry/api';
|
|
38
42
|
|
|
39
43
|
// src/shutdown.ts
|
|
@@ -166,6 +170,201 @@ function registerShutdownHooks() {
|
|
|
166
170
|
}
|
|
167
171
|
registerShutdownHooks();
|
|
168
172
|
|
|
169
|
-
|
|
173
|
+
// src/flatten-attributes.ts
|
|
174
|
+
function toAttributeValue(value) {
|
|
175
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
if (Array.isArray(value)) {
|
|
179
|
+
if (value.every((v) => typeof v === "string") || value.every((v) => typeof v === "number") || value.every((v) => typeof v === "boolean")) {
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
return JSON.stringify(value);
|
|
184
|
+
} catch {
|
|
185
|
+
return "<serialization-failed>";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (value instanceof Date) {
|
|
189
|
+
return value.toISOString();
|
|
190
|
+
}
|
|
191
|
+
if (value instanceof Error) {
|
|
192
|
+
return value.message;
|
|
193
|
+
}
|
|
194
|
+
return void 0;
|
|
195
|
+
}
|
|
196
|
+
function flattenToAttributes(fields, prefix = "") {
|
|
197
|
+
const out = {};
|
|
198
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
199
|
+
function flatten(obj, currentPrefix) {
|
|
200
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
201
|
+
if (value == null) continue;
|
|
202
|
+
const nextKey = currentPrefix ? `${currentPrefix}.${key}` : key;
|
|
203
|
+
const attr = toAttributeValue(value);
|
|
204
|
+
if (attr !== void 0) {
|
|
205
|
+
out[nextKey] = attr;
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (typeof value === "object" && value.constructor === Object) {
|
|
209
|
+
if (seen.has(value)) {
|
|
210
|
+
out[nextKey] = "<circular-reference>";
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
seen.add(value);
|
|
214
|
+
flatten(value, nextKey);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
out[nextKey] = JSON.stringify(value);
|
|
219
|
+
} catch {
|
|
220
|
+
out[nextKey] = "<serialization-failed>";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
flatten(fields, prefix);
|
|
225
|
+
return out;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/structured-error.ts
|
|
229
|
+
function createStructuredError(input) {
|
|
230
|
+
const error = new Error(input.message, {
|
|
231
|
+
cause: input.cause
|
|
232
|
+
});
|
|
233
|
+
error.name = input.name ?? "StructuredError";
|
|
234
|
+
if (input.why !== void 0) error.why = input.why;
|
|
235
|
+
if (input.fix !== void 0) error.fix = input.fix;
|
|
236
|
+
if (input.link !== void 0) error.link = input.link;
|
|
237
|
+
if (input.code !== void 0) error.code = input.code;
|
|
238
|
+
if (input.status !== void 0) error.status = input.status;
|
|
239
|
+
if (input.details !== void 0) error.details = input.details;
|
|
240
|
+
return error;
|
|
241
|
+
}
|
|
242
|
+
function getStructuredErrorAttributes(error) {
|
|
243
|
+
const structured = error;
|
|
244
|
+
const attributes = {
|
|
245
|
+
"error.type": error.name || "Error",
|
|
246
|
+
"error.message": error.message
|
|
247
|
+
};
|
|
248
|
+
if (error.stack) attributes["error.stack"] = error.stack;
|
|
249
|
+
if (structured.why) attributes["error.why"] = structured.why;
|
|
250
|
+
if (structured.fix) attributes["error.fix"] = structured.fix;
|
|
251
|
+
if (structured.link) attributes["error.link"] = structured.link;
|
|
252
|
+
if (structured.code !== void 0) {
|
|
253
|
+
attributes["error.code"] = typeof structured.code === "string" ? structured.code : String(structured.code);
|
|
254
|
+
}
|
|
255
|
+
if (structured.status !== void 0) {
|
|
256
|
+
attributes["error.status"] = structured.status;
|
|
257
|
+
}
|
|
258
|
+
if (structured.details) {
|
|
259
|
+
Object.assign(
|
|
260
|
+
attributes,
|
|
261
|
+
flattenToAttributes(structured.details, "error.details")
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
return attributes;
|
|
265
|
+
}
|
|
266
|
+
function recordStructuredError(ctx2, error) {
|
|
267
|
+
ctx2.recordException(error);
|
|
268
|
+
ctx2.setStatus({
|
|
269
|
+
code: SpanStatusCode.ERROR,
|
|
270
|
+
message: error.message
|
|
271
|
+
});
|
|
272
|
+
ctx2.setAttributes(getStructuredErrorAttributes(error));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/request-logger.ts
|
|
276
|
+
function resolveContext(ctx2) {
|
|
277
|
+
if (ctx2) return ctx2;
|
|
278
|
+
const span2 = trace.getActiveSpan();
|
|
279
|
+
if (!span2) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
"[autotel] getRequestLogger() requires an active span. Wrap your handler with trace()."
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
return createTraceContext(span2);
|
|
285
|
+
}
|
|
286
|
+
function getRequestLogger(ctx2, options) {
|
|
287
|
+
const activeContext = resolveContext(ctx2);
|
|
288
|
+
let contextState = {};
|
|
289
|
+
const addLogEvent = (level, message, fields) => {
|
|
290
|
+
const attrs2 = fields ? flattenToAttributes(fields) : void 0;
|
|
291
|
+
activeContext.addEvent(`log.${level}`, {
|
|
292
|
+
message,
|
|
293
|
+
...attrs2
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
return {
|
|
297
|
+
set(fields) {
|
|
298
|
+
contextState = {
|
|
299
|
+
...contextState,
|
|
300
|
+
...fields
|
|
301
|
+
};
|
|
302
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
303
|
+
},
|
|
304
|
+
info(message, fields) {
|
|
305
|
+
addLogEvent("info", message, fields);
|
|
306
|
+
if (fields) {
|
|
307
|
+
contextState = {
|
|
308
|
+
...contextState,
|
|
309
|
+
...fields
|
|
310
|
+
};
|
|
311
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
warn(message, fields) {
|
|
315
|
+
addLogEvent("warn", message, fields);
|
|
316
|
+
activeContext.setAttribute("autotel.log.level", "warn");
|
|
317
|
+
if (fields) {
|
|
318
|
+
contextState = {
|
|
319
|
+
...contextState,
|
|
320
|
+
...fields
|
|
321
|
+
};
|
|
322
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
error(error, fields) {
|
|
326
|
+
const err = typeof error === "string" ? new Error(error) : error;
|
|
327
|
+
recordStructuredError(activeContext, err);
|
|
328
|
+
addLogEvent("error", err.message, fields);
|
|
329
|
+
if (fields) {
|
|
330
|
+
contextState = {
|
|
331
|
+
...contextState,
|
|
332
|
+
...fields
|
|
333
|
+
};
|
|
334
|
+
activeContext.setAttributes(flattenToAttributes(fields));
|
|
335
|
+
}
|
|
336
|
+
activeContext.setAttribute("autotel.log.level", "error");
|
|
337
|
+
},
|
|
338
|
+
getContext() {
|
|
339
|
+
return { ...contextState };
|
|
340
|
+
},
|
|
341
|
+
emitNow(overrides) {
|
|
342
|
+
const mergedContext = {
|
|
343
|
+
...contextState,
|
|
344
|
+
...overrides ?? {}
|
|
345
|
+
};
|
|
346
|
+
const flattened = flattenToAttributes(mergedContext);
|
|
347
|
+
activeContext.setAttributes(flattened);
|
|
348
|
+
const snapshot = {
|
|
349
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
350
|
+
traceId: activeContext.traceId,
|
|
351
|
+
spanId: activeContext.spanId,
|
|
352
|
+
correlationId: activeContext.correlationId,
|
|
353
|
+
context: mergedContext
|
|
354
|
+
};
|
|
355
|
+
activeContext.addEvent("log.emit.manual", {
|
|
356
|
+
...flattened
|
|
357
|
+
});
|
|
358
|
+
if (options?.onEmit) {
|
|
359
|
+
Promise.resolve(options.onEmit(snapshot)).catch((error) => {
|
|
360
|
+
console.warn("[autotel] request logger onEmit failed:", error);
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
return snapshot;
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export { createStructuredError, flattenToAttributes, flush, getRequestLogger, getStructuredErrorAttributes, recordStructuredError, shutdown, toAttributeValue };
|
|
170
369
|
//# sourceMappingURL=index.js.map
|
|
171
370
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shutdown.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Graceful shutdown with flush and cleanup\n */\n\nimport { getSdk, getLogger } from './init';\nimport { getEventQueue, resetEventQueue } from './track';\nimport { resetEvents } from './event';\nimport { resetMetrics } from './metric';\n\n/**\n * Flush all pending telemetry\n *\n * Flushes both events events and OpenTelemetry spans to their destinations.\n * Includes timeout protection to prevent hanging in serverless environments.\n *\n * Safe to call multiple times.\n *\n * @param options - Optional configuration\n * @param options.timeout - Timeout in milliseconds (default: 2000ms)\n * @param options.forShutdown - If true, permanently disables the events queue after flush (used internally by shutdown())\n *\n * @example Manual flush in serverless\n * ```typescript\n * import { flush } from 'autotel';\n *\n * export const handler = async (event) => {\n * // ... process event\n * await flush(); // Flush before function returns\n * return result;\n * };\n * ```\n *\n * @example With custom timeout\n * ```typescript\n * await flush({ timeout: 5000 }); // 5 second timeout\n * ```\n */\nexport async function flush(options?: {\n timeout?: number;\n forShutdown?: boolean;\n}): Promise<void> {\n const timeout = options?.timeout ?? 2000;\n const forShutdown = options?.forShutdown ?? false;\n\n const doFlush = async () => {\n // Flush events queue (or shutdown queue when tearing down)\n const eventsQueue = getEventQueue();\n if (eventsQueue) {\n if (forShutdown) {\n await eventsQueue.shutdown();\n } else {\n await eventsQueue.flush();\n }\n }\n\n // Flush OpenTelemetry spans\n // This ensures spans are exported immediately, critical for serverless\n const sdk = getSdk();\n if (sdk) {\n try {\n // Type assertion needed as getTracerProvider is not in the public NodeSDK interface\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkAny = sdk as any;\n if (typeof sdkAny.getTracerProvider === 'function') {\n const tracerProvider = sdkAny.getTracerProvider();\n if (\n tracerProvider &&\n typeof tracerProvider.forceFlush === 'function'\n ) {\n await tracerProvider.forceFlush();\n }\n }\n } catch {\n // Ignore errors when accessing tracer provider (may not be available in test mocks)\n }\n }\n };\n\n // Add timeout protection to prevent hanging\n let timeoutHandle: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n doFlush().finally(() => {\n // Clear timeout as soon as flush completes\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }),\n new Promise<void>((_, reject) => {\n timeoutHandle = setTimeout(\n () => reject(new Error('Flush timeout')),\n timeout,\n );\n // Use unref() to allow Node to exit if flush completes first\n // This prevents the 2s delay in serverless when flush succeeds immediately\n timeoutHandle.unref();\n }),\n ]);\n } catch (error) {\n // Clear timeout on error too\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n const logger = getLogger();\n logger.error(\n {\n err: error instanceof Error ? error : new Error(String(error)),\n },\n '[autotel] Flush error',\n );\n throw error;\n }\n}\n\n/**\n * Shutdown telemetry and cleanup resources\n *\n * - Flushes all pending data\n * - Shuts down OpenTelemetry SDK\n * - Cleans up resources\n *\n * Call this before process exit.\n *\n * Always performs cleanup even if flush fails, preventing resource leaks\n * in serverless handlers or tests.\n *\n * @example Express server\n * ```typescript\n * const server = app.listen(3000)\n *\n * process.on('SIGTERM', async () => {\n * await server.close()\n * await shutdown()\n * process.exit(0)\n * })\n * ```\n */\nexport async function shutdown(): Promise<void> {\n const logger = getLogger();\n let shutdownError: Error | null = null;\n\n // Attempt to flush (with queue shutdown so new events are rejected), but continue with cleanup even if it fails\n try {\n await flush({ forShutdown: true });\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n shutdownError = err;\n logger.error(\n {\n err,\n },\n '[autotel] Flush failed during shutdown, continuing cleanup',\n );\n }\n\n // Always shutdown SDK and clean up resources\n try {\n // Shutdown OpenTelemetry SDK\n const sdk = getSdk();\n if (sdk) {\n await sdk.shutdown();\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Ignore ECONNREFUSED errors - this happens when no OTLP endpoint was configured\n // The SDK tries to flush exporters that don't exist, which is harmless\n const isConnectionRefused =\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === 'ECONNREFUSED';\n\n if (!isConnectionRefused) {\n // Only store/log non-connection errors\n if (!shutdownError) {\n shutdownError = err;\n }\n logger.error({ err }, '[autotel] SDK shutdown failed');\n }\n } finally {\n // Clean up singleton Maps and queues to prevent memory leaks\n // This runs even if SDK shutdown fails\n const eventsQueue = getEventQueue();\n if (eventsQueue && typeof eventsQueue.cleanup === 'function') {\n eventsQueue.cleanup();\n }\n resetEvents();\n resetMetrics();\n resetEventQueue();\n }\n\n // Rethrow first error after cleanup completes\n // This allows tests and CI to detect failures while still ensuring cleanup\n if (shutdownError) {\n throw shutdownError;\n }\n}\n\n/**\n * Register automatic shutdown hooks for common signals\n *\n * Handles:\n * - SIGTERM (Docker/K8s graceful shutdown)\n * - SIGINT (Ctrl+C)\n *\n * @internal Called automatically on module load\n */\nfunction registerShutdownHooks(): void {\n if (typeof process === 'undefined') return; // Not in Node.js\n\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n let shuttingDown = false;\n\n for (const signal of signals) {\n process.on(signal, async () => {\n if (shuttingDown) return; // Prevent double shutdown\n shuttingDown = true;\n\n if (process.env.NODE_ENV !== 'test') {\n getLogger().info(\n {},\n `[autotel] Received ${signal}, flushing telemetry...`,\n );\n }\n\n try {\n await shutdown();\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n '[autotel] Error during shutdown',\n );\n } finally {\n process.exit(0);\n }\n });\n }\n}\n\n// Auto-register shutdown hooks\nregisterShutdownHooks();\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/shutdown.ts","../src/flatten-attributes.ts","../src/structured-error.ts","../src/request-logger.ts"],"names":["ctx","span","otelTrace","attrs"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Graceful shutdown with flush and cleanup\n */\n\nimport { getSdk, getLogger } from './init';\nimport { getEventQueue, resetEventQueue } from './track';\nimport { resetEvents } from './event';\nimport { resetMetrics } from './metric';\n\n/**\n * Flush all pending telemetry\n *\n * Flushes both events events and OpenTelemetry spans to their destinations.\n * Includes timeout protection to prevent hanging in serverless environments.\n *\n * Safe to call multiple times.\n *\n * @param options - Optional configuration\n * @param options.timeout - Timeout in milliseconds (default: 2000ms)\n * @param options.forShutdown - If true, permanently disables the events queue after flush (used internally by shutdown())\n *\n * @example Manual flush in serverless\n * ```typescript\n * import { flush } from 'autotel';\n *\n * export const handler = async (event) => {\n * // ... process event\n * await flush(); // Flush before function returns\n * return result;\n * };\n * ```\n *\n * @example With custom timeout\n * ```typescript\n * await flush({ timeout: 5000 }); // 5 second timeout\n * ```\n */\nexport async function flush(options?: {\n timeout?: number;\n forShutdown?: boolean;\n}): Promise<void> {\n const timeout = options?.timeout ?? 2000;\n const forShutdown = options?.forShutdown ?? false;\n\n const doFlush = async () => {\n // Flush events queue (or shutdown queue when tearing down)\n const eventsQueue = getEventQueue();\n if (eventsQueue) {\n if (forShutdown) {\n await eventsQueue.shutdown();\n } else {\n await eventsQueue.flush();\n }\n }\n\n // Flush OpenTelemetry spans\n // This ensures spans are exported immediately, critical for serverless\n const sdk = getSdk();\n if (sdk) {\n try {\n // Type assertion needed as getTracerProvider is not in the public NodeSDK interface\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const sdkAny = sdk as any;\n if (typeof sdkAny.getTracerProvider === 'function') {\n const tracerProvider = sdkAny.getTracerProvider();\n if (\n tracerProvider &&\n typeof tracerProvider.forceFlush === 'function'\n ) {\n await tracerProvider.forceFlush();\n }\n }\n } catch {\n // Ignore errors when accessing tracer provider (may not be available in test mocks)\n }\n }\n };\n\n // Add timeout protection to prevent hanging\n let timeoutHandle: NodeJS.Timeout | undefined;\n try {\n await Promise.race([\n doFlush().finally(() => {\n // Clear timeout as soon as flush completes\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n }),\n new Promise<void>((_, reject) => {\n timeoutHandle = setTimeout(\n () => reject(new Error('Flush timeout')),\n timeout,\n );\n // Use unref() to allow Node to exit if flush completes first\n // This prevents the 2s delay in serverless when flush succeeds immediately\n timeoutHandle.unref();\n }),\n ]);\n } catch (error) {\n // Clear timeout on error too\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n const logger = getLogger();\n logger.error(\n {\n err: error instanceof Error ? error : new Error(String(error)),\n },\n '[autotel] Flush error',\n );\n throw error;\n }\n}\n\n/**\n * Shutdown telemetry and cleanup resources\n *\n * - Flushes all pending data\n * - Shuts down OpenTelemetry SDK\n * - Cleans up resources\n *\n * Call this before process exit.\n *\n * Always performs cleanup even if flush fails, preventing resource leaks\n * in serverless handlers or tests.\n *\n * @example Express server\n * ```typescript\n * const server = app.listen(3000)\n *\n * process.on('SIGTERM', async () => {\n * await server.close()\n * await shutdown()\n * process.exit(0)\n * })\n * ```\n */\nexport async function shutdown(): Promise<void> {\n const logger = getLogger();\n let shutdownError: Error | null = null;\n\n // Attempt to flush (with queue shutdown so new events are rejected), but continue with cleanup even if it fails\n try {\n await flush({ forShutdown: true });\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n shutdownError = err;\n logger.error(\n {\n err,\n },\n '[autotel] Flush failed during shutdown, continuing cleanup',\n );\n }\n\n // Always shutdown SDK and clean up resources\n try {\n // Shutdown OpenTelemetry SDK\n const sdk = getSdk();\n if (sdk) {\n await sdk.shutdown();\n }\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Ignore ECONNREFUSED errors - this happens when no OTLP endpoint was configured\n // The SDK tries to flush exporters that don't exist, which is harmless\n const isConnectionRefused =\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === 'ECONNREFUSED';\n\n if (!isConnectionRefused) {\n // Only store/log non-connection errors\n if (!shutdownError) {\n shutdownError = err;\n }\n logger.error({ err }, '[autotel] SDK shutdown failed');\n }\n } finally {\n // Clean up singleton Maps and queues to prevent memory leaks\n // This runs even if SDK shutdown fails\n const eventsQueue = getEventQueue();\n if (eventsQueue && typeof eventsQueue.cleanup === 'function') {\n eventsQueue.cleanup();\n }\n resetEvents();\n resetMetrics();\n resetEventQueue();\n }\n\n // Rethrow first error after cleanup completes\n // This allows tests and CI to detect failures while still ensuring cleanup\n if (shutdownError) {\n throw shutdownError;\n }\n}\n\n/**\n * Register automatic shutdown hooks for common signals\n *\n * Handles:\n * - SIGTERM (Docker/K8s graceful shutdown)\n * - SIGINT (Ctrl+C)\n *\n * @internal Called automatically on module load\n */\nfunction registerShutdownHooks(): void {\n if (typeof process === 'undefined') return; // Not in Node.js\n\n const signals: NodeJS.Signals[] = ['SIGTERM', 'SIGINT'];\n let shuttingDown = false;\n\n for (const signal of signals) {\n process.on(signal, async () => {\n if (shuttingDown) return; // Prevent double shutdown\n shuttingDown = true;\n\n if (process.env.NODE_ENV !== 'test') {\n getLogger().info(\n {},\n `[autotel] Received ${signal}, flushing telemetry...`,\n );\n }\n\n try {\n await shutdown();\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n '[autotel] Error during shutdown',\n );\n } finally {\n process.exit(0);\n }\n });\n }\n}\n\n// Auto-register shutdown hooks\nregisterShutdownHooks();\n","import type { AttributeValue } from './trace-context';\n\n/**\n * Convert an unknown value to an OTel-compatible AttributeValue.\n * Returns undefined when the value cannot be represented.\n */\nexport function toAttributeValue(value: unknown): AttributeValue | undefined {\n if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n ) {\n return value;\n }\n if (Array.isArray(value)) {\n if (\n value.every((v) => typeof v === 'string') ||\n value.every((v) => typeof v === 'number') ||\n value.every((v) => typeof v === 'boolean')\n ) {\n return value as AttributeValue;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '<serialization-failed>';\n }\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (value instanceof Error) {\n return value.message;\n }\n return undefined;\n}\n\n/**\n * Recursively flatten a nested object into dot-notation OTel attributes.\n * Includes circular reference protection via WeakSet.\n */\nexport function flattenToAttributes(\n fields: Record<string, unknown>,\n prefix = '',\n): Record<string, AttributeValue> {\n const out: Record<string, AttributeValue> = {};\n const seen = new WeakSet<object>();\n\n function flatten(obj: Record<string, unknown>, currentPrefix: string): void {\n for (const [key, value] of Object.entries(obj)) {\n if (value == null) continue;\n const nextKey = currentPrefix ? `${currentPrefix}.${key}` : key;\n\n const attr = toAttributeValue(value);\n if (attr !== undefined) {\n out[nextKey] = attr;\n continue;\n }\n\n if (typeof value === 'object' && value.constructor === Object) {\n if (seen.has(value)) {\n out[nextKey] = '<circular-reference>';\n continue;\n }\n seen.add(value);\n flatten(value as Record<string, unknown>, nextKey);\n continue;\n }\n\n try {\n out[nextKey] = JSON.stringify(value);\n } catch {\n out[nextKey] = '<serialization-failed>';\n }\n }\n }\n\n flatten(fields, prefix);\n return out;\n}\n","import { SpanStatusCode } from '@opentelemetry/api';\nimport type { AttributeValue, TraceContext } from './trace-context';\nimport { flattenToAttributes } from './flatten-attributes';\n\nexport interface StructuredErrorInput {\n message: string;\n why?: string;\n fix?: string;\n link?: string;\n code?: string | number;\n status?: number;\n cause?: unknown;\n details?: Record<string, unknown>;\n name?: string;\n}\n\nexport interface StructuredError extends Error {\n why?: string;\n fix?: string;\n link?: string;\n code?: string | number;\n status?: number;\n details?: Record<string, unknown>;\n}\n\nexport function createStructuredError(\n input: StructuredErrorInput,\n): StructuredError {\n const error = new Error(input.message, {\n cause: input.cause,\n }) as StructuredError;\n\n error.name = input.name ?? 'StructuredError';\n if (input.why !== undefined) error.why = input.why;\n if (input.fix !== undefined) error.fix = input.fix;\n if (input.link !== undefined) error.link = input.link;\n if (input.code !== undefined) error.code = input.code;\n if (input.status !== undefined) error.status = input.status;\n if (input.details !== undefined) error.details = input.details;\n\n return error;\n}\n\nexport function getStructuredErrorAttributes(\n error: Error,\n): Record<string, AttributeValue> {\n const structured = error as StructuredError;\n const attributes: Record<string, AttributeValue> = {\n 'error.type': error.name || 'Error',\n 'error.message': error.message,\n };\n\n if (error.stack) attributes['error.stack'] = error.stack;\n if (structured.why) attributes['error.why'] = structured.why;\n if (structured.fix) attributes['error.fix'] = structured.fix;\n if (structured.link) attributes['error.link'] = structured.link;\n if (structured.code !== undefined) {\n attributes['error.code'] =\n typeof structured.code === 'string'\n ? structured.code\n : String(structured.code);\n }\n if (structured.status !== undefined) {\n attributes['error.status'] = structured.status;\n }\n if (structured.details) {\n Object.assign(\n attributes,\n flattenToAttributes(structured.details, 'error.details'),\n );\n }\n\n return attributes;\n}\n\nexport function recordStructuredError(\n ctx: Pick<TraceContext, 'recordException' | 'setAttributes' | 'setStatus'>,\n error: Error,\n): void {\n ctx.recordException(error);\n ctx.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n ctx.setAttributes(getStructuredErrorAttributes(error));\n}\n","import { trace as otelTrace } from '@opentelemetry/api';\nimport type { TraceContext } from './trace-context';\nimport { createTraceContext } from './trace-context';\nimport { recordStructuredError } from './structured-error';\nimport { flattenToAttributes } from './flatten-attributes';\n\nexport interface RequestLogger {\n set(fields: Record<string, unknown>): void;\n info(message: string, fields?: Record<string, unknown>): void;\n warn(message: string, fields?: Record<string, unknown>): void;\n error(error: Error | string, fields?: Record<string, unknown>): void;\n getContext(): Record<string, unknown>;\n emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot;\n}\n\nexport interface RequestLogSnapshot {\n timestamp: string;\n traceId: string;\n spanId: string;\n correlationId: string;\n context: Record<string, unknown>;\n}\n\nexport interface RequestLoggerOptions {\n /** Callback invoked by emitNow() for manual fan-out. */\n onEmit?: (snapshot: RequestLogSnapshot) => void | Promise<void>;\n}\n\nfunction resolveContext(ctx?: TraceContext): TraceContext {\n if (ctx) return ctx;\n\n const span = otelTrace.getActiveSpan();\n if (!span) {\n throw new Error(\n '[autotel] getRequestLogger() requires an active span. Wrap your handler with trace().',\n );\n }\n return createTraceContext(span);\n}\n\nexport function getRequestLogger(\n ctx?: TraceContext,\n options?: RequestLoggerOptions,\n): RequestLogger {\n const activeContext = resolveContext(ctx);\n let contextState: Record<string, unknown> = {};\n\n const addLogEvent = (\n level: 'info' | 'warn' | 'error',\n message: string,\n fields?: Record<string, unknown>,\n ) => {\n const attrs = fields ? flattenToAttributes(fields) : undefined;\n activeContext.addEvent(`log.${level}`, {\n message,\n ...attrs,\n });\n };\n\n return {\n set(fields: Record<string, unknown>) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n },\n\n info(message: string, fields?: Record<string, unknown>) {\n addLogEvent('info', message, fields);\n if (fields) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n }\n },\n\n warn(message: string, fields?: Record<string, unknown>) {\n addLogEvent('warn', message, fields);\n activeContext.setAttribute('autotel.log.level', 'warn');\n if (fields) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n }\n },\n\n error(error: Error | string, fields?: Record<string, unknown>) {\n const err = typeof error === 'string' ? new Error(error) : error;\n recordStructuredError(activeContext, err);\n addLogEvent('error', err.message, fields);\n\n if (fields) {\n contextState = {\n ...contextState,\n ...fields,\n };\n activeContext.setAttributes(flattenToAttributes(fields));\n }\n activeContext.setAttribute('autotel.log.level', 'error');\n },\n\n getContext() {\n return { ...contextState };\n },\n\n emitNow(overrides?: Record<string, unknown>): RequestLogSnapshot {\n const mergedContext = {\n ...contextState,\n ...(overrides ?? {}),\n };\n const flattened = flattenToAttributes(mergedContext);\n activeContext.setAttributes(flattened);\n\n const snapshot: RequestLogSnapshot = {\n timestamp: new Date().toISOString(),\n traceId: activeContext.traceId,\n spanId: activeContext.spanId,\n correlationId: activeContext.correlationId,\n context: mergedContext,\n };\n\n activeContext.addEvent('log.emit.manual', {\n ...flattened,\n });\n\n if (options?.onEmit) {\n Promise.resolve(options.onEmit(snapshot)).catch((error) => {\n console.warn('[autotel] request logger onEmit failed:', error);\n });\n }\n\n return snapshot;\n },\n };\n}\n"]}
|
|
@@ -11,6 +11,7 @@ import { LogRecordProcessor } from '@opentelemetry/sdk-logs';
|
|
|
11
11
|
import { SpanFilterPredicate } from './filtering-span-processor.cjs';
|
|
12
12
|
import { SpanNameNormalizerConfig } from './span-name-normalizer.cjs';
|
|
13
13
|
import { AttributeRedactorConfig, AttributeRedactorPreset } from './attribute-redacting-processor.cjs';
|
|
14
|
+
import { CanonicalLogLineOptions } from './processors.cjs';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Input validation for events events and attributes
|
|
@@ -941,6 +942,23 @@ interface AutotelConfig {
|
|
|
941
942
|
messageFormat?: (span: _opentelemetry_sdk_trace_base.ReadableSpan) => string;
|
|
942
943
|
/** Whether to include resource attributes (default: true) */
|
|
943
944
|
includeResourceAttributes?: boolean;
|
|
945
|
+
/** Predicate to decide whether to emit (runs after event is built). */
|
|
946
|
+
shouldEmit?: CanonicalLogLineOptions['shouldEmit'];
|
|
947
|
+
/**
|
|
948
|
+
* Declarative tail sampling conditions (OR logic).
|
|
949
|
+
* Ignored when `shouldEmit` is provided.
|
|
950
|
+
* @example keep: [{ status: 500 }, { durationMs: 1000 }]
|
|
951
|
+
*/
|
|
952
|
+
keep?: CanonicalLogLineOptions['keep'];
|
|
953
|
+
/** Callback invoked after emit for custom fan-out. */
|
|
954
|
+
drain?: CanonicalLogLineOptions['drain'];
|
|
955
|
+
/** Handler for drain failures. */
|
|
956
|
+
onDrainError?: CanonicalLogLineOptions['onDrainError'];
|
|
957
|
+
/**
|
|
958
|
+
* Pretty-print canonical log lines to console.
|
|
959
|
+
* Defaults to true when NODE_ENV is 'development'.
|
|
960
|
+
*/
|
|
961
|
+
pretty?: boolean;
|
|
944
962
|
};
|
|
945
963
|
}
|
|
946
964
|
/**
|
|
@@ -11,6 +11,7 @@ import { LogRecordProcessor } from '@opentelemetry/sdk-logs';
|
|
|
11
11
|
import { SpanFilterPredicate } from './filtering-span-processor.js';
|
|
12
12
|
import { SpanNameNormalizerConfig } from './span-name-normalizer.js';
|
|
13
13
|
import { AttributeRedactorConfig, AttributeRedactorPreset } from './attribute-redacting-processor.js';
|
|
14
|
+
import { CanonicalLogLineOptions } from './processors.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Input validation for events events and attributes
|
|
@@ -941,6 +942,23 @@ interface AutotelConfig {
|
|
|
941
942
|
messageFormat?: (span: _opentelemetry_sdk_trace_base.ReadableSpan) => string;
|
|
942
943
|
/** Whether to include resource attributes (default: true) */
|
|
943
944
|
includeResourceAttributes?: boolean;
|
|
945
|
+
/** Predicate to decide whether to emit (runs after event is built). */
|
|
946
|
+
shouldEmit?: CanonicalLogLineOptions['shouldEmit'];
|
|
947
|
+
/**
|
|
948
|
+
* Declarative tail sampling conditions (OR logic).
|
|
949
|
+
* Ignored when `shouldEmit` is provided.
|
|
950
|
+
* @example keep: [{ status: 500 }, { durationMs: 1000 }]
|
|
951
|
+
*/
|
|
952
|
+
keep?: CanonicalLogLineOptions['keep'];
|
|
953
|
+
/** Callback invoked after emit for custom fan-out. */
|
|
954
|
+
drain?: CanonicalLogLineOptions['drain'];
|
|
955
|
+
/** Handler for drain failures. */
|
|
956
|
+
onDrainError?: CanonicalLogLineOptions['onDrainError'];
|
|
957
|
+
/**
|
|
958
|
+
* Pretty-print canonical log lines to console.
|
|
959
|
+
* Defaults to true when NODE_ENV is 'development'.
|
|
960
|
+
*/
|
|
961
|
+
pretty?: boolean;
|
|
944
962
|
};
|
|
945
963
|
}
|
|
946
964
|
/**
|