autotel 2.25.1 → 2.25.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto.cjs +2 -2
- package/dist/auto.js +1 -1
- package/dist/{chunk-HCFBEOBM.cjs → chunk-4KGC5N3J.cjs} +13 -13
- package/dist/{chunk-HCFBEOBM.cjs.map → chunk-4KGC5N3J.cjs.map} +1 -1
- package/dist/{chunk-NYTCPK4J.js → chunk-4SCBD22Z.js} +3 -3
- package/dist/{chunk-NYTCPK4J.js.map → chunk-4SCBD22Z.js.map} +1 -1
- package/dist/{chunk-JZKMXKJX.js → chunk-77PLEJ54.js} +3 -3
- package/dist/{chunk-JZKMXKJX.js.map → chunk-77PLEJ54.js.map} +1 -1
- package/dist/{chunk-JDV3LYOI.js → chunk-IKRHEUS7.js} +3 -3
- package/dist/{chunk-JDV3LYOI.js.map → chunk-IKRHEUS7.js.map} +1 -1
- package/dist/{chunk-GIND746I.cjs → chunk-JVICEM6W.cjs} +78 -2
- package/dist/chunk-JVICEM6W.cjs.map +1 -0
- package/dist/{chunk-P5YCN2Z3.js → chunk-KUSYIHW7.js} +3 -3
- package/dist/{chunk-P5YCN2Z3.js.map → chunk-KUSYIHW7.js.map} +1 -1
- package/dist/{chunk-LRFG6HRL.cjs → chunk-L627YSSP.cjs} +5 -5
- package/dist/{chunk-LRFG6HRL.cjs.map → chunk-L627YSSP.cjs.map} +1 -1
- package/dist/{chunk-DBUNRUDB.cjs → chunk-MNMLCLHH.cjs} +5 -5
- package/dist/{chunk-DBUNRUDB.cjs.map → chunk-MNMLCLHH.cjs.map} +1 -1
- package/dist/{chunk-BKIAH2YS.js → chunk-QUW4I2OI.js} +3 -3
- package/dist/{chunk-BKIAH2YS.js.map → chunk-QUW4I2OI.js.map} +1 -1
- package/dist/{chunk-7ZYUFMWU.cjs → chunk-RWOVNF3V.cjs} +26 -26
- package/dist/{chunk-7ZYUFMWU.cjs.map → chunk-RWOVNF3V.cjs.map} +1 -1
- package/dist/{chunk-73SCHI7V.cjs → chunk-UKUYBUFQ.cjs} +7 -7
- package/dist/{chunk-73SCHI7V.cjs.map → chunk-UKUYBUFQ.cjs.map} +1 -1
- package/dist/{chunk-7RV6L24E.js → chunk-VXLEJWLY.js} +79 -3
- package/dist/chunk-VXLEJWLY.js.map +1 -0
- package/dist/decorators.cjs +2 -2
- package/dist/decorators.js +2 -2
- package/dist/event.cjs +5 -5
- package/dist/event.js +2 -2
- package/dist/functional.cjs +9 -9
- package/dist/functional.js +2 -2
- package/dist/index.cjs +41 -41
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -9
- package/dist/{init-Co9CWOY6.d.cts → init-Q4uIQKbq.d.cts} +25 -0
- package/dist/{init-oLqNJTpj.d.ts → init-ls4xSZe5.d.ts} +25 -0
- package/dist/instrumentation.cjs +8 -8
- package/dist/instrumentation.js +1 -1
- package/dist/messaging.cjs +6 -6
- package/dist/messaging.js +3 -3
- package/dist/semantic-helpers.cjs +7 -7
- package/dist/semantic-helpers.js +3 -3
- package/dist/webhook.cjs +3 -3
- package/dist/webhook.js +2 -2
- package/dist/workflow-distributed.cjs +4 -4
- package/dist/workflow-distributed.js +2 -2
- package/dist/workflow.cjs +7 -7
- package/dist/workflow.js +3 -3
- package/dist/yaml-config.d.cts +1 -1
- package/dist/yaml-config.d.ts +1 -1
- package/package.json +3 -11
- package/src/init.customization.test.ts +152 -0
- package/src/init.ts +158 -5
- package/src/posthog-logs.ts +1 -1
- package/dist/chunk-7RV6L24E.js.map +0 -1
- package/dist/chunk-GIND746I.cjs.map +0 -1
package/dist/webhook.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { trace } from './chunk-
|
|
1
|
+
import { trace } from './chunk-IKRHEUS7.js';
|
|
2
2
|
import './chunk-SR35DG5A.js';
|
|
3
3
|
import './chunk-B3ZHLLMP.js';
|
|
4
4
|
import './chunk-WD4RP6IV.js';
|
|
5
5
|
import './chunk-USSL3D6L.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-VXLEJWLY.js';
|
|
7
7
|
import './chunk-YTGF4L2C.js';
|
|
8
8
|
import './chunk-X4RMFFMR.js';
|
|
9
9
|
import './chunk-WGWSHJ2N.js';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkINJD3G4K_cjs = require('./chunk-INJD3G4K.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkRWOVNF3V_cjs = require('./chunk-RWOVNF3V.cjs');
|
|
5
5
|
require('./chunk-W4EUTSB2.cjs');
|
|
6
6
|
require('./chunk-GML3FBOT.cjs');
|
|
7
7
|
require('./chunk-D5LMF53P.cjs');
|
|
8
8
|
require('./chunk-XRKAL7WJ.cjs');
|
|
9
|
-
require('./chunk-
|
|
9
|
+
require('./chunk-JVICEM6W.cjs');
|
|
10
10
|
require('./chunk-6YIDHH2S.cjs');
|
|
11
11
|
require('./chunk-GVLK7YUU.cjs');
|
|
12
12
|
require('./chunk-ZNMBW67B.cjs');
|
|
@@ -59,7 +59,7 @@ var WorkflowBaggage = chunkINJD3G4K_cjs.createSafeBaggageSchema(workflowBaggageF
|
|
|
59
59
|
function traceDistributedWorkflow(config) {
|
|
60
60
|
const spanName = `workflow.${config.name}`;
|
|
61
61
|
return (fnFactory) => {
|
|
62
|
-
return
|
|
62
|
+
return chunkRWOVNF3V_cjs.trace(
|
|
63
63
|
{ name: spanName, spanKind: api.SpanKind.INTERNAL },
|
|
64
64
|
(baseCtx) => {
|
|
65
65
|
return async (...args) => {
|
|
@@ -158,7 +158,7 @@ function traceDistributedWorkflow(config) {
|
|
|
158
158
|
function traceDistributedStep(config) {
|
|
159
159
|
const spanName = `workflow.step.${config.name}`;
|
|
160
160
|
return (fnFactory) => {
|
|
161
|
-
return
|
|
161
|
+
return chunkRWOVNF3V_cjs.trace(
|
|
162
162
|
{ name: spanName, spanKind: api.SpanKind.INTERNAL },
|
|
163
163
|
(baseCtx) => {
|
|
164
164
|
return async (...args) => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createSafeBaggageSchema } from './chunk-4IFSYQVX.js';
|
|
2
|
-
import { trace } from './chunk-
|
|
2
|
+
import { trace } from './chunk-IKRHEUS7.js';
|
|
3
3
|
import './chunk-SR35DG5A.js';
|
|
4
4
|
import './chunk-B3ZHLLMP.js';
|
|
5
5
|
import './chunk-WD4RP6IV.js';
|
|
6
6
|
import './chunk-USSL3D6L.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-VXLEJWLY.js';
|
|
8
8
|
import './chunk-YTGF4L2C.js';
|
|
9
9
|
import './chunk-X4RMFFMR.js';
|
|
10
10
|
import './chunk-WGWSHJ2N.js';
|
package/dist/workflow.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
3
|
+
var chunkMNMLCLHH_cjs = require('./chunk-MNMLCLHH.cjs');
|
|
4
|
+
require('./chunk-RWOVNF3V.cjs');
|
|
5
5
|
require('./chunk-W4EUTSB2.cjs');
|
|
6
6
|
require('./chunk-GML3FBOT.cjs');
|
|
7
7
|
require('./chunk-D5LMF53P.cjs');
|
|
8
8
|
require('./chunk-XRKAL7WJ.cjs');
|
|
9
|
-
require('./chunk-
|
|
9
|
+
require('./chunk-JVICEM6W.cjs');
|
|
10
10
|
require('./chunk-6YIDHH2S.cjs');
|
|
11
11
|
require('./chunk-GVLK7YUU.cjs');
|
|
12
12
|
require('./chunk-ZNMBW67B.cjs');
|
|
@@ -25,19 +25,19 @@ require('./chunk-JEQ2X3Z6.cjs');
|
|
|
25
25
|
|
|
26
26
|
Object.defineProperty(exports, "getCurrentWorkflowContext", {
|
|
27
27
|
enumerable: true,
|
|
28
|
-
get: function () { return
|
|
28
|
+
get: function () { return chunkMNMLCLHH_cjs.getCurrentWorkflowContext; }
|
|
29
29
|
});
|
|
30
30
|
Object.defineProperty(exports, "isInWorkflow", {
|
|
31
31
|
enumerable: true,
|
|
32
|
-
get: function () { return
|
|
32
|
+
get: function () { return chunkMNMLCLHH_cjs.isInWorkflow; }
|
|
33
33
|
});
|
|
34
34
|
Object.defineProperty(exports, "traceStep", {
|
|
35
35
|
enumerable: true,
|
|
36
|
-
get: function () { return
|
|
36
|
+
get: function () { return chunkMNMLCLHH_cjs.traceStep; }
|
|
37
37
|
});
|
|
38
38
|
Object.defineProperty(exports, "traceWorkflow", {
|
|
39
39
|
enumerable: true,
|
|
40
|
-
get: function () { return
|
|
40
|
+
get: function () { return chunkMNMLCLHH_cjs.traceWorkflow; }
|
|
41
41
|
});
|
|
42
42
|
//# sourceMappingURL=workflow.cjs.map
|
|
43
43
|
//# sourceMappingURL=workflow.cjs.map
|
package/dist/workflow.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export { getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { getCurrentWorkflowContext, isInWorkflow, traceStep, traceWorkflow } from './chunk-KUSYIHW7.js';
|
|
2
|
+
import './chunk-IKRHEUS7.js';
|
|
3
3
|
import './chunk-SR35DG5A.js';
|
|
4
4
|
import './chunk-B3ZHLLMP.js';
|
|
5
5
|
import './chunk-WD4RP6IV.js';
|
|
6
6
|
import './chunk-USSL3D6L.js';
|
|
7
|
-
import './chunk-
|
|
7
|
+
import './chunk-VXLEJWLY.js';
|
|
8
8
|
import './chunk-YTGF4L2C.js';
|
|
9
9
|
import './chunk-X4RMFFMR.js';
|
|
10
10
|
import './chunk-WGWSHJ2N.js';
|
package/dist/yaml-config.d.cts
CHANGED
package/dist/yaml-config.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel",
|
|
3
|
-
"version": "2.25.
|
|
3
|
+
"version": "2.25.2",
|
|
4
4
|
"description": "Write Once, Observe Anywhere",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -251,10 +251,12 @@
|
|
|
251
251
|
"dependencies": {
|
|
252
252
|
"@opentelemetry/api": "^1.9.0",
|
|
253
253
|
"@opentelemetry/api-logs": "^0.213.0",
|
|
254
|
+
"@opentelemetry/exporter-logs-otlp-http": "^0.213.0",
|
|
254
255
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.213.0",
|
|
255
256
|
"@opentelemetry/exporter-trace-otlp-http": "^0.213.0",
|
|
256
257
|
"@opentelemetry/instrumentation": "^0.213.0",
|
|
257
258
|
"@opentelemetry/resources": "^2.6.0",
|
|
259
|
+
"@opentelemetry/sdk-logs": "^0.213.0",
|
|
258
260
|
"@opentelemetry/sdk-metrics": "^2.6.0",
|
|
259
261
|
"@opentelemetry/sdk-node": "^0.213.0",
|
|
260
262
|
"@opentelemetry/sdk-trace-base": "^2.6.0",
|
|
@@ -265,13 +267,11 @@
|
|
|
265
267
|
"peerDependencies": {
|
|
266
268
|
"@opentelemetry/auto-instrumentations-node": "^0.71.0",
|
|
267
269
|
"@opentelemetry/exporter-logs-otlp-grpc": "^0.213.0",
|
|
268
|
-
"@opentelemetry/exporter-logs-otlp-http": "^0.213.0",
|
|
269
270
|
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.213.0",
|
|
270
271
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0",
|
|
271
272
|
"@opentelemetry/resource-detector-aws": "^2.13.0",
|
|
272
273
|
"@opentelemetry/resource-detector-container": "^0.8.4",
|
|
273
274
|
"@opentelemetry/resource-detector-gcp": "^0.48.0",
|
|
274
|
-
"@opentelemetry/sdk-logs": "^0.213.0",
|
|
275
275
|
"@opentelemetry/sdk-trace-node": "^2.6.0",
|
|
276
276
|
"@traceloop/node-server-sdk": "^0.22.8",
|
|
277
277
|
"pino": "^10.3.1",
|
|
@@ -285,18 +285,12 @@
|
|
|
285
285
|
"@opentelemetry/exporter-logs-otlp-grpc": {
|
|
286
286
|
"optional": true
|
|
287
287
|
},
|
|
288
|
-
"@opentelemetry/exporter-logs-otlp-http": {
|
|
289
|
-
"optional": true
|
|
290
|
-
},
|
|
291
288
|
"@opentelemetry/exporter-metrics-otlp-grpc": {
|
|
292
289
|
"optional": true
|
|
293
290
|
},
|
|
294
291
|
"@opentelemetry/exporter-trace-otlp-grpc": {
|
|
295
292
|
"optional": true
|
|
296
293
|
},
|
|
297
|
-
"@opentelemetry/sdk-logs": {
|
|
298
|
-
"optional": true
|
|
299
|
-
},
|
|
300
294
|
"@opentelemetry/sdk-trace-node": {
|
|
301
295
|
"optional": true
|
|
302
296
|
},
|
|
@@ -328,13 +322,11 @@
|
|
|
328
322
|
"@opentelemetry/auto-instrumentations-node": "^0.71.0",
|
|
329
323
|
"@opentelemetry/context-async-hooks": "^2.6.0",
|
|
330
324
|
"@opentelemetry/exporter-logs-otlp-grpc": "^0.213.0",
|
|
331
|
-
"@opentelemetry/exporter-logs-otlp-http": "^0.213.0",
|
|
332
325
|
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.213.0",
|
|
333
326
|
"@opentelemetry/exporter-trace-otlp-grpc": "^0.213.0",
|
|
334
327
|
"@opentelemetry/resource-detector-aws": "^2.13.0",
|
|
335
328
|
"@opentelemetry/resource-detector-container": "^0.8.4",
|
|
336
329
|
"@opentelemetry/resource-detector-gcp": "^0.48.0",
|
|
337
|
-
"@opentelemetry/sdk-logs": "^0.213.0",
|
|
338
330
|
"@opentelemetry/sdk-trace-node": "^2.6.0",
|
|
339
331
|
"@swc/core": "^1.15.21",
|
|
340
332
|
"@total-typescript/ts-reset": "^0.6.1",
|
|
@@ -14,6 +14,8 @@ async function loadInitWithMocks() {
|
|
|
14
14
|
const traceExporterOptions: Record<string, unknown>[] = [];
|
|
15
15
|
const metricExporterOptions: Record<string, unknown>[] = [];
|
|
16
16
|
const metricReaderOptions: Record<string, unknown>[] = [];
|
|
17
|
+
const logExporterOptions: Record<string, unknown>[] = [];
|
|
18
|
+
const logProcessorOptions: Record<string, unknown>[] = [];
|
|
17
19
|
|
|
18
20
|
class MockNodeSDK {
|
|
19
21
|
constructor(options: Record<string, unknown>) {
|
|
@@ -71,15 +73,52 @@ async function loadInitWithMocks() {
|
|
|
71
73
|
PeriodicExportingMetricReader: MockPeriodicExportingMetricReader,
|
|
72
74
|
}));
|
|
73
75
|
|
|
76
|
+
class MockOTLPLogExporter {
|
|
77
|
+
options: Record<string, unknown>;
|
|
78
|
+
|
|
79
|
+
constructor(options: Record<string, unknown>) {
|
|
80
|
+
this.options = options;
|
|
81
|
+
logExporterOptions.push(options);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
class MockBatchLogRecordProcessor {
|
|
86
|
+
exporter: unknown;
|
|
87
|
+
|
|
88
|
+
constructor(exporter: unknown) {
|
|
89
|
+
this.exporter = exporter;
|
|
90
|
+
logProcessorOptions.push({ exporter });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
onEmit() {}
|
|
94
|
+
shutdown() {
|
|
95
|
+
return Promise.resolve();
|
|
96
|
+
}
|
|
97
|
+
forceFlush() {
|
|
98
|
+
return Promise.resolve();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
vi.doMock('@opentelemetry/exporter-logs-otlp-http', () => ({
|
|
103
|
+
OTLPLogExporter: MockOTLPLogExporter,
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
vi.doMock('@opentelemetry/sdk-logs', () => ({
|
|
107
|
+
BatchLogRecordProcessor: MockBatchLogRecordProcessor,
|
|
108
|
+
}));
|
|
109
|
+
|
|
74
110
|
const mod = await import('./init');
|
|
75
111
|
|
|
76
112
|
return {
|
|
77
113
|
init: mod.init,
|
|
78
114
|
getConfig: mod.getConfig,
|
|
115
|
+
resolveLogsFlag: mod.resolveLogsFlag,
|
|
79
116
|
sdkInstances,
|
|
80
117
|
traceExporterOptions,
|
|
81
118
|
metricExporterOptions,
|
|
82
119
|
metricReaderOptions,
|
|
120
|
+
logExporterOptions,
|
|
121
|
+
logProcessorOptions,
|
|
83
122
|
};
|
|
84
123
|
}
|
|
85
124
|
|
|
@@ -87,6 +126,8 @@ describe('init() customization', () => {
|
|
|
87
126
|
afterEach(() => {
|
|
88
127
|
vi.restoreAllMocks();
|
|
89
128
|
delete process.env.AUTOTEL_METRICS;
|
|
129
|
+
delete process.env.AUTOTEL_LOGS;
|
|
130
|
+
delete process.env.OTEL_LOGS_EXPORTER;
|
|
90
131
|
delete process.env.NODE_ENV;
|
|
91
132
|
});
|
|
92
133
|
|
|
@@ -217,4 +258,115 @@ describe('init() customization', () => {
|
|
|
217
258
|
const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
|
|
218
259
|
expect(options.spanProcessors).toEqual([customProcessor]);
|
|
219
260
|
});
|
|
261
|
+
|
|
262
|
+
it('auto-configures OTLP log exporter when logs enabled with endpoint', async () => {
|
|
263
|
+
const { init, sdkInstances, logExporterOptions } =
|
|
264
|
+
await loadInitWithMocks();
|
|
265
|
+
|
|
266
|
+
init({
|
|
267
|
+
service: 'log-app',
|
|
268
|
+
endpoint: 'http://localhost:4318',
|
|
269
|
+
logs: true,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(logExporterOptions).toHaveLength(1);
|
|
273
|
+
expect(logExporterOptions[0]!.url).toBe('http://localhost:4318/v1/logs');
|
|
274
|
+
const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
|
|
275
|
+
expect(options.logRecordProcessors).toBeDefined();
|
|
276
|
+
expect(
|
|
277
|
+
(options.logRecordProcessors as unknown[]).length,
|
|
278
|
+
).toBeGreaterThanOrEqual(1);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('does not auto-configure logs when logRecordProcessors are omitted', async () => {
|
|
282
|
+
const { init, sdkInstances, logExporterOptions } =
|
|
283
|
+
await loadInitWithMocks();
|
|
284
|
+
|
|
285
|
+
init({
|
|
286
|
+
service: 'default-logs',
|
|
287
|
+
endpoint: 'http://localhost:4318',
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
expect(logExporterOptions).toHaveLength(0);
|
|
291
|
+
const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
|
|
292
|
+
expect(options.logRecordProcessors).toBeUndefined();
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('does not override OTEL_LOGS_EXPORTER env configuration by default', async () => {
|
|
296
|
+
const { init, sdkInstances, logExporterOptions } =
|
|
297
|
+
await loadInitWithMocks();
|
|
298
|
+
|
|
299
|
+
process.env.OTEL_LOGS_EXPORTER = 'none';
|
|
300
|
+
|
|
301
|
+
init({
|
|
302
|
+
service: 'env-logs',
|
|
303
|
+
endpoint: 'http://localhost:4318',
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
expect(logExporterOptions).toHaveLength(0);
|
|
307
|
+
const options = sdkInstances.at(-1)?.options as Record<string, unknown>;
|
|
308
|
+
expect(options.logRecordProcessors).toBeUndefined();
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('auto-configures logs when logs: true is set', async () => {
|
|
312
|
+
const { init, logExporterOptions } = await loadInitWithMocks();
|
|
313
|
+
|
|
314
|
+
init({
|
|
315
|
+
service: 'default-logs',
|
|
316
|
+
endpoint: 'http://localhost:4318',
|
|
317
|
+
logs: true,
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
expect(logExporterOptions).toHaveLength(1);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it('skips log exporter when logs: false', async () => {
|
|
324
|
+
const { init, logExporterOptions } = await loadInitWithMocks();
|
|
325
|
+
|
|
326
|
+
init({
|
|
327
|
+
service: 'no-logs',
|
|
328
|
+
endpoint: 'http://localhost:4318',
|
|
329
|
+
logs: false,
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
expect(logExporterOptions).toHaveLength(0);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('skips log exporter when no endpoint', async () => {
|
|
336
|
+
const { init, logExporterOptions } = await loadInitWithMocks();
|
|
337
|
+
|
|
338
|
+
init({ service: 'no-endpoint', logs: true });
|
|
339
|
+
|
|
340
|
+
expect(logExporterOptions).toHaveLength(0);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('respects AUTOTEL_LOGS env var override', async () => {
|
|
344
|
+
const { resolveLogsFlag } = await loadInitWithMocks();
|
|
345
|
+
|
|
346
|
+
process.env.AUTOTEL_LOGS = 'off';
|
|
347
|
+
expect(resolveLogsFlag(true)).toBe(false);
|
|
348
|
+
|
|
349
|
+
process.env.AUTOTEL_LOGS = 'on';
|
|
350
|
+
expect(resolveLogsFlag(false)).toBe(true);
|
|
351
|
+
|
|
352
|
+
delete process.env.AUTOTEL_LOGS;
|
|
353
|
+
expect(resolveLogsFlag(true)).toBe(true);
|
|
354
|
+
expect(resolveLogsFlag(false)).toBe(false);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it('passes OTLP headers to log exporter', async () => {
|
|
358
|
+
const { init, logExporterOptions } = await loadInitWithMocks();
|
|
359
|
+
|
|
360
|
+
init({
|
|
361
|
+
service: 'headers-logs',
|
|
362
|
+
endpoint: 'http://localhost:4318',
|
|
363
|
+
logs: true,
|
|
364
|
+
headers: { Authorization: 'Bearer token' },
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
expect(logExporterOptions).toHaveLength(1);
|
|
368
|
+
expect(logExporterOptions[0]!.headers).toEqual({
|
|
369
|
+
Authorization: 'Bearer token',
|
|
370
|
+
});
|
|
371
|
+
});
|
|
220
372
|
});
|
package/src/init.ts
CHANGED
|
@@ -12,8 +12,11 @@ import {
|
|
|
12
12
|
type SpanProcessor,
|
|
13
13
|
SimpleSpanProcessor,
|
|
14
14
|
ConsoleSpanExporter,
|
|
15
|
+
SamplingDecision,
|
|
16
|
+
type SpanExporter,
|
|
17
|
+
type Sampler as OtelSampler,
|
|
18
|
+
type SamplingResult,
|
|
15
19
|
} from '@opentelemetry/sdk-trace-base';
|
|
16
|
-
import type { SpanExporter } from '@opentelemetry/sdk-trace-base';
|
|
17
20
|
import {
|
|
18
21
|
resourceFromAttributes,
|
|
19
22
|
type Resource,
|
|
@@ -26,7 +29,7 @@ import type { Sampler } from './sampling';
|
|
|
26
29
|
import { AdaptiveSampler } from './sampling';
|
|
27
30
|
import type { EventSubscriber } from './event-subscriber';
|
|
28
31
|
import type { Logger } from './logger';
|
|
29
|
-
import type { Attributes } from '@opentelemetry/api';
|
|
32
|
+
import type { Attributes, Context, SpanKind, Link } from '@opentelemetry/api';
|
|
30
33
|
import type { ValidationConfig } from './validation';
|
|
31
34
|
import {
|
|
32
35
|
PeriodicExportingMetricReader,
|
|
@@ -34,9 +37,17 @@ import {
|
|
|
34
37
|
} from '@opentelemetry/sdk-metrics';
|
|
35
38
|
import { OTLPMetricExporter as OTLPMetricExporterHTTP } from '@opentelemetry/exporter-metrics-otlp-http';
|
|
36
39
|
import { OTLPTraceExporter as OTLPTraceExporterHTTP } from '@opentelemetry/exporter-trace-otlp-http';
|
|
40
|
+
import { OTLPLogExporter as OTLPLogExporterHTTP } from '@opentelemetry/exporter-logs-otlp-http';
|
|
37
41
|
import type { PushMetricExporter } from '@opentelemetry/sdk-metrics';
|
|
38
|
-
import
|
|
39
|
-
|
|
42
|
+
import {
|
|
43
|
+
BatchLogRecordProcessor,
|
|
44
|
+
type LogRecordExporter,
|
|
45
|
+
type LogRecordProcessor,
|
|
46
|
+
} from '@opentelemetry/sdk-logs';
|
|
47
|
+
import {
|
|
48
|
+
buildPostHogLogProcessors,
|
|
49
|
+
RedactingLogRecordProcessor,
|
|
50
|
+
} from './posthog-logs';
|
|
40
51
|
import { TailSamplingSpanProcessor } from './tail-sampling-processor';
|
|
41
52
|
import { BaggageSpanProcessor } from './baggage-span-processor';
|
|
42
53
|
import {
|
|
@@ -75,6 +86,36 @@ const silentLogger: Logger = {
|
|
|
75
86
|
debug: () => {},
|
|
76
87
|
};
|
|
77
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Adapts an Autotel Sampler to the OTel SDK Sampler interface.
|
|
91
|
+
*/
|
|
92
|
+
function toOtelSampler(sampler: Sampler): OtelSampler {
|
|
93
|
+
return {
|
|
94
|
+
shouldSample(
|
|
95
|
+
_context: Context,
|
|
96
|
+
_traceId: string,
|
|
97
|
+
spanName: string,
|
|
98
|
+
_spanKind: SpanKind,
|
|
99
|
+
_attributes: Attributes,
|
|
100
|
+
links: Link[],
|
|
101
|
+
): SamplingResult {
|
|
102
|
+
const shouldTrace = sampler.shouldSample({
|
|
103
|
+
operationName: spanName,
|
|
104
|
+
args: [],
|
|
105
|
+
links,
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
decision: shouldTrace
|
|
109
|
+
? SamplingDecision.RECORD_AND_SAMPLED
|
|
110
|
+
: SamplingDecision.NOT_RECORD,
|
|
111
|
+
};
|
|
112
|
+
},
|
|
113
|
+
toString(): string {
|
|
114
|
+
return `AutotelSamplerAdapter`;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
78
119
|
// Type imports for exporters
|
|
79
120
|
type OTLPExporterConfig = {
|
|
80
121
|
url?: string;
|
|
@@ -90,6 +131,9 @@ let OTLPTraceExporterGRPC:
|
|
|
90
131
|
let OTLPMetricExporterGRPC:
|
|
91
132
|
| (new (config: OTLPExporterConfig) => PushMetricExporter)
|
|
92
133
|
| undefined;
|
|
134
|
+
let OTLPLogExporterGRPC:
|
|
135
|
+
| (new (config: OTLPExporterConfig) => LogRecordExporter)
|
|
136
|
+
| undefined;
|
|
93
137
|
|
|
94
138
|
/**
|
|
95
139
|
* Helper: Lazy-load gRPC trace exporter
|
|
@@ -169,6 +213,43 @@ function createMetricExporter(
|
|
|
169
213
|
return new OTLPMetricExporterHTTP(config);
|
|
170
214
|
}
|
|
171
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Helper: Lazy-load gRPC log exporter
|
|
218
|
+
*/
|
|
219
|
+
function loadGRPCLogExporter(): new (
|
|
220
|
+
config: OTLPExporterConfig,
|
|
221
|
+
) => LogRecordExporter {
|
|
222
|
+
if (OTLPLogExporterGRPC) return OTLPLogExporterGRPC;
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const grpcModule = requireModule<{
|
|
226
|
+
OTLPLogExporter: new (config: OTLPExporterConfig) => LogRecordExporter;
|
|
227
|
+
}>('@opentelemetry/exporter-logs-otlp-grpc');
|
|
228
|
+
OTLPLogExporterGRPC = grpcModule.OTLPLogExporter;
|
|
229
|
+
return OTLPLogExporterGRPC;
|
|
230
|
+
} catch {
|
|
231
|
+
throw new Error(
|
|
232
|
+
'gRPC log exporter not found. Install @opentelemetry/exporter-logs-otlp-grpc',
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Helper: Create log exporter based on protocol
|
|
239
|
+
*/
|
|
240
|
+
function createLogExporter(
|
|
241
|
+
protocol: 'http' | 'grpc',
|
|
242
|
+
config: OTLPExporterConfig,
|
|
243
|
+
): LogRecordExporter {
|
|
244
|
+
if (protocol === 'grpc') {
|
|
245
|
+
const Exporter = loadGRPCLogExporter();
|
|
246
|
+
return new Exporter(config);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Default: HTTP
|
|
250
|
+
return new OTLPLogExporterHTTP(config);
|
|
251
|
+
}
|
|
252
|
+
|
|
172
253
|
/**
|
|
173
254
|
* Helper: Resolve protocol from config and environment
|
|
174
255
|
*/
|
|
@@ -194,7 +275,7 @@ function resolveProtocol(configProtocol?: 'http' | 'grpc'): 'http' | 'grpc' {
|
|
|
194
275
|
*/
|
|
195
276
|
function formatEndpointUrl(
|
|
196
277
|
endpoint: string,
|
|
197
|
-
signal: 'traces' | 'metrics',
|
|
278
|
+
signal: 'traces' | 'metrics' | 'logs',
|
|
198
279
|
protocol: 'http' | 'grpc',
|
|
199
280
|
): string {
|
|
200
281
|
if (protocol === 'grpc') {
|
|
@@ -496,6 +577,32 @@ export interface AutotelConfig {
|
|
|
496
577
|
*/
|
|
497
578
|
metrics?: boolean | 'auto';
|
|
498
579
|
|
|
580
|
+
/**
|
|
581
|
+
* OTLP logs configuration
|
|
582
|
+
* - true: auto-configure OTLP log exporter from endpoint
|
|
583
|
+
* - false: disabled (default)
|
|
584
|
+
* - 'auto': same as false (opt-in only)
|
|
585
|
+
*
|
|
586
|
+
* When enabled and an endpoint is configured, autotel will automatically
|
|
587
|
+
* create a BatchLogRecordProcessor with an OTLPLogExporter - no manual
|
|
588
|
+
* imports needed. Works alongside logRecordProcessors (additive).
|
|
589
|
+
*
|
|
590
|
+
* Requires @opentelemetry/sdk-logs and @opentelemetry/exporter-logs-otlp-http
|
|
591
|
+
* (or -grpc) as peer dependencies.
|
|
592
|
+
*
|
|
593
|
+
* Can be overridden with AUTOTEL_LOGS=on|off env var.
|
|
594
|
+
*
|
|
595
|
+
* @example
|
|
596
|
+
* ```typescript
|
|
597
|
+
* init({
|
|
598
|
+
* service: 'my-app',
|
|
599
|
+
* endpoint: 'http://localhost:4318',
|
|
600
|
+
* logs: true,
|
|
601
|
+
* });
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
logs?: boolean | 'auto';
|
|
605
|
+
|
|
499
606
|
/** Sampling strategy (default: AdaptiveSampler with 10% baseline) */
|
|
500
607
|
sampler?: Sampler;
|
|
501
608
|
|
|
@@ -1043,6 +1150,27 @@ export function resolveMetricsFlag(
|
|
|
1043
1150
|
return true;
|
|
1044
1151
|
}
|
|
1045
1152
|
|
|
1153
|
+
/**
|
|
1154
|
+
* Resolve logs flag with env var override support.
|
|
1155
|
+
* Defaults to disabled (opt-in only) to avoid unexpected log export
|
|
1156
|
+
* and to preserve the upstream SDK's OTEL_LOGS_EXPORTER handling.
|
|
1157
|
+
*/
|
|
1158
|
+
export function resolveLogsFlag(
|
|
1159
|
+
configFlag: boolean | 'auto' = 'auto',
|
|
1160
|
+
): boolean {
|
|
1161
|
+
// 1. Check env var override (highest priority)
|
|
1162
|
+
const envFlag = process.env.AUTOTEL_LOGS;
|
|
1163
|
+
if (envFlag === 'on' || envFlag === 'true') return true;
|
|
1164
|
+
if (envFlag === 'off' || envFlag === 'false') return false;
|
|
1165
|
+
|
|
1166
|
+
// 2. Check config flag
|
|
1167
|
+
if (configFlag === true) return true;
|
|
1168
|
+
if (configFlag === false) return false;
|
|
1169
|
+
|
|
1170
|
+
// 3. Default: disabled (opt-in only)
|
|
1171
|
+
return false;
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1046
1174
|
/**
|
|
1047
1175
|
* Resolve debug flag with env var override support
|
|
1048
1176
|
*
|
|
@@ -1184,6 +1312,7 @@ export function init(cfg: AutotelConfig): void {
|
|
|
1184
1312
|
const environment =
|
|
1185
1313
|
mergedConfig.environment || process.env.NODE_ENV || 'development';
|
|
1186
1314
|
const metricsEnabled = resolveMetricsFlag(mergedConfig.metrics);
|
|
1315
|
+
const logsEnabled = resolveLogsFlag(mergedConfig.logs);
|
|
1187
1316
|
|
|
1188
1317
|
// Detect hostname for proper Datadog correlation and Service Catalog discovery
|
|
1189
1318
|
const hostname = detectHostname();
|
|
@@ -1373,6 +1502,26 @@ export function init(cfg: AutotelConfig): void {
|
|
|
1373
1502
|
logRecordProcessors = [...mergedConfig.logRecordProcessors];
|
|
1374
1503
|
}
|
|
1375
1504
|
|
|
1505
|
+
// Auto-configure OTLP log exporter when logs are enabled and endpoint is set
|
|
1506
|
+
if (logsEnabled && endpoint) {
|
|
1507
|
+
const logExporter = createLogExporter(protocol, {
|
|
1508
|
+
url: formatEndpointUrl(endpoint, 'logs', protocol),
|
|
1509
|
+
headers: otlpHeaders,
|
|
1510
|
+
});
|
|
1511
|
+
|
|
1512
|
+
let processor: LogRecordProcessor = new BatchLogRecordProcessor(
|
|
1513
|
+
logExporter,
|
|
1514
|
+
);
|
|
1515
|
+
if (_stringRedactor) {
|
|
1516
|
+
processor = new RedactingLogRecordProcessor(processor, _stringRedactor);
|
|
1517
|
+
}
|
|
1518
|
+
if (!logRecordProcessors) {
|
|
1519
|
+
logRecordProcessors = [];
|
|
1520
|
+
}
|
|
1521
|
+
logRecordProcessors.push(processor);
|
|
1522
|
+
logger.info({}, '[autotel] OTLP log exporter configured');
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1376
1525
|
// PostHog OTLP logs integration
|
|
1377
1526
|
const posthogProcessors = buildPostHogLogProcessors(
|
|
1378
1527
|
mergedConfig.posthog,
|
|
@@ -1443,8 +1592,12 @@ export function init(cfg: AutotelConfig): void {
|
|
|
1443
1592
|
}
|
|
1444
1593
|
}
|
|
1445
1594
|
|
|
1595
|
+
const autotelSampler = mergedConfig.sampler || getDefaultSampler();
|
|
1596
|
+
const sampler: OtelSampler = toOtelSampler(autotelSampler);
|
|
1597
|
+
|
|
1446
1598
|
const sdkOptions: Partial<NodeSDKConfiguration> = {
|
|
1447
1599
|
resource,
|
|
1600
|
+
sampler,
|
|
1448
1601
|
instrumentations: finalInstrumentations,
|
|
1449
1602
|
};
|
|
1450
1603
|
|
package/src/posthog-logs.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { LogRecordProcessor } from '@opentelemetry/sdk-logs';
|
|
|
2
2
|
import { safeRequire } from './node-require';
|
|
3
3
|
import type { StringRedactor } from './redact-values';
|
|
4
4
|
|
|
5
|
-
class RedactingLogRecordProcessor implements LogRecordProcessor {
|
|
5
|
+
export class RedactingLogRecordProcessor implements LogRecordProcessor {
|
|
6
6
|
constructor(
|
|
7
7
|
private wrapped: LogRecordProcessor,
|
|
8
8
|
private redact: StringRedactor,
|