autotel-edge 3.16.13 → 3.16.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config-0FktBGyj.js +290 -0
- package/dist/config-0FktBGyj.js.map +1 -0
- package/dist/events.d.ts +42 -43
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +144 -137
- package/dist/events.js.map +1 -1
- package/dist/execution-logger-BWlya70r.d.ts +137 -0
- package/dist/execution-logger-BWlya70r.d.ts.map +1 -0
- package/dist/execution-logger-CoxSsBmU.js +247 -0
- package/dist/execution-logger-CoxSsBmU.js.map +1 -0
- package/dist/index.d.ts +192 -276
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +930 -1060
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +122 -136
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +783 -774
- package/dist/logger.js.map +1 -1
- package/dist/parse-error.d.ts +12 -10
- package/dist/parse-error.d.ts.map +1 -0
- package/dist/parse-error.js +55 -2
- package/dist/parse-error.js.map +1 -1
- package/dist/sampling.d.ts +51 -76
- package/dist/sampling.d.ts.map +1 -0
- package/dist/sampling.js +155 -90
- package/dist/sampling.js.map +1 -1
- package/dist/testing.d.ts +1 -2
- package/dist/testing.js +1 -3
- package/dist/types-HCbsjZzp.d.ts +214 -0
- package/dist/types-HCbsjZzp.d.ts.map +1 -0
- package/package.json +6 -6
- package/src/core/buffer.ts +4 -3
- package/src/core/provider.context.test.ts +55 -0
- package/src/core/provider.ts +18 -1
- package/binding.gyp +0 -9
- package/dist/chunk-AL7ZD64M.js +0 -291
- package/dist/chunk-AL7ZD64M.js.map +0 -1
- package/dist/chunk-INQQQVXN.js +0 -310
- package/dist/chunk-INQQQVXN.js.map +0 -1
- package/dist/chunk-M7Z4P5MC.js +0 -64
- package/dist/chunk-M7Z4P5MC.js.map +0 -1
- package/dist/execution-logger-77TRRoWn.d.ts +0 -84
- package/dist/testing.js.map +0 -1
- package/dist/types-uulICZo7.d.ts +0 -216
- package/index.js +0 -1
package/dist/sampling.js
CHANGED
|
@@ -1,108 +1,173 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/sampling/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create an adaptive tail sampler
|
|
4
|
+
*
|
|
5
|
+
* This sampler ensures you never miss critical issues while keeping costs down:
|
|
6
|
+
* - Always traces errors (status code = ERROR)
|
|
7
|
+
* - Always traces slow requests (duration >= slowThresholdMs)
|
|
8
|
+
* - Uses baseline sample rate for successful fast requests
|
|
9
|
+
*
|
|
10
|
+
* **Recommended for production use.**
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const tailSampler = createAdaptiveTailSampler({
|
|
15
|
+
* baselineSampleRate: 0.1, // 10% of normal requests
|
|
16
|
+
* slowThresholdMs: 1000, // Requests > 1s are "slow"
|
|
17
|
+
* alwaysSampleErrors: true, // Always trace errors
|
|
18
|
+
* alwaysSampleSlow: true // Always trace slow requests
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
2
22
|
function createAdaptiveTailSampler(options = {}) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
if (alwaysSampleSlow) {
|
|
21
|
-
const duration = getDurationMs(localRootSpan);
|
|
22
|
-
if (duration >= slowThresholdMs) {
|
|
23
|
-
return true;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return baselineDecision;
|
|
27
|
-
};
|
|
23
|
+
const baselineSampleRate = options.baselineSampleRate ?? .1;
|
|
24
|
+
const slowThresholdMs = options.slowThresholdMs ?? 1e3;
|
|
25
|
+
const alwaysSampleErrors = options.alwaysSampleErrors ?? true;
|
|
26
|
+
const alwaysSampleSlow = options.alwaysSampleSlow ?? true;
|
|
27
|
+
if (baselineSampleRate < 0 || baselineSampleRate > 1) throw new Error("Baseline sample rate must be between 0 and 1");
|
|
28
|
+
const baselineDecisions = /* @__PURE__ */ new Map();
|
|
29
|
+
return (traceInfo) => {
|
|
30
|
+
const { traceId, localRootSpan } = traceInfo;
|
|
31
|
+
if (!baselineDecisions.has(traceId)) baselineDecisions.set(traceId, Math.random() < baselineSampleRate);
|
|
32
|
+
const baselineDecision = baselineDecisions.get(traceId);
|
|
33
|
+
if (alwaysSampleErrors && localRootSpan.status.code === 2) return true;
|
|
34
|
+
if (alwaysSampleSlow) {
|
|
35
|
+
if (getDurationMs(localRootSpan) >= slowThresholdMs) return true;
|
|
36
|
+
}
|
|
37
|
+
return baselineDecision;
|
|
38
|
+
};
|
|
28
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a simple random tail sampler
|
|
42
|
+
*
|
|
43
|
+
* Samples a fixed percentage of all traces regardless of outcome.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const tailSampler = createRandomTailSampler(0.1) // 10% of all requests
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
29
50
|
function createRandomTailSampler(sampleRate) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
decisions.set(traceId, Math.random() < sampleRate);
|
|
38
|
-
}
|
|
39
|
-
return decisions.get(traceId);
|
|
40
|
-
};
|
|
51
|
+
if (sampleRate < 0 || sampleRate > 1) throw new Error("Sample rate must be between 0 and 1");
|
|
52
|
+
const decisions = /* @__PURE__ */ new Map();
|
|
53
|
+
return (traceInfo) => {
|
|
54
|
+
const { traceId } = traceInfo;
|
|
55
|
+
if (!decisions.has(traceId)) decisions.set(traceId, Math.random() < sampleRate);
|
|
56
|
+
return decisions.get(traceId);
|
|
57
|
+
};
|
|
41
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Create a tail sampler that keeps all errors
|
|
61
|
+
*
|
|
62
|
+
* Useful for debugging - captures all failures while dropping successful requests.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const tailSampler = createErrorOnlyTailSampler()
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
42
69
|
function createErrorOnlyTailSampler() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
70
|
+
return (traceInfo) => {
|
|
71
|
+
return traceInfo.localRootSpan.status.code === 2;
|
|
72
|
+
};
|
|
46
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Create a tail sampler that keeps slow requests
|
|
76
|
+
*
|
|
77
|
+
* Useful for performance debugging - captures slow requests while dropping fast ones.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* const tailSampler = createSlowOnlyTailSampler(1000) // Keep requests > 1s
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
47
84
|
function createSlowOnlyTailSampler(thresholdMs) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
85
|
+
return (traceInfo) => {
|
|
86
|
+
return getDurationMs(traceInfo.localRootSpan) >= thresholdMs;
|
|
87
|
+
};
|
|
52
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Combine multiple tail samplers with OR logic
|
|
91
|
+
*
|
|
92
|
+
* Keeps a trace if ANY sampler returns true.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const tailSampler = combineTailSamplers(
|
|
97
|
+
* createErrorOnlyTailSampler(),
|
|
98
|
+
* createSlowOnlyTailSampler(1000),
|
|
99
|
+
* createRandomTailSampler(0.01) // 1% baseline
|
|
100
|
+
* )
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
53
103
|
function combineTailSamplers(...samplers) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
return samplers.some((sampler) => sampler(traceInfo));
|
|
59
|
-
};
|
|
104
|
+
if (samplers.length === 0) throw new Error("combineTailSamplers requires at least one sampler");
|
|
105
|
+
return (traceInfo) => {
|
|
106
|
+
return samplers.some((sampler) => sampler(traceInfo));
|
|
107
|
+
};
|
|
60
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Create a tail sampler based on custom predicate
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // Keep traces with specific attributes
|
|
115
|
+
* const tailSampler = createCustomTailSampler((trace) => {
|
|
116
|
+
* const attrs = trace.localRootSpan.attributes
|
|
117
|
+
* return attrs['user.id'] === 'vip_123'
|
|
118
|
+
* })
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
61
121
|
function createCustomTailSampler(predicate) {
|
|
62
|
-
|
|
122
|
+
return predicate;
|
|
63
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Helper: Get span duration in milliseconds
|
|
126
|
+
*/
|
|
64
127
|
function getDurationMs(span) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return end - start;
|
|
128
|
+
const start = span.startTime[0] * 1e3 + span.startTime[1] / 1e6;
|
|
129
|
+
return span.endTime[0] * 1e3 + span.endTime[1] / 1e6 - start;
|
|
68
130
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Common presets for quick setup
|
|
133
|
+
*/
|
|
134
|
+
const SamplingPresets = {
|
|
135
|
+
/**
|
|
136
|
+
* Production: 10% baseline, all errors, all slow (>1s)
|
|
137
|
+
* Recommended for most production workloads
|
|
138
|
+
*/
|
|
139
|
+
production: () => createAdaptiveTailSampler({
|
|
140
|
+
baselineSampleRate: .1,
|
|
141
|
+
slowThresholdMs: 1e3
|
|
142
|
+
}),
|
|
143
|
+
/**
|
|
144
|
+
* High-traffic: 1% baseline, all errors, all slow (>2s)
|
|
145
|
+
* For high-volume services where cost is a concern
|
|
146
|
+
*/
|
|
147
|
+
highTraffic: () => createAdaptiveTailSampler({
|
|
148
|
+
baselineSampleRate: .01,
|
|
149
|
+
slowThresholdMs: 2e3
|
|
150
|
+
}),
|
|
151
|
+
/**
|
|
152
|
+
* Debugging: All errors, all slow (>500ms), 50% baseline
|
|
153
|
+
* For active debugging sessions
|
|
154
|
+
*/
|
|
155
|
+
debugging: () => createAdaptiveTailSampler({
|
|
156
|
+
baselineSampleRate: .5,
|
|
157
|
+
slowThresholdMs: 500
|
|
158
|
+
}),
|
|
159
|
+
/**
|
|
160
|
+
* Development: 100% sampling
|
|
161
|
+
* For local development and testing
|
|
162
|
+
*/
|
|
163
|
+
development: () => () => true,
|
|
164
|
+
/**
|
|
165
|
+
* Errors only: Capture all failures, drop all successes
|
|
166
|
+
* For error-focused monitoring
|
|
167
|
+
*/
|
|
168
|
+
errorsOnly: () => createErrorOnlyTailSampler()
|
|
104
169
|
};
|
|
105
170
|
|
|
171
|
+
//#endregion
|
|
106
172
|
export { SamplingPresets, combineTailSamplers, createAdaptiveTailSampler, createCustomTailSampler, createErrorOnlyTailSampler, createRandomTailSampler, createSlowOnlyTailSampler };
|
|
107
|
-
//# sourceMappingURL=sampling.js.map
|
|
108
173
|
//# sourceMappingURL=sampling.js.map
|
package/dist/sampling.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/sampling/index.ts"],"names":[],"mappings":"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","file":"sampling.js","sourcesContent":["/**\n * Sampling strategies for autotel-edge\n *\n * Provides intelligent sampling to reduce telemetry costs while capturing critical data.\n *\n * Key strategies:\n * - Always trace errors and slow requests (critical for debugging)\n * - Adaptive sampling based on load\n * - Baseline random sampling for normal traffic\n *\n * @example\n * ```typescript\n * import { createAdaptiveTailSampler } from 'autotel-edge/sampling'\n *\n * export default instrument(handler, {\n * sampling: {\n * tailSampler: createAdaptiveTailSampler({\n * baselineSampleRate: 0.1, // 10% of normal requests\n * slowThresholdMs: 1000, // Requests > 1s are \"slow\"\n * })\n * }\n * })\n * ```\n */\n\nimport type { TailSampleFn, LocalTrace } from '../types';\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\n\nexport interface AdaptiveSamplerOptions {\n /**\n * Baseline sample rate for normal (successful, fast) requests\n * @default 0.1 (10%)\n */\n baselineSampleRate?: number;\n\n /**\n * Threshold in milliseconds for \"slow\" requests\n * Requests taking longer than this will always be trace\n * @default 1000ms\n */\n slowThresholdMs?: number;\n\n /**\n * Always trace error spans\n * @default true\n */\n alwaysSampleErrors?: boolean;\n\n /**\n * Always trace slow spans\n * @default true\n */\n alwaysSampleSlow?: boolean;\n}\n\n/**\n * Create an adaptive tail sampler\n *\n * This sampler ensures you never miss critical issues while keeping costs down:\n * - Always traces errors (status code = ERROR)\n * - Always traces slow requests (duration >= slowThresholdMs)\n * - Uses baseline sample rate for successful fast requests\n *\n * **Recommended for production use.**\n *\n * @example\n * ```typescript\n * const tailSampler = createAdaptiveTailSampler({\n * baselineSampleRate: 0.1, // 10% of normal requests\n * slowThresholdMs: 1000, // Requests > 1s are \"slow\"\n * alwaysSampleErrors: true, // Always trace errors\n * alwaysSampleSlow: true // Always trace slow requests\n * })\n * ```\n */\nexport function createAdaptiveTailSampler(\n options: AdaptiveSamplerOptions = {},\n): TailSampleFn {\n const baselineSampleRate = options.baselineSampleRate ?? 0.1;\n const slowThresholdMs = options.slowThresholdMs ?? 1000;\n const alwaysSampleErrors = options.alwaysSampleErrors ?? true;\n const alwaysSampleSlow = options.alwaysSampleSlow ?? true;\n\n if (baselineSampleRate < 0 || baselineSampleRate > 1) {\n throw new Error('Baseline sample rate must be between 0 and 1');\n }\n\n // Store baseline decisions using trace ID\n const baselineDecisions = new Map<string, boolean>();\n\n return (traceInfo: LocalTrace): boolean => {\n const { traceId, localRootSpan } = traceInfo;\n\n // Get or create baseline decision for this trace\n if (!baselineDecisions.has(traceId)) {\n baselineDecisions.set(traceId, Math.random() < baselineSampleRate);\n }\n const baselineDecision = baselineDecisions.get(traceId)!;\n\n // Always keep errors (SpanStatusCode.ERROR = 2)\n if (alwaysSampleErrors && localRootSpan.status.code === 2) {\n return true;\n }\n\n // Always keep slow requests\n if (alwaysSampleSlow) {\n const duration = getDurationMs(localRootSpan);\n if (duration >= slowThresholdMs) {\n return true;\n }\n }\n\n // Otherwise, use baseline decision\n return baselineDecision;\n };\n}\n\n/**\n * Create a simple random tail sampler\n *\n * Samples a fixed percentage of all traces regardless of outcome.\n *\n * @example\n * ```typescript\n * const tailSampler = createRandomTailSampler(0.1) // 10% of all requests\n * ```\n */\nexport function createRandomTailSampler(sampleRate: number): TailSampleFn {\n if (sampleRate < 0 || sampleRate > 1) {\n throw new Error('Sample rate must be between 0 and 1');\n }\n\n const decisions = new Map<string, boolean>();\n\n return (traceInfo: LocalTrace): boolean => {\n const { traceId } = traceInfo;\n\n if (!decisions.has(traceId)) {\n decisions.set(traceId, Math.random() < sampleRate);\n }\n\n return decisions.get(traceId)!;\n };\n}\n\n/**\n * Create a tail sampler that keeps all errors\n *\n * Useful for debugging - captures all failures while dropping successful requests.\n *\n * @example\n * ```typescript\n * const tailSampler = createErrorOnlyTailSampler()\n * ```\n */\nexport function createErrorOnlyTailSampler(): TailSampleFn {\n return (traceInfo: LocalTrace): boolean => {\n // SpanStatusCode.ERROR = 2\n return traceInfo.localRootSpan.status.code === 2;\n };\n}\n\n/**\n * Create a tail sampler that keeps slow requests\n *\n * Useful for performance debugging - captures slow requests while dropping fast ones.\n *\n * @example\n * ```typescript\n * const tailSampler = createSlowOnlyTailSampler(1000) // Keep requests > 1s\n * ```\n */\nexport function createSlowOnlyTailSampler(thresholdMs: number): TailSampleFn {\n return (traceInfo: LocalTrace): boolean => {\n const duration = getDurationMs(traceInfo.localRootSpan);\n return duration >= thresholdMs;\n };\n}\n\n/**\n * Combine multiple tail samplers with OR logic\n *\n * Keeps a trace if ANY sampler returns true.\n *\n * @example\n * ```typescript\n * const tailSampler = combineTailSamplers(\n * createErrorOnlyTailSampler(),\n * createSlowOnlyTailSampler(1000),\n * createRandomTailSampler(0.01) // 1% baseline\n * )\n * ```\n */\nexport function combineTailSamplers(...samplers: TailSampleFn[]): TailSampleFn {\n if (samplers.length === 0) {\n throw new Error('combineTailSamplers requires at least one sampler');\n }\n\n return (traceInfo: LocalTrace): boolean => {\n return samplers.some((sampler) => sampler(traceInfo));\n };\n}\n\n/**\n * Create a tail sampler based on custom predicate\n *\n * @example\n * ```typescript\n * // Keep traces with specific attributes\n * const tailSampler = createCustomTailSampler((trace) => {\n * const attrs = trace.localRootSpan.attributes\n * return attrs['user.id'] === 'vip_123'\n * })\n * ```\n */\nexport function createCustomTailSampler(\n predicate: (traceInfo: LocalTrace) => boolean,\n): TailSampleFn {\n return predicate;\n}\n\n/**\n * Helper: Get span duration in milliseconds\n */\nfunction getDurationMs(span: ReadableSpan): number {\n const start = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;\n const end = span.endTime[0] * 1000 + span.endTime[1] / 1_000_000;\n return end - start;\n}\n\n/**\n * Common presets for quick setup\n */\nexport const SamplingPresets = {\n /**\n * Production: 10% baseline, all errors, all slow (>1s)\n * Recommended for most production workloads\n */\n production: (): TailSampleFn =>\n createAdaptiveTailSampler({\n baselineSampleRate: 0.1,\n slowThresholdMs: 1000,\n }),\n\n /**\n * High-traffic: 1% baseline, all errors, all slow (>2s)\n * For high-volume services where cost is a concern\n */\n highTraffic: (): TailSampleFn =>\n createAdaptiveTailSampler({\n baselineSampleRate: 0.01,\n slowThresholdMs: 2000,\n }),\n\n /**\n * Debugging: All errors, all slow (>500ms), 50% baseline\n * For active debugging sessions\n */\n debugging: (): TailSampleFn =>\n createAdaptiveTailSampler({\n baselineSampleRate: 0.5,\n slowThresholdMs: 500,\n }),\n\n /**\n * Development: 100% sampling\n * For local development and testing\n */\n development: (): TailSampleFn => () => true,\n\n /**\n * Errors only: Capture all failures, drop all successes\n * For error-focused monitoring\n */\n errorsOnly: (): TailSampleFn => createErrorOnlyTailSampler(),\n};\n"]}
|
|
1
|
+
{"version":3,"file":"sampling.js","names":[],"sources":["../src/sampling/index.ts"],"sourcesContent":["/**\n * Sampling strategies for autotel-edge\n *\n * Provides intelligent sampling to reduce telemetry costs while capturing critical data.\n *\n * Key strategies:\n * - Always trace errors and slow requests (critical for debugging)\n * - Adaptive sampling based on load\n * - Baseline random sampling for normal traffic\n *\n * @example\n * ```typescript\n * import { createAdaptiveTailSampler } from 'autotel-edge/sampling'\n *\n * export default instrument(handler, {\n * sampling: {\n * tailSampler: createAdaptiveTailSampler({\n * baselineSampleRate: 0.1, // 10% of normal requests\n * slowThresholdMs: 1000, // Requests > 1s are \"slow\"\n * })\n * }\n * })\n * ```\n */\n\nimport type { TailSampleFn, LocalTrace } from '../types';\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\n\nexport interface AdaptiveSamplerOptions {\n /**\n * Baseline sample rate for normal (successful, fast) requests\n * @default 0.1 (10%)\n */\n baselineSampleRate?: number;\n\n /**\n * Threshold in milliseconds for \"slow\" requests\n * Requests taking longer than this will always be trace\n * @default 1000ms\n */\n slowThresholdMs?: number;\n\n /**\n * Always trace error spans\n * @default true\n */\n alwaysSampleErrors?: boolean;\n\n /**\n * Always trace slow spans\n * @default true\n */\n alwaysSampleSlow?: boolean;\n}\n\n/**\n * Create an adaptive tail sampler\n *\n * This sampler ensures you never miss critical issues while keeping costs down:\n * - Always traces errors (status code = ERROR)\n * - Always traces slow requests (duration >= slowThresholdMs)\n * - Uses baseline sample rate for successful fast requests\n *\n * **Recommended for production use.**\n *\n * @example\n * ```typescript\n * const tailSampler = createAdaptiveTailSampler({\n * baselineSampleRate: 0.1, // 10% of normal requests\n * slowThresholdMs: 1000, // Requests > 1s are \"slow\"\n * alwaysSampleErrors: true, // Always trace errors\n * alwaysSampleSlow: true // Always trace slow requests\n * })\n * ```\n */\nexport function createAdaptiveTailSampler(\n options: AdaptiveSamplerOptions = {},\n): TailSampleFn {\n const baselineSampleRate = options.baselineSampleRate ?? 0.1;\n const slowThresholdMs = options.slowThresholdMs ?? 1000;\n const alwaysSampleErrors = options.alwaysSampleErrors ?? true;\n const alwaysSampleSlow = options.alwaysSampleSlow ?? true;\n\n if (baselineSampleRate < 0 || baselineSampleRate > 1) {\n throw new Error('Baseline sample rate must be between 0 and 1');\n }\n\n // Store baseline decisions using trace ID\n const baselineDecisions = new Map<string, boolean>();\n\n return (traceInfo: LocalTrace): boolean => {\n const { traceId, localRootSpan } = traceInfo;\n\n // Get or create baseline decision for this trace\n if (!baselineDecisions.has(traceId)) {\n baselineDecisions.set(traceId, Math.random() < baselineSampleRate);\n }\n const baselineDecision = baselineDecisions.get(traceId)!;\n\n // Always keep errors (SpanStatusCode.ERROR = 2)\n if (alwaysSampleErrors && localRootSpan.status.code === 2) {\n return true;\n }\n\n // Always keep slow requests\n if (alwaysSampleSlow) {\n const duration = getDurationMs(localRootSpan);\n if (duration >= slowThresholdMs) {\n return true;\n }\n }\n\n // Otherwise, use baseline decision\n return baselineDecision;\n };\n}\n\n/**\n * Create a simple random tail sampler\n *\n * Samples a fixed percentage of all traces regardless of outcome.\n *\n * @example\n * ```typescript\n * const tailSampler = createRandomTailSampler(0.1) // 10% of all requests\n * ```\n */\nexport function createRandomTailSampler(sampleRate: number): TailSampleFn {\n if (sampleRate < 0 || sampleRate > 1) {\n throw new Error('Sample rate must be between 0 and 1');\n }\n\n const decisions = new Map<string, boolean>();\n\n return (traceInfo: LocalTrace): boolean => {\n const { traceId } = traceInfo;\n\n if (!decisions.has(traceId)) {\n decisions.set(traceId, Math.random() < sampleRate);\n }\n\n return decisions.get(traceId)!;\n };\n}\n\n/**\n * Create a tail sampler that keeps all errors\n *\n * Useful for debugging - captures all failures while dropping successful requests.\n *\n * @example\n * ```typescript\n * const tailSampler = createErrorOnlyTailSampler()\n * ```\n */\nexport function createErrorOnlyTailSampler(): TailSampleFn {\n return (traceInfo: LocalTrace): boolean => {\n // SpanStatusCode.ERROR = 2\n return traceInfo.localRootSpan.status.code === 2;\n };\n}\n\n/**\n * Create a tail sampler that keeps slow requests\n *\n * Useful for performance debugging - captures slow requests while dropping fast ones.\n *\n * @example\n * ```typescript\n * const tailSampler = createSlowOnlyTailSampler(1000) // Keep requests > 1s\n * ```\n */\nexport function createSlowOnlyTailSampler(thresholdMs: number): TailSampleFn {\n return (traceInfo: LocalTrace): boolean => {\n const duration = getDurationMs(traceInfo.localRootSpan);\n return duration >= thresholdMs;\n };\n}\n\n/**\n * Combine multiple tail samplers with OR logic\n *\n * Keeps a trace if ANY sampler returns true.\n *\n * @example\n * ```typescript\n * const tailSampler = combineTailSamplers(\n * createErrorOnlyTailSampler(),\n * createSlowOnlyTailSampler(1000),\n * createRandomTailSampler(0.01) // 1% baseline\n * )\n * ```\n */\nexport function combineTailSamplers(...samplers: TailSampleFn[]): TailSampleFn {\n if (samplers.length === 0) {\n throw new Error('combineTailSamplers requires at least one sampler');\n }\n\n return (traceInfo: LocalTrace): boolean => {\n return samplers.some((sampler) => sampler(traceInfo));\n };\n}\n\n/**\n * Create a tail sampler based on custom predicate\n *\n * @example\n * ```typescript\n * // Keep traces with specific attributes\n * const tailSampler = createCustomTailSampler((trace) => {\n * const attrs = trace.localRootSpan.attributes\n * return attrs['user.id'] === 'vip_123'\n * })\n * ```\n */\nexport function createCustomTailSampler(\n predicate: (traceInfo: LocalTrace) => boolean,\n): TailSampleFn {\n return predicate;\n}\n\n/**\n * Helper: Get span duration in milliseconds\n */\nfunction getDurationMs(span: ReadableSpan): number {\n const start = span.startTime[0] * 1000 + span.startTime[1] / 1_000_000;\n const end = span.endTime[0] * 1000 + span.endTime[1] / 1_000_000;\n return end - start;\n}\n\n/**\n * Common presets for quick setup\n */\nexport const SamplingPresets = {\n /**\n * Production: 10% baseline, all errors, all slow (>1s)\n * Recommended for most production workloads\n */\n production: (): TailSampleFn =>\n createAdaptiveTailSampler({\n baselineSampleRate: 0.1,\n slowThresholdMs: 1000,\n }),\n\n /**\n * High-traffic: 1% baseline, all errors, all slow (>2s)\n * For high-volume services where cost is a concern\n */\n highTraffic: (): TailSampleFn =>\n createAdaptiveTailSampler({\n baselineSampleRate: 0.01,\n slowThresholdMs: 2000,\n }),\n\n /**\n * Debugging: All errors, all slow (>500ms), 50% baseline\n * For active debugging sessions\n */\n debugging: (): TailSampleFn =>\n createAdaptiveTailSampler({\n baselineSampleRate: 0.5,\n slowThresholdMs: 500,\n }),\n\n /**\n * Development: 100% sampling\n * For local development and testing\n */\n development: (): TailSampleFn => () => true,\n\n /**\n * Errors only: Capture all failures, drop all successes\n * For error-focused monitoring\n */\n errorsOnly: (): TailSampleFn => createErrorOnlyTailSampler(),\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA2EA,SAAgB,0BACd,UAAkC,CAAC,GACrB;CACd,MAAM,qBAAqB,QAAQ,sBAAsB;CACzD,MAAM,kBAAkB,QAAQ,mBAAmB;CACnD,MAAM,qBAAqB,QAAQ,sBAAsB;CACzD,MAAM,mBAAmB,QAAQ,oBAAoB;CAErD,IAAI,qBAAqB,KAAK,qBAAqB,GACjD,MAAM,IAAI,MAAM,8CAA8C;CAIhE,MAAM,oCAAoB,IAAI,IAAqB;CAEnD,QAAQ,cAAmC;EACzC,MAAM,EAAE,SAAS,kBAAkB;EAGnC,IAAI,CAAC,kBAAkB,IAAI,OAAO,GAChC,kBAAkB,IAAI,SAAS,KAAK,OAAO,IAAI,kBAAkB;EAEnE,MAAM,mBAAmB,kBAAkB,IAAI,OAAO;EAGtD,IAAI,sBAAsB,cAAc,OAAO,SAAS,GACtD,OAAO;EAIT,IAAI,kBAEF;OADiB,cAAc,aACpB,KAAK,iBACd,OAAO;EACT;EAIF,OAAO;CACT;AACF;;;;;;;;;;;AAYA,SAAgB,wBAAwB,YAAkC;CACxE,IAAI,aAAa,KAAK,aAAa,GACjC,MAAM,IAAI,MAAM,qCAAqC;CAGvD,MAAM,4BAAY,IAAI,IAAqB;CAE3C,QAAQ,cAAmC;EACzC,MAAM,EAAE,YAAY;EAEpB,IAAI,CAAC,UAAU,IAAI,OAAO,GACxB,UAAU,IAAI,SAAS,KAAK,OAAO,IAAI,UAAU;EAGnD,OAAO,UAAU,IAAI,OAAO;CAC9B;AACF;;;;;;;;;;;AAYA,SAAgB,6BAA2C;CACzD,QAAQ,cAAmC;EAEzC,OAAO,UAAU,cAAc,OAAO,SAAS;CACjD;AACF;;;;;;;;;;;AAYA,SAAgB,0BAA0B,aAAmC;CAC3E,QAAQ,cAAmC;EAEzC,OADiB,cAAc,UAAU,aAC3B,KAAK;CACrB;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,oBAAoB,GAAG,UAAwC;CAC7E,IAAI,SAAS,WAAW,GACtB,MAAM,IAAI,MAAM,mDAAmD;CAGrE,QAAQ,cAAmC;EACzC,OAAO,SAAS,MAAM,YAAY,QAAQ,SAAS,CAAC;CACtD;AACF;;;;;;;;;;;;;AAcA,SAAgB,wBACd,WACc;CACd,OAAO;AACT;;;;AAKA,SAAS,cAAc,MAA4B;CACjD,MAAM,QAAQ,KAAK,UAAU,KAAK,MAAO,KAAK,UAAU,KAAK;CAE7D,OADY,KAAK,QAAQ,KAAK,MAAO,KAAK,QAAQ,KAAK,MAC1C;AACf;;;;AAKA,MAAa,kBAAkB;;;;;CAK7B,kBACE,0BAA0B;EACxB,oBAAoB;EACpB,iBAAiB;CACnB,CAAC;;;;;CAMH,mBACE,0BAA0B;EACxB,oBAAoB;EACpB,iBAAiB;CACnB,CAAC;;;;;CAMH,iBACE,0BAA0B;EACxB,oBAAoB;EACpB,iBAAiB;CACnB,CAAC;;;;;CAMH,yBAAuC;;;;;CAMvC,kBAAgC,2BAA2B;AAC7D"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { }
|
|
1
|
+
export { };
|
package/dist/testing.js
CHANGED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { Attributes, Context, Span, SpanOptions, TextMapPropagator } from "@opentelemetry/api";
|
|
2
|
+
import { ReadableSpan, ReadableSpan as ReadableSpan$1, Sampler, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Trigger types for edge handlers
|
|
7
|
+
* Can be a Request or any vendor-specific trigger type
|
|
8
|
+
*/
|
|
9
|
+
type Trigger = Request | DOConstructorTrigger | WorkflowTrigger | 'do-alarm' | unknown;
|
|
10
|
+
interface DOConstructorTrigger {
|
|
11
|
+
id: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
}
|
|
14
|
+
interface WorkflowTrigger {
|
|
15
|
+
type: 'workflow';
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Config types
|
|
20
|
+
*/
|
|
21
|
+
interface OTLPExporterConfig {
|
|
22
|
+
url: string;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
type ExporterConfig = OTLPExporterConfig | SpanExporter;
|
|
26
|
+
interface ServiceConfig {
|
|
27
|
+
name: string;
|
|
28
|
+
namespace?: string;
|
|
29
|
+
version?: string;
|
|
30
|
+
}
|
|
31
|
+
interface ParentRatioSamplingConfig {
|
|
32
|
+
acceptRemote?: boolean;
|
|
33
|
+
ratio: number;
|
|
34
|
+
}
|
|
35
|
+
type HeadSamplerConf = Sampler | ParentRatioSamplingConfig;
|
|
36
|
+
interface SamplingConfig<HS extends HeadSamplerConf = HeadSamplerConf> {
|
|
37
|
+
headSampler?: HS;
|
|
38
|
+
tailSampler?: TailSampleFn;
|
|
39
|
+
}
|
|
40
|
+
interface InstrumentationOptions {
|
|
41
|
+
instrumentGlobalFetch?: boolean;
|
|
42
|
+
instrumentGlobalCache?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Disable instrumentation entirely (useful for local development)
|
|
45
|
+
* When enabled, the handler is returned as-is without any instrumentation
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
disabled?: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Utility types
|
|
52
|
+
*/
|
|
53
|
+
type OrPromise<T> = T | Promise<T>;
|
|
54
|
+
/**
|
|
55
|
+
* Adapter event types
|
|
56
|
+
*/
|
|
57
|
+
type FunnelStepStatus = 'started' | 'completed' | 'abandoned' | 'failed' | (string & {});
|
|
58
|
+
type OutcomeStatus = 'success' | 'failure' | 'partial' | (string & {});
|
|
59
|
+
interface EdgeEventBase {
|
|
60
|
+
[key: string]: unknown;
|
|
61
|
+
service: string;
|
|
62
|
+
timestamp: number;
|
|
63
|
+
attributes: Record<string, unknown>;
|
|
64
|
+
traceId?: string;
|
|
65
|
+
spanId?: string;
|
|
66
|
+
correlationId?: string;
|
|
67
|
+
name: string;
|
|
68
|
+
}
|
|
69
|
+
interface EdgeTrackEvent extends EdgeEventBase {
|
|
70
|
+
type: 'event';
|
|
71
|
+
event: string;
|
|
72
|
+
}
|
|
73
|
+
interface EdgeFunnelStepEvent extends EdgeEventBase {
|
|
74
|
+
type: 'funnel-step';
|
|
75
|
+
funnel: string;
|
|
76
|
+
status: FunnelStepStatus;
|
|
77
|
+
}
|
|
78
|
+
interface EdgeOutcomeEvent extends EdgeEventBase {
|
|
79
|
+
type: 'outcome';
|
|
80
|
+
operation: string;
|
|
81
|
+
outcome: OutcomeStatus;
|
|
82
|
+
}
|
|
83
|
+
interface EdgeValueEvent extends EdgeEventBase {
|
|
84
|
+
type: 'value';
|
|
85
|
+
metric: string;
|
|
86
|
+
value: number;
|
|
87
|
+
}
|
|
88
|
+
type EdgeEvent = EdgeTrackEvent | EdgeFunnelStepEvent | EdgeOutcomeEvent | EdgeValueEvent;
|
|
89
|
+
type EdgeSubscriber = (event: EdgeEvent) => OrPromise<void>;
|
|
90
|
+
interface FetcherConfig {
|
|
91
|
+
includeTraceContext?: boolean | ((request: Request) => boolean);
|
|
92
|
+
}
|
|
93
|
+
interface RouteServiceConfig {
|
|
94
|
+
service: string;
|
|
95
|
+
}
|
|
96
|
+
interface PostProcessParams {
|
|
97
|
+
/**
|
|
98
|
+
* The request object that was passed to the fetch handler.
|
|
99
|
+
*/
|
|
100
|
+
request: Request;
|
|
101
|
+
/**
|
|
102
|
+
* The generated response object.
|
|
103
|
+
*/
|
|
104
|
+
response: Response;
|
|
105
|
+
/**
|
|
106
|
+
* A readable version of the span object that can be used to access the span's attributes and events.
|
|
107
|
+
*/
|
|
108
|
+
readable: ReadableSpan;
|
|
109
|
+
}
|
|
110
|
+
interface FetchHandlerConfig {
|
|
111
|
+
/**
|
|
112
|
+
* Whether to enable context propagation for incoming requests to `fetch`.
|
|
113
|
+
* This enables or disables distributed tracing from W3C Trace Context headers.
|
|
114
|
+
* @default true
|
|
115
|
+
*/
|
|
116
|
+
acceptTraceContext?: boolean | ((request: Request) => boolean);
|
|
117
|
+
/**
|
|
118
|
+
* Allows further customization of the generated span, based on the request/response data.
|
|
119
|
+
*/
|
|
120
|
+
postProcess?: (span: Span, ctx: PostProcessParams) => void;
|
|
121
|
+
/**
|
|
122
|
+
* Route patterns to include for fetch handler instrumentation.
|
|
123
|
+
* Supports glob patterns like '/api/**'.
|
|
124
|
+
* If not set, all routes are included.
|
|
125
|
+
*/
|
|
126
|
+
include?: string[];
|
|
127
|
+
/**
|
|
128
|
+
* Route patterns to exclude from fetch handler instrumentation.
|
|
129
|
+
* Supports glob patterns like '/health' and '/_internal/**'.
|
|
130
|
+
* Exclusions take precedence over inclusions.
|
|
131
|
+
*/
|
|
132
|
+
exclude?: string[];
|
|
133
|
+
/**
|
|
134
|
+
* Route-specific service mapping.
|
|
135
|
+
* The first matching pattern wins based on object iteration order.
|
|
136
|
+
*/
|
|
137
|
+
routes?: Record<string, RouteServiceConfig>;
|
|
138
|
+
}
|
|
139
|
+
interface HandlerConfig {
|
|
140
|
+
fetch?: FetchHandlerConfig;
|
|
141
|
+
}
|
|
142
|
+
interface DataSafetyConfig {
|
|
143
|
+
/** Redact query parameters from URL attributes (default: false) */
|
|
144
|
+
redactQueryParams?: boolean;
|
|
145
|
+
/** Control D1 SQL statement capture: 'full' (default), 'obfuscated', or 'off' */
|
|
146
|
+
captureDbStatement?: 'off' | 'obfuscated' | 'full';
|
|
147
|
+
/** Only capture these email headers (lowercase). When set, other headers are excluded. */
|
|
148
|
+
emailHeaderAllowlist?: string[];
|
|
149
|
+
}
|
|
150
|
+
interface EdgeConfigBase {
|
|
151
|
+
service: ServiceConfig;
|
|
152
|
+
handlers?: HandlerConfig;
|
|
153
|
+
fetch?: FetcherConfig;
|
|
154
|
+
postProcessor?: PostProcessorFn;
|
|
155
|
+
sampling?: SamplingConfig;
|
|
156
|
+
propagator?: TextMapPropagator;
|
|
157
|
+
instrumentation?: InstrumentationOptions;
|
|
158
|
+
subscribers?: EdgeSubscriber[];
|
|
159
|
+
/** Opt-in data safety controls for sensitive attribute capture */
|
|
160
|
+
dataSafety?: DataSafetyConfig;
|
|
161
|
+
}
|
|
162
|
+
interface EdgeConfigExporter extends EdgeConfigBase {
|
|
163
|
+
exporter: ExporterConfig;
|
|
164
|
+
}
|
|
165
|
+
interface EdgeConfigSpanProcessors extends EdgeConfigBase {
|
|
166
|
+
spanProcessors: SpanProcessor | SpanProcessor[];
|
|
167
|
+
}
|
|
168
|
+
type EdgeConfig = EdgeConfigExporter | EdgeConfigSpanProcessors;
|
|
169
|
+
interface ResolvedEdgeConfig extends EdgeConfigBase {
|
|
170
|
+
handlers: Required<HandlerConfig>;
|
|
171
|
+
fetch: Required<FetcherConfig>;
|
|
172
|
+
postProcessor: PostProcessorFn;
|
|
173
|
+
sampling: Required<SamplingConfig<Sampler>>;
|
|
174
|
+
spanProcessors: SpanProcessor[];
|
|
175
|
+
propagator: TextMapPropagator;
|
|
176
|
+
instrumentation: InstrumentationOptions;
|
|
177
|
+
subscribers: EdgeSubscriber[];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Function types
|
|
181
|
+
*/
|
|
182
|
+
type ResolveConfigFn<Env = any> = (env: Env, trigger: Trigger) => EdgeConfig;
|
|
183
|
+
type ConfigurationOption = EdgeConfig | ResolveConfigFn;
|
|
184
|
+
type PostProcessorFn = (spans: ReadableSpan[]) => ReadableSpan[];
|
|
185
|
+
type TailSampleFn = (traceInfo: LocalTrace) => boolean;
|
|
186
|
+
interface LocalTrace {
|
|
187
|
+
traceId: string;
|
|
188
|
+
spans: ReadableSpan[];
|
|
189
|
+
localRootSpan: ReadableSpan;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Span processor with flush support
|
|
193
|
+
*/
|
|
194
|
+
type TraceFlushableSpanProcessor = SpanProcessor & {
|
|
195
|
+
forceFlush: (traceId?: string) => Promise<void>;
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* Handler instrumentation
|
|
199
|
+
*/
|
|
200
|
+
interface InitialSpanInfo {
|
|
201
|
+
name: string;
|
|
202
|
+
options: SpanOptions;
|
|
203
|
+
context?: Context;
|
|
204
|
+
}
|
|
205
|
+
interface HandlerInstrumentation<T extends Trigger, R extends any> {
|
|
206
|
+
getInitialSpanInfo: (trigger: T) => InitialSpanInfo;
|
|
207
|
+
getAttributesFromResult?: (result: Awaited<R>) => Attributes;
|
|
208
|
+
instrumentTrigger?: (trigger: T) => T;
|
|
209
|
+
executionSucces?: (span: Span, trigger: T, result: Awaited<R>) => void;
|
|
210
|
+
executionFailed?: (span: Span, trigger: T, error?: any) => void;
|
|
211
|
+
}
|
|
212
|
+
//#endregion
|
|
213
|
+
export { WorkflowTrigger as A, ResolvedEdgeConfig as C, TailSampleFn as D, ServiceConfig as E, TraceFlushableSpanProcessor as O, ResolveConfigFn as S, SamplingConfig as T, OTLPExporterConfig as _, EdgeEvent as a, PostProcessorFn as b, EdgeSubscriber as c, ExporterConfig as d, FunnelStepStatus as f, LocalTrace as g, InstrumentationOptions as h, EdgeConfig as i, Trigger as k, EdgeTrackEvent as l, InitialSpanInfo as m, DOConstructorTrigger as n, EdgeFunnelStepEvent as o, HandlerInstrumentation as p, DataSafetyConfig as r, EdgeOutcomeEvent as s, ConfigurationOption as t, EdgeValueEvent as u, OrPromise as v, RouteServiceConfig as w, ReadableSpan$1 as x, OutcomeStatus as y };
|
|
214
|
+
//# sourceMappingURL=types-HCbsjZzp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-HCbsjZzp.d.ts","names":[],"sources":["../src/types.ts"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-edge",
|
|
3
|
-
"version": "3.16.
|
|
3
|
+
"version": "3.16.15",
|
|
4
4
|
"description": "Vendor-agnostic OpenTelemetry for edge runtimes - foundation for Cloudflare, Vercel, Netlify, Deno",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@opentelemetry/context-async-hooks": "^2.7.1",
|
|
67
|
-
"@types/node": "^25.9.
|
|
67
|
+
"@types/node": "^25.9.2",
|
|
68
68
|
"rimraf": "^6.1.3",
|
|
69
|
-
"
|
|
69
|
+
"tsdown": "^0.22.2",
|
|
70
70
|
"typescript": "^6.0.3",
|
|
71
|
-
"vitest": "^4.1.
|
|
71
|
+
"vitest": "^4.1.8",
|
|
72
72
|
"vitest-mock-extended": "^4.0.0"
|
|
73
73
|
},
|
|
74
74
|
"repository": {
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
},
|
|
82
82
|
"homepage": "https://github.com/jagreehal/autotel/tree/main/packages/autotel-edge#readme",
|
|
83
83
|
"scripts": {
|
|
84
|
-
"build": "
|
|
85
|
-
"dev": "
|
|
84
|
+
"build": "tsdown",
|
|
85
|
+
"dev": "tsdown --watch",
|
|
86
86
|
"lint": "eslint src/**/*.ts",
|
|
87
87
|
"lint:fix": "eslint src/**/*.ts --fix",
|
|
88
88
|
"type-check": "tsc --noEmit",
|
package/src/core/buffer.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { Buffer } from 'node:buffer';
|
|
|
11
11
|
//@ts-ignore
|
|
12
12
|
globalThis.Buffer = Buffer;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
// Re-export the single imported binding. Importing AND re-exporting `Buffer`
|
|
15
|
+
// from 'node:buffer' separately makes rolldown (tsdown) emit a dangling
|
|
16
|
+
// `Buffer$1` reference, so keep exactly one binding.
|
|
17
|
+
export { Buffer };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { trace } from '@opentelemetry/api';
|
|
3
|
+
import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
4
|
+
import { SamplingDecision, type SpanProcessor } from '@opentelemetry/sdk-trace-base';
|
|
5
|
+
import { WorkerTracerProvider } from './provider';
|
|
6
|
+
|
|
7
|
+
const noopProcessor: SpanProcessor = {
|
|
8
|
+
onStart: () => {},
|
|
9
|
+
onEnd: () => {},
|
|
10
|
+
shutdown: async () => {},
|
|
11
|
+
forceFlush: async () => {},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Regression guard for Issue 1.1: register() must register the context manager
|
|
16
|
+
* with the global OTel API, otherwise the active span is lost after the first
|
|
17
|
+
* `await` and consumers that resolve trace context from the active span
|
|
18
|
+
* (autotel-agent / autotel-audit inside a handler or Workflow step) break.
|
|
19
|
+
*
|
|
20
|
+
* NOTE: this test registers a global context manager, so it lives in its own
|
|
21
|
+
* file to avoid leaking that global state into other suites.
|
|
22
|
+
*/
|
|
23
|
+
describe('WorkerTracerProvider global context propagation', () => {
|
|
24
|
+
it('keeps the active span across an await after register()', async () => {
|
|
25
|
+
const provider = new WorkerTracerProvider(
|
|
26
|
+
[noopProcessor],
|
|
27
|
+
resourceFromAttributes({}),
|
|
28
|
+
);
|
|
29
|
+
provider.register();
|
|
30
|
+
|
|
31
|
+
// The provider's WorkerTracer needs a head sampler (normally set from config).
|
|
32
|
+
(
|
|
33
|
+
provider.getTracer('test') as unknown as {
|
|
34
|
+
setHeadSampler(s: unknown): void;
|
|
35
|
+
}
|
|
36
|
+
).setHeadSampler({
|
|
37
|
+
shouldSample: () => ({
|
|
38
|
+
decision: SamplingDecision.RECORD_AND_SAMPLED,
|
|
39
|
+
attributes: {},
|
|
40
|
+
traceState: undefined,
|
|
41
|
+
}),
|
|
42
|
+
toString: () => 'AlwaysOn',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Resolve via the global API to prove the global registration took effect.
|
|
46
|
+
const tracer = trace.getTracer('test');
|
|
47
|
+
|
|
48
|
+
await tracer.startActiveSpan('op', async (span) => {
|
|
49
|
+
// Simulate the async work a handler / step.do() callback performs.
|
|
50
|
+
await Promise.resolve();
|
|
51
|
+
expect(trace.getActiveSpan()).toBe(span);
|
|
52
|
+
span.end();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|