autotel 4.0.0 → 4.2.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 +26 -1
- package/dist/auto.cjs +2 -2
- package/dist/auto.js +1 -1
- package/dist/correlation-id.cjs +1 -1
- package/dist/correlation-id.js +1 -1
- package/dist/decorators.cjs +1 -1
- package/dist/decorators.js +1 -1
- package/dist/{event-Dlqr4ZNL.cjs → event-BhHREDJk.cjs} +3 -3
- package/dist/{event-Dlqr4ZNL.cjs.map → event-BhHREDJk.cjs.map} +1 -1
- package/dist/{event-_58ryBjh.js → event-ByBTV9M2.js} +3 -3
- package/dist/{event-_58ryBjh.js.map → event-ByBTV9M2.js.map} +1 -1
- package/dist/event.cjs +1 -1
- package/dist/event.js +1 -1
- package/dist/{functional-BGkT8J-h.js → functional-DtI0u4vx.js} +19 -19
- package/dist/functional-DtI0u4vx.js.map +1 -0
- package/dist/{functional-C4CzoVrX.cjs → functional-zpzNLhky.cjs} +4 -4
- package/dist/{functional-C4CzoVrX.cjs.map → functional-zpzNLhky.cjs.map} +1 -1
- 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 +5 -5
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/{init-DJQOdVlN.d.ts → init-B7u-DjxM.d.ts} +57 -2
- package/dist/init-B7u-DjxM.d.ts.map +1 -0
- package/dist/{init-DvapOXCc.cjs → init-BX7AmFRl.cjs} +40 -21
- package/dist/init-BX7AmFRl.cjs.map +1 -0
- package/dist/{init-Ch6t7MNI.js → init-D-jnNMix.js} +39 -20
- package/dist/init-D-jnNMix.js.map +1 -0
- package/dist/{init-CNp-ee80.d.cts → init-DSrRmVnz.d.cts} +57 -2
- package/dist/init-DSrRmVnz.d.cts.map +1 -0
- package/dist/instrumentation.cjs +1 -1
- package/dist/instrumentation.js +1 -1
- package/dist/logger-D3Ej3DII.js +446 -0
- package/dist/logger-D3Ej3DII.js.map +1 -0
- package/dist/logger-thMPLpOG.cjs +487 -0
- package/dist/logger-thMPLpOG.cjs.map +1 -0
- package/dist/logger.cjs +8 -236
- package/dist/logger.js +2 -204
- package/dist/messaging.cjs +1 -1
- package/dist/messaging.js +1 -1
- package/dist/semantic-helpers.cjs +1 -1
- package/dist/semantic-helpers.js +1 -1
- package/dist/{track-3HY4NGV-.cjs → track-D59FfpL0.cjs} +2 -2
- package/dist/{track-3HY4NGV-.cjs.map → track-D59FfpL0.cjs.map} +1 -1
- package/dist/{track-nsKVy-pj.js → track-wc0HafS_.js} +6 -6
- package/dist/track-wc0HafS_.js.map +1 -0
- 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 +1 -1
- package/dist/workflow.js +1 -1
- package/dist/{yaml-config-B3dQ82GR.cjs → yaml-config-Ck2uB0Dp.cjs} +2 -1
- package/dist/yaml-config-Ck2uB0Dp.cjs.map +1 -0
- package/dist/yaml-config.cjs +1 -1
- package/dist/yaml-config.d.cts +7 -1
- package/dist/yaml-config.d.cts.map +1 -1
- package/dist/yaml-config.d.ts +7 -1
- package/dist/yaml-config.d.ts.map +1 -1
- package/dist/yaml-config.js +1 -0
- package/dist/yaml-config.js.map +1 -1
- package/package.json +1 -2
- package/skills/autotel-core/SKILL.md +2 -0
- package/skills/autotel-instrumentation/SKILL.md +25 -0
- package/skills/debug-missing-spans/SKILL.md +3 -1
- package/skills/migrate-to-autotel/SKILL.md +24 -23
- package/skills/review-otel-patterns/SKILL.md +5 -4
- package/dist/functional-BGkT8J-h.js.map +0 -1
- package/dist/init-CNp-ee80.d.cts.map +0 -1
- package/dist/init-Ch6t7MNI.js.map +0 -1
- package/dist/init-DJQOdVlN.d.ts.map +0 -1
- package/dist/init-DvapOXCc.cjs.map +0 -1
- package/dist/logger.cjs.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/track-nsKVy-pj.js.map +0 -1
- package/dist/yaml-config-B3dQ82GR.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 -594
- 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 -2312
- 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 -337
- package/src/yaml-config.ts +0 -342
package/src/events-config.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Events configuration types for trace context, correlation IDs, and enrichment
|
|
3
|
-
*
|
|
4
|
-
* @example Basic usage
|
|
5
|
-
* ```typescript
|
|
6
|
-
* import { init } from 'autotel';
|
|
7
|
-
*
|
|
8
|
-
* init({
|
|
9
|
-
* service: 'my-app',
|
|
10
|
-
* events: {
|
|
11
|
-
* includeTraceContext: true,
|
|
12
|
-
* traceUrl: (ctx) => `https://grafana.internal/explore?traceId=${ctx.traceId}`
|
|
13
|
-
* }
|
|
14
|
-
* });
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Context passed to the traceUrl function for generating clickable trace URLs
|
|
20
|
-
*/
|
|
21
|
-
export interface TraceUrlContext {
|
|
22
|
-
/** Trace ID (32 hex chars) - may be undefined outside a trace */
|
|
23
|
-
traceId?: string;
|
|
24
|
-
/** Span ID (16 hex chars) - may be undefined outside a trace */
|
|
25
|
-
spanId?: string;
|
|
26
|
-
/** Correlation ID (always present, 16 hex chars) */
|
|
27
|
-
correlationId: string;
|
|
28
|
-
/** Service name from init config */
|
|
29
|
-
serviceName: string;
|
|
30
|
-
/** Environment from init config */
|
|
31
|
-
environment?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Per-key transform options for baggage enrichment
|
|
36
|
-
*/
|
|
37
|
-
export type BaggageTransform = 'plain' | 'hash' | ((value: string) => string);
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Baggage enrichment configuration with guardrails
|
|
41
|
-
*/
|
|
42
|
-
export interface EnrichFromBaggageConfig {
|
|
43
|
-
/**
|
|
44
|
-
* Allowlist of baggage keys to include in events
|
|
45
|
-
* Supports exact matches and patterns (e.g., 'tenant.*')
|
|
46
|
-
*/
|
|
47
|
-
allow: string[];
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Optional denylist of baggage keys to exclude
|
|
51
|
-
* Takes precedence over allow list
|
|
52
|
-
*/
|
|
53
|
-
deny?: string[];
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Optional prefix to add to all enriched keys
|
|
57
|
-
* @example 'ctx.' results in 'ctx.tenant.id'
|
|
58
|
-
*/
|
|
59
|
-
prefix?: string;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Maximum number of keys to include (default: 10)
|
|
63
|
-
* Prevents payload bloat from excessive baggage
|
|
64
|
-
*/
|
|
65
|
-
maxKeys?: number;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Maximum total bytes for enriched values (default: 1024)
|
|
69
|
-
* Prevents payload bloat from large baggage values
|
|
70
|
-
*/
|
|
71
|
-
maxBytes?: number;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Per-key transform options
|
|
75
|
-
* - 'plain': Include value as-is
|
|
76
|
-
* - 'hash': Hash the value (for PII protection)
|
|
77
|
-
* - function: Custom transform function
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```typescript
|
|
81
|
-
* transform: {
|
|
82
|
-
* 'user.id': 'hash', // Hash user ID for privacy
|
|
83
|
-
* 'tenant.id': 'plain', // Include tenant ID as-is
|
|
84
|
-
* 'session.id': (v) => v.slice(0, 8) // Custom truncation
|
|
85
|
-
* }
|
|
86
|
-
* ```
|
|
87
|
-
*/
|
|
88
|
-
transform?: Record<string, BaggageTransform>;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Events configuration for trace context and enrichment
|
|
93
|
-
*/
|
|
94
|
-
export interface EventsConfig {
|
|
95
|
-
/**
|
|
96
|
-
* Include trace context in events (default: false)
|
|
97
|
-
*
|
|
98
|
-
* When enabled, events automatically include:
|
|
99
|
-
* - autotel.trace_id (32 hex chars)
|
|
100
|
-
* - autotel.span_id (16 hex chars)
|
|
101
|
-
* - autotel.trace_flags (2 hex chars)
|
|
102
|
-
* - autotel.trace_state (raw tracestate string, if present)
|
|
103
|
-
* - autotel.correlation_id (always present, 16 hex chars)
|
|
104
|
-
*
|
|
105
|
-
* Subscribers map these to platform-specific names:
|
|
106
|
-
* - PostHog: $trace_id, $span_id
|
|
107
|
-
* - Mixpanel: trace_id, span_id
|
|
108
|
-
*/
|
|
109
|
-
includeTraceContext?: boolean;
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Include full array of linked trace IDs for batch/fan-in scenarios (default: false)
|
|
113
|
-
*
|
|
114
|
-
* When false (default), batch/fan-in events include:
|
|
115
|
-
* - autotel.linked_trace_id_count: Number of linked parents
|
|
116
|
-
* - autotel.linked_trace_id_hash: Stable hash of sorted IDs (keeps payload lean)
|
|
117
|
-
*
|
|
118
|
-
* When true, events also include:
|
|
119
|
-
* - autotel.linked_trace_ids: Full array of linked trace IDs
|
|
120
|
-
*/
|
|
121
|
-
includeLinkedTraceIds?: boolean;
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Generate clickable trace URL from context
|
|
125
|
-
*
|
|
126
|
-
* @param ctx - Trace context with traceId, spanId, correlationId, serviceName, environment
|
|
127
|
-
* @returns URL string or undefined to skip
|
|
128
|
-
*
|
|
129
|
-
* @example Grafana Tempo
|
|
130
|
-
* ```typescript
|
|
131
|
-
* traceUrl: (ctx) => ctx.traceId
|
|
132
|
-
* ? `https://grafana.internal/explore?traceId=${ctx.traceId}`
|
|
133
|
-
* : undefined
|
|
134
|
-
* ```
|
|
135
|
-
*
|
|
136
|
-
* @example Datadog
|
|
137
|
-
* ```typescript
|
|
138
|
-
* traceUrl: (ctx) => ctx.traceId
|
|
139
|
-
* ? `https://app.datadoghq.com/apm/traces?traceId=${ctx.traceId}`
|
|
140
|
-
* : undefined
|
|
141
|
-
* ```
|
|
142
|
-
*
|
|
143
|
-
* @example Jaeger
|
|
144
|
-
* ```typescript
|
|
145
|
-
* traceUrl: (ctx) => ctx.traceId
|
|
146
|
-
* ? `https://jaeger.internal/trace/${ctx.traceId}`
|
|
147
|
-
* : undefined
|
|
148
|
-
* ```
|
|
149
|
-
*/
|
|
150
|
-
traceUrl?: (ctx: TraceUrlContext) => string | undefined;
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Auto-enrich events from baggage with guardrails
|
|
154
|
-
*
|
|
155
|
-
* Automatically includes baggage entries in events without manual code.
|
|
156
|
-
* Apply allow/deny lists and per-key transforms for PII protection.
|
|
157
|
-
*
|
|
158
|
-
* @example Basic allowlist
|
|
159
|
-
* ```typescript
|
|
160
|
-
* enrichFromBaggage: {
|
|
161
|
-
* allow: ['tenant.id', 'user.id', 'request.id']
|
|
162
|
-
* }
|
|
163
|
-
* // Events include: tenant.id, user.id, request.id from baggage
|
|
164
|
-
* ```
|
|
165
|
-
*
|
|
166
|
-
* @example With prefix and transforms
|
|
167
|
-
* ```typescript
|
|
168
|
-
* enrichFromBaggage: {
|
|
169
|
-
* allow: ['tenant.id', 'user.id', 'user.email'],
|
|
170
|
-
* deny: ['user.ssn'],
|
|
171
|
-
* prefix: 'ctx.',
|
|
172
|
-
* transform: {
|
|
173
|
-
* 'user.id': 'hash',
|
|
174
|
-
* 'user.email': 'hash'
|
|
175
|
-
* }
|
|
176
|
-
* }
|
|
177
|
-
* // Events include: ctx.tenant.id, ctx.user.id (hashed), ctx.user.email (hashed)
|
|
178
|
-
* ```
|
|
179
|
-
*/
|
|
180
|
-
enrichFromBaggage?: EnrichFromBaggageConfig;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Autotel context object attached to event envelopes
|
|
185
|
-
*
|
|
186
|
-
* This structured object is attached to events and subscribers
|
|
187
|
-
* decide how to map/flatten for their platform.
|
|
188
|
-
*/
|
|
189
|
-
export interface AutotelEventContext {
|
|
190
|
-
/** Trace ID (32 hex chars) - present when inside a trace */
|
|
191
|
-
trace_id?: string;
|
|
192
|
-
/** Span ID (16 hex chars) - present when inside a span */
|
|
193
|
-
span_id?: string;
|
|
194
|
-
/** Trace flags (2 hex chars, e.g., '01' for sampled) */
|
|
195
|
-
trace_flags?: string;
|
|
196
|
-
/** Raw tracestate string - present if tracestate exists */
|
|
197
|
-
trace_state?: string;
|
|
198
|
-
/** Clickable trace URL - present if traceUrl config is set */
|
|
199
|
-
trace_url?: string;
|
|
200
|
-
/** Correlation ID (always present, 16 hex chars) */
|
|
201
|
-
correlation_id: string;
|
|
202
|
-
/** Number of linked parent traces (batch/fan-in scenarios) */
|
|
203
|
-
linked_trace_id_count?: number;
|
|
204
|
-
/** Stable hash of linked trace IDs (default for batch/fan-in) */
|
|
205
|
-
linked_trace_id_hash?: string;
|
|
206
|
-
/** Full array of linked trace IDs (only if includeLinkedTraceIds: true) */
|
|
207
|
-
linked_trace_ids?: string[];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Hash a string value for PII protection
|
|
212
|
-
*
|
|
213
|
-
* Uses a simple, fast hash function suitable for correlation.
|
|
214
|
-
* NOT cryptographically secure - use for PII masking, not security.
|
|
215
|
-
*/
|
|
216
|
-
export function hashValue(value: string): string {
|
|
217
|
-
let hash = 0;
|
|
218
|
-
for (let i = 0; i < value.length; i++) {
|
|
219
|
-
const char = value.charCodeAt(i);
|
|
220
|
-
hash = (hash << 5) - hash + char;
|
|
221
|
-
hash = hash & hash; // Convert to 32-bit integer
|
|
222
|
-
}
|
|
223
|
-
// Convert to positive hex string
|
|
224
|
-
return (hash >>> 0).toString(16).padStart(8, '0');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Create a stable hash of an array of trace IDs
|
|
229
|
-
*
|
|
230
|
-
* Sorts the array first to ensure deterministic output regardless of order.
|
|
231
|
-
*/
|
|
232
|
-
export function hashLinkedTraceIds(traceIds: string[]): string {
|
|
233
|
-
const sorted = [...traceIds].sort();
|
|
234
|
-
return hashValue(sorted.join(','));
|
|
235
|
-
}
|
package/src/exporters.ts
DELETED
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenTelemetry Exporters
|
|
3
|
-
*
|
|
4
|
-
* Re-exports commonly-needed OpenTelemetry exporters for development and debugging.
|
|
5
|
-
*
|
|
6
|
-
* These exporters are already included in autotel's dependencies, so re-exporting
|
|
7
|
-
* them provides a "one install is all you need" developer experience without any
|
|
8
|
-
* bundle size impact.
|
|
9
|
-
*
|
|
10
|
-
* Use these for:
|
|
11
|
-
* - Development debugging (see spans in console)
|
|
12
|
-
* - Progressive development (verify instrumentation works)
|
|
13
|
-
* - Example applications (demonstrate tracing)
|
|
14
|
-
* - Testing (capture spans for assertions)
|
|
15
|
-
*
|
|
16
|
-
* @example Pretty console debugging (recommended)
|
|
17
|
-
* ```typescript
|
|
18
|
-
* import { init } from 'autotel'
|
|
19
|
-
*
|
|
20
|
-
* init({
|
|
21
|
-
* service: 'my-app',
|
|
22
|
-
* debug: 'pretty', // Colorized, hierarchical output
|
|
23
|
-
* })
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* @example Pretty exporter with custom options
|
|
27
|
-
* ```typescript
|
|
28
|
-
* import { init } from 'autotel'
|
|
29
|
-
* import { PrettyConsoleExporter } from 'autotel/exporters'
|
|
30
|
-
*
|
|
31
|
-
* init({
|
|
32
|
-
* service: 'my-app',
|
|
33
|
-
* spanExporters: [new PrettyConsoleExporter({
|
|
34
|
-
* colors: true,
|
|
35
|
-
* showAttributes: true,
|
|
36
|
-
* hideAttributes: ['http.user_agent'],
|
|
37
|
-
* })],
|
|
38
|
-
* })
|
|
39
|
-
* ```
|
|
40
|
-
*
|
|
41
|
-
* @example Raw console debugging
|
|
42
|
-
* ```typescript
|
|
43
|
-
* import { init } from 'autotel'
|
|
44
|
-
* import { ConsoleSpanExporter } from 'autotel/exporters'
|
|
45
|
-
*
|
|
46
|
-
* init({
|
|
47
|
-
* service: 'my-app',
|
|
48
|
-
* spanExporters: [new ConsoleSpanExporter()],
|
|
49
|
-
* })
|
|
50
|
-
* ```
|
|
51
|
-
*
|
|
52
|
-
* @example In-memory testing
|
|
53
|
-
* ```typescript
|
|
54
|
-
* import { init } from 'autotel'
|
|
55
|
-
* import { InMemorySpanExporter } from 'autotel/exporters'
|
|
56
|
-
* import { SimpleSpanProcessor } from 'autotel/processors'
|
|
57
|
-
*
|
|
58
|
-
* const exporter = new InMemorySpanExporter()
|
|
59
|
-
* init({
|
|
60
|
-
* service: 'test',
|
|
61
|
-
* spanProcessor: new SimpleSpanProcessor(exporter),
|
|
62
|
-
* })
|
|
63
|
-
*
|
|
64
|
-
* // Run code under test
|
|
65
|
-
* await myFunction()
|
|
66
|
-
*
|
|
67
|
-
* // Assert on collected spans
|
|
68
|
-
* const spans = exporter.getFinishedSpans()
|
|
69
|
-
* expect(spans).toHaveLength(1)
|
|
70
|
-
* ```
|
|
71
|
-
*
|
|
72
|
-
* Note: For high-level testing utilities with assertion helpers, see `autotel/testing`.
|
|
73
|
-
* For custom span processing, see `autotel/processors`.
|
|
74
|
-
*
|
|
75
|
-
* @module autotel/exporters
|
|
76
|
-
* @see {@link https://opentelemetry.io/docs/specs/otel/trace/sdk/#span-exporter | OTel Span Exporter Spec}
|
|
77
|
-
*/
|
|
78
|
-
|
|
79
|
-
export {
|
|
80
|
-
/**
|
|
81
|
-
* Console exporter - prints raw JSON spans to stdout.
|
|
82
|
-
*
|
|
83
|
-
* Perfect for:
|
|
84
|
-
* - Verbose debugging (see all span details)
|
|
85
|
-
* - Example applications (demonstrate tracing)
|
|
86
|
-
* - Quick debugging (no backend setup required)
|
|
87
|
-
*
|
|
88
|
-
* Note: For better DX, use `debug: 'pretty'` or `PrettyConsoleExporter` instead.
|
|
89
|
-
*
|
|
90
|
-
* @example
|
|
91
|
-
* ```typescript
|
|
92
|
-
* import { ConsoleSpanExporter } from 'autotel/exporters'
|
|
93
|
-
*
|
|
94
|
-
* const exporter = new ConsoleSpanExporter()
|
|
95
|
-
* ```
|
|
96
|
-
*/
|
|
97
|
-
ConsoleSpanExporter,
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* In-memory exporter - stores spans in memory.
|
|
101
|
-
*
|
|
102
|
-
* Perfect for:
|
|
103
|
-
* - Unit testing (capture and assert on spans)
|
|
104
|
-
* - Integration testing (verify trace structure)
|
|
105
|
-
* - Development (inspect spans programmatically)
|
|
106
|
-
*
|
|
107
|
-
* Note: Memory will grow unbounded - clear spans periodically or use for testing only.
|
|
108
|
-
*
|
|
109
|
-
* @example
|
|
110
|
-
* ```typescript
|
|
111
|
-
* import { InMemorySpanExporter } from 'autotel/exporters'
|
|
112
|
-
*
|
|
113
|
-
* const exporter = new InMemorySpanExporter()
|
|
114
|
-
* // ... run code
|
|
115
|
-
* const spans = exporter.getFinishedSpans()
|
|
116
|
-
* exporter.reset() // Clear memory
|
|
117
|
-
* ```
|
|
118
|
-
*/
|
|
119
|
-
InMemorySpanExporter,
|
|
120
|
-
} from '@opentelemetry/sdk-trace-base';
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Pretty console exporter - colorized, hierarchical span output.
|
|
124
|
-
*
|
|
125
|
-
* Perfect for:
|
|
126
|
-
* - Local development (beautiful, readable output)
|
|
127
|
-
* - Debugging (see trace hierarchy at a glance)
|
|
128
|
-
* - Progressive development (verify spans look correct)
|
|
129
|
-
*
|
|
130
|
-
* Features:
|
|
131
|
-
* - Colorized status (✓ green, ✗ red)
|
|
132
|
-
* - Duration color coding (fast=green, medium=yellow, slow=red)
|
|
133
|
-
* - Hierarchical tree view showing parent-child relationships
|
|
134
|
-
* - Attribute display with truncation
|
|
135
|
-
* - Error message highlighting
|
|
136
|
-
*
|
|
137
|
-
* Note: Not recommended for production use.
|
|
138
|
-
*
|
|
139
|
-
* @example Basic usage
|
|
140
|
-
* ```typescript
|
|
141
|
-
* import { init } from 'autotel'
|
|
142
|
-
*
|
|
143
|
-
* init({
|
|
144
|
-
* service: 'my-app',
|
|
145
|
-
* debug: 'pretty', // Uses PrettyConsoleExporter
|
|
146
|
-
* })
|
|
147
|
-
* ```
|
|
148
|
-
*
|
|
149
|
-
* @example With custom options
|
|
150
|
-
* ```typescript
|
|
151
|
-
* import { PrettyConsoleExporter } from 'autotel/exporters'
|
|
152
|
-
*
|
|
153
|
-
* const exporter = new PrettyConsoleExporter({
|
|
154
|
-
* colors: true, // Auto-detect TTY by default
|
|
155
|
-
* showAttributes: true, // Show span attributes
|
|
156
|
-
* maxValueLength: 50, // Truncate long values
|
|
157
|
-
* hideAttributes: ['http.user_agent'], // Hide specific attributes
|
|
158
|
-
* showTraceId: false, // Show trace ID header
|
|
159
|
-
* })
|
|
160
|
-
* ```
|
|
161
|
-
*/
|
|
162
|
-
export {
|
|
163
|
-
PrettyConsoleExporter,
|
|
164
|
-
type PrettyConsoleExporterOptions,
|
|
165
|
-
} from './pretty-console-exporter';
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for FilteringSpanProcessor
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
FilteringSpanProcessor,
|
|
8
|
-
type SpanFilterPredicate,
|
|
9
|
-
} from './filtering-span-processor';
|
|
10
|
-
import type {
|
|
11
|
-
SpanProcessor,
|
|
12
|
-
ReadableSpan,
|
|
13
|
-
} from '@opentelemetry/sdk-trace-base';
|
|
14
|
-
import type { Context } from '@opentelemetry/api';
|
|
15
|
-
import type { Span } from '@opentelemetry/sdk-trace-base';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Mock span processor to capture forwarded spans
|
|
19
|
-
*/
|
|
20
|
-
class MockSpanProcessor implements SpanProcessor {
|
|
21
|
-
public startedSpans: Span[] = [];
|
|
22
|
-
public endedSpans: ReadableSpan[] = [];
|
|
23
|
-
public flushed = false;
|
|
24
|
-
public shutdownCalled = false;
|
|
25
|
-
|
|
26
|
-
onStart(span: Span): void {
|
|
27
|
-
this.startedSpans.push(span);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
onEnd(span: ReadableSpan): void {
|
|
31
|
-
this.endedSpans.push(span);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async forceFlush(): Promise<void> {
|
|
35
|
-
this.flushed = true;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async shutdown(): Promise<void> {
|
|
39
|
-
this.shutdownCalled = true;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
reset(): void {
|
|
43
|
-
this.startedSpans = [];
|
|
44
|
-
this.endedSpans = [];
|
|
45
|
-
this.flushed = false;
|
|
46
|
-
this.shutdownCalled = false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Create a mock ReadableSpan for testing
|
|
52
|
-
*/
|
|
53
|
-
function createMockSpan(
|
|
54
|
-
name: string,
|
|
55
|
-
instrumentationScopeName = 'test-scope',
|
|
56
|
-
attributes: Record<string, unknown> = {},
|
|
57
|
-
): ReadableSpan {
|
|
58
|
-
return {
|
|
59
|
-
name,
|
|
60
|
-
attributes,
|
|
61
|
-
instrumentationScope: {
|
|
62
|
-
name: instrumentationScopeName,
|
|
63
|
-
version: '1.0.0',
|
|
64
|
-
},
|
|
65
|
-
spanContext: () => ({
|
|
66
|
-
traceId: 'trace123',
|
|
67
|
-
spanId: 'span123',
|
|
68
|
-
traceFlags: 1,
|
|
69
|
-
}),
|
|
70
|
-
duration: [0, 1_000_000], // 1ms
|
|
71
|
-
status: { code: 0 },
|
|
72
|
-
kind: 0,
|
|
73
|
-
startTime: [0, 0],
|
|
74
|
-
endTime: [0, 1_000_000],
|
|
75
|
-
ended: true,
|
|
76
|
-
resource: {
|
|
77
|
-
attributes: {},
|
|
78
|
-
merge: () => ({}) as never,
|
|
79
|
-
},
|
|
80
|
-
droppedAttributesCount: 0,
|
|
81
|
-
droppedEventsCount: 0,
|
|
82
|
-
droppedLinksCount: 0,
|
|
83
|
-
events: [],
|
|
84
|
-
links: [],
|
|
85
|
-
parentSpanId: undefined,
|
|
86
|
-
} as unknown as ReadableSpan;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
describe('FilteringSpanProcessor', () => {
|
|
90
|
-
let mockProcessor: MockSpanProcessor;
|
|
91
|
-
|
|
92
|
-
beforeEach(() => {
|
|
93
|
-
mockProcessor = new MockSpanProcessor();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
describe('basic filtering', () => {
|
|
97
|
-
it('should forward spans that pass the filter', () => {
|
|
98
|
-
const filter: SpanFilterPredicate = (span) => span.name !== 'drop-me';
|
|
99
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
100
|
-
filter,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const keepSpan = createMockSpan('keep-me');
|
|
104
|
-
filteringProcessor.onEnd(keepSpan);
|
|
105
|
-
|
|
106
|
-
expect(mockProcessor.endedSpans).toHaveLength(1);
|
|
107
|
-
expect(mockProcessor.endedSpans[0]).toBe(keepSpan);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should drop spans that fail the filter', () => {
|
|
111
|
-
const filter: SpanFilterPredicate = (span) => span.name !== 'drop-me';
|
|
112
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
113
|
-
filter,
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
const dropSpan = createMockSpan('drop-me');
|
|
117
|
-
filteringProcessor.onEnd(dropSpan);
|
|
118
|
-
|
|
119
|
-
expect(mockProcessor.endedSpans).toHaveLength(0);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('should always forward onStart (no filtering)', () => {
|
|
123
|
-
const filter: SpanFilterPredicate = () => false; // Drop everything
|
|
124
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
125
|
-
filter,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const mockSpan = {} as Span;
|
|
129
|
-
const mockContext = {} as Context;
|
|
130
|
-
filteringProcessor.onStart(mockSpan, mockContext);
|
|
131
|
-
|
|
132
|
-
expect(mockProcessor.startedSpans).toHaveLength(1);
|
|
133
|
-
expect(mockProcessor.startedSpans[0]).toBe(mockSpan);
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('instrumentation scope filtering (primary use case)', () => {
|
|
138
|
-
it('should filter out spans by instrumentation scope name', () => {
|
|
139
|
-
const filter: SpanFilterPredicate = (span) =>
|
|
140
|
-
span.instrumentationScope.name !== 'next.js';
|
|
141
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
142
|
-
filter,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
const nextSpan = createMockSpan('GET /api/users', 'next.js');
|
|
146
|
-
const autotelSpan = createMockSpan('createUser', 'autotel');
|
|
147
|
-
|
|
148
|
-
filteringProcessor.onEnd(nextSpan);
|
|
149
|
-
filteringProcessor.onEnd(autotelSpan);
|
|
150
|
-
|
|
151
|
-
expect(mockProcessor.endedSpans).toHaveLength(1);
|
|
152
|
-
expect(mockProcessor.endedSpans[0].instrumentationScope.name).toBe(
|
|
153
|
-
'autotel',
|
|
154
|
-
);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should support multiple instrumentation scope exclusions', () => {
|
|
158
|
-
const excludedScopes = new Set([
|
|
159
|
-
'next.js',
|
|
160
|
-
'@opentelemetry/instrumentation-http',
|
|
161
|
-
]);
|
|
162
|
-
const filter: SpanFilterPredicate = (span) =>
|
|
163
|
-
!excludedScopes.has(span.instrumentationScope.name);
|
|
164
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
165
|
-
filter,
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
filteringProcessor.onEnd(createMockSpan('span1', 'next.js'));
|
|
169
|
-
filteringProcessor.onEnd(
|
|
170
|
-
createMockSpan('span2', '@opentelemetry/instrumentation-http'),
|
|
171
|
-
);
|
|
172
|
-
filteringProcessor.onEnd(createMockSpan('span3', 'autotel'));
|
|
173
|
-
|
|
174
|
-
expect(mockProcessor.endedSpans).toHaveLength(1);
|
|
175
|
-
expect(mockProcessor.endedSpans[0].name).toBe('span3');
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('error handling', () => {
|
|
180
|
-
it('should forward span if filter throws (fail-open)', () => {
|
|
181
|
-
const filter: SpanFilterPredicate = () => {
|
|
182
|
-
throw new Error('Filter error');
|
|
183
|
-
};
|
|
184
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
185
|
-
filter,
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
const span = createMockSpan('test-span');
|
|
189
|
-
filteringProcessor.onEnd(span);
|
|
190
|
-
|
|
191
|
-
// Span should be forwarded despite filter error
|
|
192
|
-
expect(mockProcessor.endedSpans).toHaveLength(1);
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
describe('lifecycle methods', () => {
|
|
197
|
-
it('should forward forceFlush to wrapped processor', async () => {
|
|
198
|
-
const filter: SpanFilterPredicate = () => true;
|
|
199
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
200
|
-
filter,
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
await filteringProcessor.forceFlush();
|
|
204
|
-
|
|
205
|
-
expect(mockProcessor.flushed).toBe(true);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
it('should forward shutdown to wrapped processor', async () => {
|
|
209
|
-
const filter: SpanFilterPredicate = () => true;
|
|
210
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
211
|
-
filter,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
await filteringProcessor.shutdown();
|
|
215
|
-
|
|
216
|
-
expect(mockProcessor.shutdownCalled).toBe(true);
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
describe('complex filtering scenarios', () => {
|
|
221
|
-
it('should support attribute-based filtering', () => {
|
|
222
|
-
const filter: SpanFilterPredicate = (span) =>
|
|
223
|
-
span.attributes['http.route'] !== '/health';
|
|
224
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
225
|
-
filter,
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
filteringProcessor.onEnd(
|
|
229
|
-
createMockSpan('GET /health', 'http', { 'http.route': '/health' }),
|
|
230
|
-
);
|
|
231
|
-
filteringProcessor.onEnd(
|
|
232
|
-
createMockSpan('GET /api/users', 'http', {
|
|
233
|
-
'http.route': '/api/users',
|
|
234
|
-
}),
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
expect(mockProcessor.endedSpans).toHaveLength(1);
|
|
238
|
-
expect(mockProcessor.endedSpans[0].name).toBe('GET /api/users');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('should support span name pattern matching', () => {
|
|
242
|
-
const filter: SpanFilterPredicate = (span) =>
|
|
243
|
-
!span.name.startsWith('internal:');
|
|
244
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
245
|
-
filter,
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
filteringProcessor.onEnd(createMockSpan('internal:bootstrap'));
|
|
249
|
-
filteringProcessor.onEnd(createMockSpan('internal:middleware'));
|
|
250
|
-
filteringProcessor.onEnd(createMockSpan('createUser'));
|
|
251
|
-
|
|
252
|
-
expect(mockProcessor.endedSpans).toHaveLength(1);
|
|
253
|
-
expect(mockProcessor.endedSpans[0].name).toBe('createUser');
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it('should support combining multiple filter conditions', () => {
|
|
257
|
-
const filter: SpanFilterPredicate = (span) => {
|
|
258
|
-
// Drop Next.js spans
|
|
259
|
-
if (span.instrumentationScope.name === 'next.js') return false;
|
|
260
|
-
// Drop health check spans
|
|
261
|
-
if (span.name.includes('/health')) return false;
|
|
262
|
-
// Keep everything else
|
|
263
|
-
return true;
|
|
264
|
-
};
|
|
265
|
-
const filteringProcessor = new FilteringSpanProcessor(mockProcessor, {
|
|
266
|
-
filter,
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
filteringProcessor.onEnd(createMockSpan('GET /api/users', 'next.js'));
|
|
270
|
-
filteringProcessor.onEnd(createMockSpan('GET /health', 'http'));
|
|
271
|
-
filteringProcessor.onEnd(createMockSpan('createUser', 'autotel'));
|
|
272
|
-
filteringProcessor.onEnd(createMockSpan('GET /api/orders', 'http'));
|
|
273
|
-
|
|
274
|
-
expect(mockProcessor.endedSpans).toHaveLength(2);
|
|
275
|
-
expect(mockProcessor.endedSpans.map((s) => s.name)).toEqual([
|
|
276
|
-
'createUser',
|
|
277
|
-
'GET /api/orders',
|
|
278
|
-
]);
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
});
|