autotel 2.1.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/LICENSE +21 -0
- package/README.md +1946 -0
- package/dist/chunk-2LNRY4QK.js +273 -0
- package/dist/chunk-2LNRY4QK.js.map +1 -0
- package/dist/chunk-3HENGDW2.js +587 -0
- package/dist/chunk-3HENGDW2.js.map +1 -0
- package/dist/chunk-4OAT42CA.cjs +73 -0
- package/dist/chunk-4OAT42CA.cjs.map +1 -0
- package/dist/chunk-5GWX5LFW.js +70 -0
- package/dist/chunk-5GWX5LFW.js.map +1 -0
- package/dist/chunk-5R2M36QB.js +195 -0
- package/dist/chunk-5R2M36QB.js.map +1 -0
- package/dist/chunk-5ZN622AO.js +73 -0
- package/dist/chunk-5ZN622AO.js.map +1 -0
- package/dist/chunk-77MSMAUQ.cjs +498 -0
- package/dist/chunk-77MSMAUQ.cjs.map +1 -0
- package/dist/chunk-ABPEQ6RK.cjs +596 -0
- package/dist/chunk-ABPEQ6RK.cjs.map +1 -0
- package/dist/chunk-BWYGJKRB.js +95 -0
- package/dist/chunk-BWYGJKRB.js.map +1 -0
- package/dist/chunk-BZHG5IZ4.js +73 -0
- package/dist/chunk-BZHG5IZ4.js.map +1 -0
- package/dist/chunk-G7VZBCD6.cjs +35 -0
- package/dist/chunk-G7VZBCD6.cjs.map +1 -0
- package/dist/chunk-GVLK7YUU.cjs +30 -0
- package/dist/chunk-GVLK7YUU.cjs.map +1 -0
- package/dist/chunk-HCCXC7XG.js +205 -0
- package/dist/chunk-HCCXC7XG.js.map +1 -0
- package/dist/chunk-HE6T6FIX.cjs +203 -0
- package/dist/chunk-HE6T6FIX.cjs.map +1 -0
- package/dist/chunk-KIXWPOCO.cjs +100 -0
- package/dist/chunk-KIXWPOCO.cjs.map +1 -0
- package/dist/chunk-KVGNW3FC.js +87 -0
- package/dist/chunk-KVGNW3FC.js.map +1 -0
- package/dist/chunk-LITNXTTT.js +3 -0
- package/dist/chunk-LITNXTTT.js.map +1 -0
- package/dist/chunk-M4ANN7RL.js +114 -0
- package/dist/chunk-M4ANN7RL.js.map +1 -0
- package/dist/chunk-NC52UBR2.cjs +32 -0
- package/dist/chunk-NC52UBR2.cjs.map +1 -0
- package/dist/chunk-NHCNRQD3.cjs +212 -0
- package/dist/chunk-NHCNRQD3.cjs.map +1 -0
- package/dist/chunk-NZ72VDNY.cjs +4 -0
- package/dist/chunk-NZ72VDNY.cjs.map +1 -0
- package/dist/chunk-P6JUDYNO.js +57 -0
- package/dist/chunk-P6JUDYNO.js.map +1 -0
- package/dist/chunk-RJYY7BWX.js +1349 -0
- package/dist/chunk-RJYY7BWX.js.map +1 -0
- package/dist/chunk-TRI4V5BF.cjs +126 -0
- package/dist/chunk-TRI4V5BF.cjs.map +1 -0
- package/dist/chunk-UL33I6IS.js +139 -0
- package/dist/chunk-UL33I6IS.js.map +1 -0
- package/dist/chunk-URRW6M2C.cjs +61 -0
- package/dist/chunk-URRW6M2C.cjs.map +1 -0
- package/dist/chunk-UY3UYPBZ.cjs +77 -0
- package/dist/chunk-UY3UYPBZ.cjs.map +1 -0
- package/dist/chunk-W3253FGB.cjs +277 -0
- package/dist/chunk-W3253FGB.cjs.map +1 -0
- package/dist/chunk-W7LHZVQF.js +26 -0
- package/dist/chunk-W7LHZVQF.js.map +1 -0
- package/dist/chunk-WBWNM6LB.cjs +1360 -0
- package/dist/chunk-WBWNM6LB.cjs.map +1 -0
- package/dist/chunk-WFJ7L2RV.js +494 -0
- package/dist/chunk-WFJ7L2RV.js.map +1 -0
- package/dist/chunk-X4RMFFMR.js +28 -0
- package/dist/chunk-X4RMFFMR.js.map +1 -0
- package/dist/chunk-Y4Y2S7BM.cjs +92 -0
- package/dist/chunk-Y4Y2S7BM.cjs.map +1 -0
- package/dist/chunk-YLPNXZFI.cjs +143 -0
- package/dist/chunk-YLPNXZFI.cjs.map +1 -0
- package/dist/chunk-YTXEZ4SD.cjs +77 -0
- package/dist/chunk-YTXEZ4SD.cjs.map +1 -0
- package/dist/chunk-Z6ZWNWWR.js +30 -0
- package/dist/chunk-Z6ZWNWWR.js.map +1 -0
- package/dist/config.cjs +26 -0
- package/dist/config.cjs.map +1 -0
- package/dist/config.d.cts +75 -0
- package/dist/config.d.ts +75 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/db.cjs +233 -0
- package/dist/db.cjs.map +1 -0
- package/dist/db.d.cts +123 -0
- package/dist/db.d.ts +123 -0
- package/dist/db.js +228 -0
- package/dist/db.js.map +1 -0
- package/dist/decorators.cjs +67 -0
- package/dist/decorators.cjs.map +1 -0
- package/dist/decorators.d.cts +91 -0
- package/dist/decorators.d.ts +91 -0
- package/dist/decorators.js +65 -0
- package/dist/decorators.js.map +1 -0
- package/dist/event-subscriber.cjs +6 -0
- package/dist/event-subscriber.cjs.map +1 -0
- package/dist/event-subscriber.d.cts +116 -0
- package/dist/event-subscriber.d.ts +116 -0
- package/dist/event-subscriber.js +3 -0
- package/dist/event-subscriber.js.map +1 -0
- package/dist/event-testing.cjs +21 -0
- package/dist/event-testing.cjs.map +1 -0
- package/dist/event-testing.d.cts +110 -0
- package/dist/event-testing.d.ts +110 -0
- package/dist/event-testing.js +4 -0
- package/dist/event-testing.js.map +1 -0
- package/dist/event.cjs +30 -0
- package/dist/event.cjs.map +1 -0
- package/dist/event.d.cts +282 -0
- package/dist/event.d.ts +282 -0
- package/dist/event.js +13 -0
- package/dist/event.js.map +1 -0
- package/dist/exporters.cjs +17 -0
- package/dist/exporters.cjs.map +1 -0
- package/dist/exporters.d.cts +1 -0
- package/dist/exporters.d.ts +1 -0
- package/dist/exporters.js +4 -0
- package/dist/exporters.js.map +1 -0
- package/dist/functional.cjs +46 -0
- package/dist/functional.cjs.map +1 -0
- package/dist/functional.d.cts +478 -0
- package/dist/functional.d.ts +478 -0
- package/dist/functional.js +13 -0
- package/dist/functional.js.map +1 -0
- package/dist/http.cjs +189 -0
- package/dist/http.cjs.map +1 -0
- package/dist/http.d.cts +169 -0
- package/dist/http.d.ts +169 -0
- package/dist/http.js +184 -0
- package/dist/http.js.map +1 -0
- package/dist/index.cjs +333 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +758 -0
- package/dist/index.d.ts +758 -0
- package/dist/index.js +143 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation.cjs +182 -0
- package/dist/instrumentation.cjs.map +1 -0
- package/dist/instrumentation.d.cts +49 -0
- package/dist/instrumentation.d.ts +49 -0
- package/dist/instrumentation.js +179 -0
- package/dist/instrumentation.js.map +1 -0
- package/dist/logger.cjs +19 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +146 -0
- package/dist/logger.d.ts +146 -0
- package/dist/logger.js +6 -0
- package/dist/logger.js.map +1 -0
- package/dist/metric-helpers.cjs +31 -0
- package/dist/metric-helpers.cjs.map +1 -0
- package/dist/metric-helpers.d.cts +13 -0
- package/dist/metric-helpers.d.ts +13 -0
- package/dist/metric-helpers.js +6 -0
- package/dist/metric-helpers.js.map +1 -0
- package/dist/metric-testing.cjs +21 -0
- package/dist/metric-testing.cjs.map +1 -0
- package/dist/metric-testing.d.cts +110 -0
- package/dist/metric-testing.d.ts +110 -0
- package/dist/metric-testing.js +4 -0
- package/dist/metric-testing.js.map +1 -0
- package/dist/metric.cjs +26 -0
- package/dist/metric.cjs.map +1 -0
- package/dist/metric.d.cts +240 -0
- package/dist/metric.d.ts +240 -0
- package/dist/metric.js +9 -0
- package/dist/metric.js.map +1 -0
- package/dist/processors.cjs +17 -0
- package/dist/processors.cjs.map +1 -0
- package/dist/processors.d.cts +1 -0
- package/dist/processors.d.ts +1 -0
- package/dist/processors.js +4 -0
- package/dist/processors.js.map +1 -0
- package/dist/sampling.cjs +40 -0
- package/dist/sampling.cjs.map +1 -0
- package/dist/sampling.d.cts +260 -0
- package/dist/sampling.d.ts +260 -0
- package/dist/sampling.js +7 -0
- package/dist/sampling.js.map +1 -0
- package/dist/semantic-helpers.cjs +35 -0
- package/dist/semantic-helpers.cjs.map +1 -0
- package/dist/semantic-helpers.d.cts +442 -0
- package/dist/semantic-helpers.d.ts +442 -0
- package/dist/semantic-helpers.js +14 -0
- package/dist/semantic-helpers.js.map +1 -0
- package/dist/tail-sampling-processor.cjs +13 -0
- package/dist/tail-sampling-processor.cjs.map +1 -0
- package/dist/tail-sampling-processor.d.cts +27 -0
- package/dist/tail-sampling-processor.d.ts +27 -0
- package/dist/tail-sampling-processor.js +4 -0
- package/dist/tail-sampling-processor.js.map +1 -0
- package/dist/testing.cjs +286 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +291 -0
- package/dist/testing.d.ts +291 -0
- package/dist/testing.js +263 -0
- package/dist/testing.js.map +1 -0
- package/dist/trace-context-DRZdUvVY.d.cts +181 -0
- package/dist/trace-context-DRZdUvVY.d.ts +181 -0
- package/dist/trace-helpers.cjs +54 -0
- package/dist/trace-helpers.cjs.map +1 -0
- package/dist/trace-helpers.d.cts +524 -0
- package/dist/trace-helpers.d.ts +524 -0
- package/dist/trace-helpers.js +5 -0
- package/dist/trace-helpers.js.map +1 -0
- package/dist/tracer-provider.cjs +21 -0
- package/dist/tracer-provider.cjs.map +1 -0
- package/dist/tracer-provider.d.cts +169 -0
- package/dist/tracer-provider.d.ts +169 -0
- package/dist/tracer-provider.js +4 -0
- package/dist/tracer-provider.js.map +1 -0
- package/package.json +280 -0
- package/src/baggage-span-processor.test.ts +202 -0
- package/src/baggage-span-processor.ts +98 -0
- package/src/circuit-breaker.test.ts +341 -0
- package/src/circuit-breaker.ts +184 -0
- package/src/config.test.ts +94 -0
- package/src/config.ts +169 -0
- package/src/db.test.ts +252 -0
- package/src/db.ts +447 -0
- package/src/decorators.test.ts +203 -0
- package/src/decorators.ts +188 -0
- package/src/env-config.test.ts +246 -0
- package/src/env-config.ts +158 -0
- package/src/event-queue.test.ts +222 -0
- package/src/event-queue.ts +203 -0
- package/src/event-subscriber.ts +136 -0
- package/src/event-testing.ts +197 -0
- package/src/event.test.ts +718 -0
- package/src/event.ts +556 -0
- package/src/exporters.ts +96 -0
- package/src/functional.test.ts +1059 -0
- package/src/functional.ts +2295 -0
- package/src/http.test.ts +487 -0
- package/src/http.ts +424 -0
- package/src/index.ts +158 -0
- package/src/init.customization.test.ts +210 -0
- package/src/init.integrations.test.ts +366 -0
- package/src/init.openllmetry.test.ts +282 -0
- package/src/init.protocol.test.ts +215 -0
- package/src/init.ts +1426 -0
- package/src/instrumentation.test.ts +108 -0
- package/src/instrumentation.ts +308 -0
- package/src/logger.test.ts +117 -0
- package/src/logger.ts +246 -0
- package/src/metric-helpers.ts +47 -0
- package/src/metric-testing.ts +197 -0
- package/src/metric.ts +434 -0
- package/src/metrics.test.ts +205 -0
- package/src/operation-context.ts +93 -0
- package/src/processors.ts +106 -0
- package/src/rate-limiter.test.ts +199 -0
- package/src/rate-limiter.ts +98 -0
- package/src/sampling.test.ts +513 -0
- package/src/sampling.ts +428 -0
- package/src/semantic-helpers.test.ts +311 -0
- package/src/semantic-helpers.ts +584 -0
- package/src/shutdown.test.ts +311 -0
- package/src/shutdown.ts +222 -0
- package/src/stub.integration.test.ts +361 -0
- package/src/tail-sampling-processor.test.ts +226 -0
- package/src/tail-sampling-processor.ts +51 -0
- package/src/testing.ts +670 -0
- package/src/trace-context.ts +470 -0
- package/src/trace-helpers.new.test.ts +278 -0
- package/src/trace-helpers.test.ts +242 -0
- package/src/trace-helpers.ts +690 -0
- package/src/tracer-provider.test.ts +183 -0
- package/src/tracer-provider.ts +266 -0
- package/src/track.test.ts +153 -0
- package/src/track.ts +120 -0
- package/src/validation.test.ts +306 -0
- package/src/validation.ts +239 -0
- package/src/variable-name-inference.test.ts +178 -0
- package/src/variable-name-inference.ts +242 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import type { NodeSDK } from '@opentelemetry/sdk-node';
|
|
3
|
+
import { mock, mockDeep, type DeepMockProxy } from 'vitest-mock-extended';
|
|
4
|
+
|
|
5
|
+
type SdkRecord = {
|
|
6
|
+
options: Record<string, unknown>;
|
|
7
|
+
instance: DeepMockProxy<NodeSDK>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const mockedModules = [
|
|
11
|
+
'@opentelemetry/sdk-node',
|
|
12
|
+
'@opentelemetry/exporter-trace-otlp-http',
|
|
13
|
+
'@opentelemetry/exporter-metrics-otlp-http',
|
|
14
|
+
'@opentelemetry/sdk-metrics',
|
|
15
|
+
'@traceloop/node-server-sdk',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
// Track traceloop initialize calls globally
|
|
19
|
+
const traceloopInitializeCalls: Array<Record<string, unknown>> = [];
|
|
20
|
+
|
|
21
|
+
// Store mock initialize function globally
|
|
22
|
+
let globalMockInitialize: ReturnType<typeof vi.fn> | null = null;
|
|
23
|
+
|
|
24
|
+
async function loadInitWithMocks() {
|
|
25
|
+
const sdkInstances: SdkRecord[] = [];
|
|
26
|
+
|
|
27
|
+
class MockNodeSDK {
|
|
28
|
+
constructor(options: Record<string, unknown>) {
|
|
29
|
+
const instance = mockDeep<NodeSDK>();
|
|
30
|
+
instance.start.mockImplementation(() => {});
|
|
31
|
+
instance.shutdown.mockResolvedValue();
|
|
32
|
+
// Add getTracerProvider method (not in public interface but used internally)
|
|
33
|
+
|
|
34
|
+
(instance as any).getTracerProvider = vi.fn().mockReturnValue(mock());
|
|
35
|
+
sdkInstances.push({ options, instance });
|
|
36
|
+
return instance;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class MockOTLPTraceExporter {
|
|
41
|
+
options: Record<string, unknown>;
|
|
42
|
+
|
|
43
|
+
constructor(options: Record<string, unknown>) {
|
|
44
|
+
this.options = options;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
class MockOTLPMetricExporter {
|
|
49
|
+
options: Record<string, unknown>;
|
|
50
|
+
|
|
51
|
+
constructor(options: Record<string, unknown>) {
|
|
52
|
+
this.options = options;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class MockPeriodicExportingMetricReader {
|
|
57
|
+
options: Record<string, unknown>;
|
|
58
|
+
|
|
59
|
+
constructor(options: Record<string, unknown>) {
|
|
60
|
+
this.options = options;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Clear module cache first
|
|
65
|
+
vi.resetModules();
|
|
66
|
+
|
|
67
|
+
// Create mock function that captures calls and store it globally
|
|
68
|
+
globalMockInitialize = vi.fn((options?: Record<string, unknown>) => {
|
|
69
|
+
traceloopInitializeCalls.push(options || {});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Re-setup the mock after resetModules
|
|
73
|
+
// Use virtual: true to make require() fail and fall back to async import
|
|
74
|
+
vi.doMock(
|
|
75
|
+
'@traceloop/node-server-sdk',
|
|
76
|
+
() => {
|
|
77
|
+
// This will be called for dynamic import() - return the mock
|
|
78
|
+
return {
|
|
79
|
+
initialize: globalMockInitialize!,
|
|
80
|
+
instrumentations: [{ name: 'openai' }, { name: 'langchain' }],
|
|
81
|
+
default: {
|
|
82
|
+
initialize: globalMockInitialize!,
|
|
83
|
+
instrumentations: [{ name: 'openai' }, { name: 'langchain' }],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
{ virtual: true },
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
vi.doMock('@opentelemetry/sdk-node', () => ({
|
|
91
|
+
NodeSDK: MockNodeSDK,
|
|
92
|
+
}));
|
|
93
|
+
|
|
94
|
+
vi.doMock('@opentelemetry/exporter-trace-otlp-http', () => ({
|
|
95
|
+
OTLPTraceExporter: MockOTLPTraceExporter,
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
vi.doMock('@opentelemetry/exporter-metrics-otlp-http', () => ({
|
|
99
|
+
OTLPMetricExporter: MockOTLPMetricExporter,
|
|
100
|
+
}));
|
|
101
|
+
|
|
102
|
+
vi.doMock('@opentelemetry/sdk-metrics', () => ({
|
|
103
|
+
PeriodicExportingMetricReader: MockPeriodicExportingMetricReader,
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
const mod = await import('./init');
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
init: mod.init,
|
|
110
|
+
getConfig: mod.getConfig,
|
|
111
|
+
sdkInstances,
|
|
112
|
+
traceloopInitializeCalls,
|
|
113
|
+
mockTraceloop: {
|
|
114
|
+
initialize: globalMockInitialize!, // Return the same mock function reference
|
|
115
|
+
instrumentations: [{ name: 'openai' }, { name: 'langchain' }],
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
describe('init() OpenLLMetry integration', () => {
|
|
121
|
+
beforeEach(() => {
|
|
122
|
+
vi.resetModules();
|
|
123
|
+
traceloopInitializeCalls.length = 0; // Clear calls array
|
|
124
|
+
globalMockInitialize = null; // Reset mock function
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
afterEach(() => {
|
|
128
|
+
for (const mod of mockedModules) {
|
|
129
|
+
vi.doUnmock(mod);
|
|
130
|
+
}
|
|
131
|
+
vi.clearAllMocks();
|
|
132
|
+
delete process.env.AUTOTELEMETRY_METRICS;
|
|
133
|
+
delete process.env.NODE_ENV;
|
|
134
|
+
delete process.env.TRACELOOP_API_KEY;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should not initialize OpenLLMetry when disabled', async () => {
|
|
138
|
+
const { init, traceloopInitializeCalls } = await loadInitWithMocks();
|
|
139
|
+
|
|
140
|
+
init({ service: 'test-app' });
|
|
141
|
+
|
|
142
|
+
expect(traceloopInitializeCalls).toHaveLength(0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Skipped: vi.doMock doesn't properly intercept require('@traceloop/node-server-sdk')
|
|
146
|
+
// when the real module is installed. The real module loads instead of the mock,
|
|
147
|
+
// so initialize() calls aren't captured. This is a known vitest limitation with
|
|
148
|
+
// optional peer dependencies that may or may not be installed.
|
|
149
|
+
it.skip('should initialize OpenLLMetry when enabled', async () => {
|
|
150
|
+
const { init, traceloopInitializeCalls } = await loadInitWithMocks();
|
|
151
|
+
|
|
152
|
+
init({
|
|
153
|
+
service: 'test-app',
|
|
154
|
+
openllmetry: { enabled: true },
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Wait for async import to complete (require fails, falls back to async import)
|
|
158
|
+
// Use a longer timeout and retry logic for CI environments
|
|
159
|
+
let attempts = 0;
|
|
160
|
+
while (traceloopInitializeCalls.length === 0 && attempts < 20) {
|
|
161
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
162
|
+
attempts++;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
expect(traceloopInitializeCalls).toHaveLength(1);
|
|
166
|
+
const callOptions = traceloopInitializeCalls[0];
|
|
167
|
+
expect(callOptions).toBeDefined();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Skipped: Same mocking issue as above - vi.doMock doesn't intercept require()
|
|
171
|
+
// calls for optional peer dependencies when the real module is installed.
|
|
172
|
+
it.skip('should pass OpenLLMetry options to initialize', async () => {
|
|
173
|
+
const { init, traceloopInitializeCalls } = await loadInitWithMocks();
|
|
174
|
+
|
|
175
|
+
init({
|
|
176
|
+
service: 'test-app',
|
|
177
|
+
openllmetry: {
|
|
178
|
+
enabled: true,
|
|
179
|
+
options: {
|
|
180
|
+
disableBatch: true,
|
|
181
|
+
apiKey: 'test-key',
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Wait for async import to complete
|
|
187
|
+
// Use a longer timeout for CI environments
|
|
188
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
189
|
+
|
|
190
|
+
expect(traceloopInitializeCalls).toHaveLength(1);
|
|
191
|
+
const callOptions = traceloopInitializeCalls[0];
|
|
192
|
+
expect(callOptions).toMatchObject({
|
|
193
|
+
disableBatch: true,
|
|
194
|
+
apiKey: 'test-key',
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Skipped: Same mocking issue - vi.doMock doesn't intercept require() for optional
|
|
199
|
+
// peer dependencies, so the mock initialize() function is never called.
|
|
200
|
+
it.skip('should reuse autotel tracer provider when OpenLLMetry is enabled', async () => {
|
|
201
|
+
const { init, traceloopInitializeCalls, sdkInstances } =
|
|
202
|
+
await loadInitWithMocks();
|
|
203
|
+
|
|
204
|
+
init({
|
|
205
|
+
service: 'test-app',
|
|
206
|
+
openllmetry: { enabled: true },
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
expect(sdkInstances).toHaveLength(1);
|
|
210
|
+
const sdkInstance = sdkInstances[0].instance;
|
|
211
|
+
|
|
212
|
+
// Wait a bit for async operations if any
|
|
213
|
+
// Use a longer timeout for CI environments
|
|
214
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
215
|
+
|
|
216
|
+
expect(traceloopInitializeCalls).toHaveLength(1);
|
|
217
|
+
const callOptions = traceloopInitializeCalls[0];
|
|
218
|
+
// Should pass tracer provider to OpenLLMetry
|
|
219
|
+
expect(callOptions).toBeDefined();
|
|
220
|
+
// Verify getTracerProvider was called to get the provider
|
|
221
|
+
|
|
222
|
+
expect((sdkInstance as any).getTracerProvider).toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it('should add OpenLLMetry instrumentations when selectiveInstrumentation is false', async () => {
|
|
226
|
+
const { init, sdkInstances, mockTraceloop } = await loadInitWithMocks();
|
|
227
|
+
|
|
228
|
+
init({
|
|
229
|
+
service: 'test-app',
|
|
230
|
+
openllmetry: { enabled: true },
|
|
231
|
+
integrations: false, // This means selectiveInstrumentation is true by default
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
|
|
235
|
+
const instrumentations = options.instrumentations as unknown[];
|
|
236
|
+
|
|
237
|
+
// When selectiveInstrumentation is true (default), OpenLLMetry instrumentations should be added
|
|
238
|
+
expect(instrumentations).toBeDefined();
|
|
239
|
+
// Should include OpenLLMetry instrumentations
|
|
240
|
+
expect(mockTraceloop.instrumentations).toBeDefined();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should handle missing @traceloop/node-server-sdk gracefully', async () => {
|
|
244
|
+
vi.doMock('@traceloop/node-server-sdk', () => {
|
|
245
|
+
throw new Error('Module not found');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const { init } = await import('./init');
|
|
249
|
+
|
|
250
|
+
// Should not throw, but log a warning
|
|
251
|
+
expect(() => {
|
|
252
|
+
init({
|
|
253
|
+
service: 'test-app',
|
|
254
|
+
openllmetry: { enabled: true },
|
|
255
|
+
});
|
|
256
|
+
}).not.toThrow();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Skipped: Same mocking issue - vi.doMock doesn't intercept require() calls,
|
|
260
|
+
// so the async import fallback path is used but the mock isn't found either.
|
|
261
|
+
// This prevents proper verification of the initialization sequence.
|
|
262
|
+
it.skip('should initialize OpenLLMetry after SDK start', async () => {
|
|
263
|
+
const { init, sdkInstances, traceloopInitializeCalls } =
|
|
264
|
+
await loadInitWithMocks();
|
|
265
|
+
|
|
266
|
+
init({
|
|
267
|
+
service: 'test-app',
|
|
268
|
+
openllmetry: { enabled: true },
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Wait for async import to complete (require fails, falls back to async import)
|
|
272
|
+
// Use a longer timeout for CI environments
|
|
273
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
274
|
+
|
|
275
|
+
// Verify SDK started (it's called synchronously in init)
|
|
276
|
+
expect(sdkInstances).toHaveLength(1);
|
|
277
|
+
expect(sdkInstances[0].instance.start).toHaveBeenCalled();
|
|
278
|
+
|
|
279
|
+
// Verify OpenLLMetry was initialized (via async import)
|
|
280
|
+
expect(traceloopInitializeCalls).toHaveLength(1);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Unit tests for protocol switching helper functions
|
|
5
|
+
*
|
|
6
|
+
* These tests verify the URL formatting and protocol resolution logic
|
|
7
|
+
* without requiring dynamic module loading or complex mocking.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Helper functions copied from init.ts for testing
|
|
11
|
+
function formatEndpointUrl(
|
|
12
|
+
endpoint: string,
|
|
13
|
+
signal: 'traces' | 'metrics',
|
|
14
|
+
protocol: 'http' | 'grpc',
|
|
15
|
+
): string {
|
|
16
|
+
if (protocol === 'grpc') {
|
|
17
|
+
// gRPC: strip any paths, return base endpoint
|
|
18
|
+
return endpoint.replace(/\/(v1\/)?(traces|metrics|logs)$/, '');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// HTTP: append signal path if not present
|
|
22
|
+
if (!endpoint.endsWith(`/v1/${signal}`)) {
|
|
23
|
+
return `${endpoint}/v1/${signal}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return endpoint;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function resolveProtocol(
|
|
30
|
+
configProtocol?: 'http' | 'grpc',
|
|
31
|
+
envProtocol?: string,
|
|
32
|
+
): 'http' | 'grpc' {
|
|
33
|
+
// 1. Check config parameter (highest priority)
|
|
34
|
+
if (configProtocol === 'grpc' || configProtocol === 'http') {
|
|
35
|
+
return configProtocol;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 2. Check OTEL_EXPORTER_OTLP_PROTOCOL env var
|
|
39
|
+
if (envProtocol === 'grpc') return 'grpc';
|
|
40
|
+
if (envProtocol === 'http/protobuf' || envProtocol === 'http') return 'http';
|
|
41
|
+
|
|
42
|
+
// 3. Default to HTTP
|
|
43
|
+
return 'http';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe('Protocol resolution logic', () => {
|
|
47
|
+
describe('resolveProtocol()', () => {
|
|
48
|
+
it('should return http by default', () => {
|
|
49
|
+
expect(resolveProtocol()).toBe('http');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should respect config parameter over env var', () => {
|
|
53
|
+
expect(resolveProtocol('http', 'grpc')).toBe('http');
|
|
54
|
+
expect(resolveProtocol('grpc', 'http')).toBe('grpc');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should use grpc when env var is grpc', () => {
|
|
58
|
+
expect(resolveProtocol(undefined, 'grpc')).toBe('grpc');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should use http when env var is http', () => {
|
|
62
|
+
expect(resolveProtocol(undefined, 'http')).toBe('http');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should use http when env var is http/protobuf', () => {
|
|
66
|
+
expect(resolveProtocol(undefined, 'http/protobuf')).toBe('http');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should default to http for invalid env var', () => {
|
|
70
|
+
expect(resolveProtocol(undefined, 'invalid')).toBe('http');
|
|
71
|
+
expect(resolveProtocol(undefined, '')).toBe('http');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should prioritize config parameter', () => {
|
|
75
|
+
expect(resolveProtocol('grpc')).toBe('grpc');
|
|
76
|
+
expect(resolveProtocol('http')).toBe('http');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('formatEndpointUrl() for HTTP protocol', () => {
|
|
81
|
+
it('should append /v1/traces for traces', () => {
|
|
82
|
+
expect(formatEndpointUrl('http://localhost:4318', 'traces', 'http')).toBe(
|
|
83
|
+
'http://localhost:4318/v1/traces',
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should append /v1/metrics for metrics', () => {
|
|
88
|
+
expect(
|
|
89
|
+
formatEndpointUrl('http://localhost:4318', 'metrics', 'http'),
|
|
90
|
+
).toBe('http://localhost:4318/v1/metrics');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should not double-append path if already present', () => {
|
|
94
|
+
expect(
|
|
95
|
+
formatEndpointUrl('http://localhost:4318/v1/traces', 'traces', 'http'),
|
|
96
|
+
).toBe('http://localhost:4318/v1/traces');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle endpoints without http prefix', () => {
|
|
100
|
+
expect(formatEndpointUrl('localhost:4318', 'traces', 'http')).toBe(
|
|
101
|
+
'localhost:4318/v1/traces',
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should handle HTTPS endpoints', () => {
|
|
106
|
+
expect(
|
|
107
|
+
formatEndpointUrl('https://otlp.example.com', 'traces', 'http'),
|
|
108
|
+
).toBe('https://otlp.example.com/v1/traces');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should handle endpoints with trailing slash', () => {
|
|
112
|
+
expect(
|
|
113
|
+
formatEndpointUrl('http://localhost:4318/', 'traces', 'http'),
|
|
114
|
+
).toBe('http://localhost:4318//v1/traces');
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('formatEndpointUrl() for gRPC protocol', () => {
|
|
119
|
+
it('should not append paths for gRPC', () => {
|
|
120
|
+
expect(formatEndpointUrl('api.honeycomb.io:443', 'traces', 'grpc')).toBe(
|
|
121
|
+
'api.honeycomb.io:443',
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should strip /v1/traces path from gRPC endpoints', () => {
|
|
126
|
+
expect(
|
|
127
|
+
formatEndpointUrl('api.example.com/v1/traces', 'traces', 'grpc'),
|
|
128
|
+
).toBe('api.example.com');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should strip /v1/metrics path from gRPC endpoints', () => {
|
|
132
|
+
expect(
|
|
133
|
+
formatEndpointUrl('api.example.com/v1/metrics', 'metrics', 'grpc'),
|
|
134
|
+
).toBe('api.example.com');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should strip /v1/logs path from gRPC endpoints', () => {
|
|
138
|
+
expect(
|
|
139
|
+
formatEndpointUrl('api.example.com/v1/logs', 'traces', 'grpc'),
|
|
140
|
+
).toBe('api.example.com');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should strip paths without v1 prefix', () => {
|
|
144
|
+
expect(
|
|
145
|
+
formatEndpointUrl('api.example.com/traces', 'traces', 'grpc'),
|
|
146
|
+
).toBe('api.example.com');
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should handle gRPC URLs with grpc:// scheme', () => {
|
|
150
|
+
expect(formatEndpointUrl('grpc://localhost:4317', 'traces', 'grpc')).toBe(
|
|
151
|
+
'grpc://localhost:4317',
|
|
152
|
+
);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should handle gRPC URLs with port numbers', () => {
|
|
156
|
+
expect(
|
|
157
|
+
formatEndpointUrl('collector.example.com:4317', 'traces', 'grpc'),
|
|
158
|
+
).toBe('collector.example.com:4317');
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('Edge cases', () => {
|
|
163
|
+
it('should handle empty endpoint for HTTP', () => {
|
|
164
|
+
expect(formatEndpointUrl('', 'traces', 'http')).toBe('/v1/traces');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should handle empty endpoint for gRPC', () => {
|
|
168
|
+
expect(formatEndpointUrl('', 'traces', 'grpc')).toBe('');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should preserve query parameters in HTTP', () => {
|
|
172
|
+
expect(
|
|
173
|
+
formatEndpointUrl('http://localhost:4318?foo=bar', 'traces', 'http'),
|
|
174
|
+
).toBe('http://localhost:4318?foo=bar/v1/traces');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should preserve query parameters in gRPC', () => {
|
|
178
|
+
expect(
|
|
179
|
+
formatEndpointUrl('api.example.com:443?foo=bar', 'traces', 'grpc'),
|
|
180
|
+
).toBe('api.example.com:443?foo=bar');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('Protocol configuration documentation', () => {
|
|
186
|
+
it('should document HTTP as default protocol', () => {
|
|
187
|
+
const defaultProtocol = resolveProtocol();
|
|
188
|
+
expect(defaultProtocol).toBe('http');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('should document Honeycomb endpoint format', () => {
|
|
192
|
+
const honeycombEndpoint = 'api.honeycomb.io:443';
|
|
193
|
+
const formattedForGrpc = formatEndpointUrl(
|
|
194
|
+
honeycombEndpoint,
|
|
195
|
+
'traces',
|
|
196
|
+
'grpc',
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(formattedForGrpc).toBe('api.honeycomb.io:443');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should document local collector HTTP format', () => {
|
|
203
|
+
const httpEndpoint = 'http://localhost:4318';
|
|
204
|
+
const formattedForHttp = formatEndpointUrl(httpEndpoint, 'traces', 'http');
|
|
205
|
+
|
|
206
|
+
expect(formattedForHttp).toBe('http://localhost:4318/v1/traces');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should document local collector gRPC format', () => {
|
|
210
|
+
const grpcEndpoint = 'localhost:4317';
|
|
211
|
+
const formattedForGrpc = formatEndpointUrl(grpcEndpoint, 'traces', 'grpc');
|
|
212
|
+
|
|
213
|
+
expect(formattedForGrpc).toBe('localhost:4317');
|
|
214
|
+
});
|
|
215
|
+
});
|