Skip to content

Commit d91dbe1

Browse files
authored
feat(exporters)!: use transport interface in node.js exporters (#4743)
* feat(exporters)!: use transport interface in node.js exporters * feat(exporters): hide compression property * feat(otlp-exporter-base)!: remove header property * feat(otlp-exporter-base): add retrying transport * fix: lint * chore: add changelog entry * fix: use queueMicrotask over nextTick * chore: move changelog entry to unreleased * chore: note that user-agent cannot be overwritten by users anymore * fix: export missing ExportResponseRetryable * fix: retry jitter
1 parent 3460a8c commit d91dbe1

File tree

38 files changed

+1225
-741
lines changed

38 files changed

+1225
-741
lines changed

experimental/CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ All notable changes to experimental packages in this project will be documented
88
### :boom: Breaking Change
99

1010
* fix(instrumentation)!:remove unused description property from interface [#4847](https://github.com/open-telemetry/opentelemetry-js/pull/4847) @blumamir
11+
* feat(exporter-*-otlp-*)!: use transport interface in node.js exporters [#4743](https://github.com/open-telemetry/opentelemetry-js/pull/4743) @pichlermarc
12+
* (user-facing) `headers` was intended for internal use has been removed from all exporters
13+
* (user-facing) `compression` was intended for internal use and has been removed from all exporters
14+
* (user-facing) `hostname` was intended for use in tests and is not used by any exporters, it will be removed in a future release
15+
* fix(exporter-*-otlp-*)!: ensure `User-Agent` header cannot be overwritten by the user [#4743](https://github.com/open-telemetry/opentelemetry-js/pull/4743) @pichlermarc
16+
* allowing overrides of the `User-Agent` header was not specification compliant.
1117

1218
### :rocket: (Enhancement)
1319

@@ -79,7 +85,7 @@ All notable changes to experimental packages in this project will be documented
7985

8086
### :bug: (Bug Fix)
8187

82-
* fix(instrumentation): Update `import-in-the-middle` to fix [numerous bugs](https://github.com/DataDog/import-in-the-middle/releases/tag/v1.8.0) [#4745](https://github.com/open-telemetry/opentelemetry-js/pull/4745) @timfish
88+
* fix(instrumentation): Update `import-in-the-middle` to fix [numerous bugs](https://github.com/DataDog/import-in-the-middle/pull/91) [#4745](https://github.com/open-telemetry/opentelemetry-js/pull/4745) @timfish
8389

8490
### :books: (Refine Doc)
8591

experimental/packages/exporter-logs-otlp-http/src/platform/node/OTLPLogExporter.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,15 @@ export class OTLPLogExporter
4949
...config,
5050
},
5151
JsonLogsSerializer,
52-
'application/json'
52+
{
53+
...baggageUtils.parseKeyPairsIntoRecord(
54+
getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
55+
),
56+
...parseHeaders(config?.headers),
57+
...USER_AGENT,
58+
'Content-Type': 'application/json',
59+
}
5360
);
54-
this.headers = {
55-
...this.headers,
56-
...USER_AGENT,
57-
...baggageUtils.parseKeyPairsIntoRecord(
58-
getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
59-
),
60-
...parseHeaders(config?.headers),
61-
};
6261
}
6362

6463
getDefaultUrl(config: OTLPExporterNodeConfigBase): string {

experimental/packages/exporter-logs-otlp-http/test/node/OTLPLogExporter.test.ts

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class MockedResponse extends Stream {
4343
super();
4444
}
4545

46-
send(data: string) {
46+
send(data: Uint8Array) {
4747
this.emit('data', data);
4848
this.emit('end');
4949
}
@@ -65,6 +65,9 @@ describe('OTLPLogExporter', () => {
6565

6666
afterEach(() => {
6767
fakeRequest = new Stream.PassThrough();
68+
Object.defineProperty(fakeRequest, 'setTimeout', {
69+
value: function (_timeout: number) {},
70+
});
6871
sinon.restore();
6972
});
7073

@@ -83,15 +86,20 @@ describe('OTLPLogExporter', () => {
8386
it('should include user-agent header by default', () => {
8487
const exporter = new OTLPLogExporter();
8588
assert.strictEqual(
86-
exporter.headers['User-Agent'],
89+
exporter['_transport']['_transport']['_parameters']['headers'][
90+
'User-Agent'
91+
],
8792
`OTel-OTLP-Exporter-JavaScript/${VERSION}`
8893
);
8994
});
9095

9196
it('should use headers defined via env', () => {
9297
envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS = 'foo=bar';
9398
const exporter = new OTLPLogExporter();
94-
assert.strictEqual(exporter.headers.foo, 'bar');
99+
assert.strictEqual(
100+
exporter['_transport']['_transport']['_parameters']['headers']['foo'],
101+
'bar'
102+
);
95103
delete envSource.OTEL_EXPORTER_OTLP_LOGS_HEADERS;
96104
});
97105

@@ -106,13 +114,19 @@ describe('OTLPLogExporter', () => {
106114

107115
it('should override headers defined via env with headers defined in constructor', () => {
108116
envSource.OTEL_EXPORTER_OTLP_HEADERS = 'foo=bar,bar=foo';
109-
const collectorExporter = new OTLPLogExporter({
117+
const exporter = new OTLPLogExporter({
110118
headers: {
111119
foo: 'constructor',
112120
},
113121
});
114-
assert.strictEqual(collectorExporter.headers.foo, 'constructor');
115-
assert.strictEqual(collectorExporter.headers.bar, 'foo');
122+
assert.strictEqual(
123+
exporter['_transport']['_transport']['_parameters']['headers']['foo'],
124+
'constructor'
125+
);
126+
assert.strictEqual(
127+
exporter['_transport']['_transport']['_parameters']['headers']['bar'],
128+
'foo'
129+
);
116130
envSource.OTEL_EXPORTER_OTLP_HEADERS = '';
117131
});
118132
});
@@ -152,10 +166,12 @@ describe('OTLPLogExporter', () => {
152166
assert.strictEqual(options.method, 'POST');
153167
assert.strictEqual(options.path, '/');
154168

155-
const mockRes = new MockedResponse(200);
156-
cb(mockRes);
157-
mockRes.send('success');
158-
done();
169+
queueMicrotask(() => {
170+
const mockRes = new MockedResponse(200);
171+
cb(mockRes);
172+
mockRes.send(Buffer.from('success'));
173+
done();
174+
});
159175
return fakeRequest as any;
160176
});
161177
collectorExporter.export(logs, () => {});
@@ -165,10 +181,12 @@ describe('OTLPLogExporter', () => {
165181
sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
166182
assert.strictEqual(options.headers['foo'], 'bar');
167183

168-
const mockRes = new MockedResponse(200);
169-
cb(mockRes);
170-
mockRes.send('success');
171-
done();
184+
queueMicrotask(() => {
185+
const mockRes = new MockedResponse(200);
186+
cb(mockRes);
187+
mockRes.send(Buffer.from('success'));
188+
done();
189+
});
172190
return fakeRequest as any;
173191
});
174192

@@ -180,10 +198,12 @@ describe('OTLPLogExporter', () => {
180198
assert.strictEqual(options.agent.keepAlive, true);
181199
assert.strictEqual(options.agent.options.keepAliveMsecs, 2000);
182200

183-
const mockRes = new MockedResponse(200);
184-
cb(mockRes);
185-
mockRes.send('success');
186-
done();
201+
queueMicrotask(() => {
202+
const mockRes = new MockedResponse(200);
203+
cb(mockRes);
204+
mockRes.send(Buffer.from('success'));
205+
done();
206+
});
187207
return fakeRequest as any;
188208
});
189209

@@ -192,10 +212,13 @@ describe('OTLPLogExporter', () => {
192212

193213
it('should successfully send the logs', done => {
194214
const fakeRequest = new Stream.PassThrough();
195-
sinon.stub(http, 'request').returns(fakeRequest as any);
215+
Object.defineProperty(fakeRequest, 'setTimeout', {
216+
value: function (_timeout: number) {},
217+
});
196218

219+
sinon.stub(http, 'request').returns(fakeRequest as any);
197220
let buff = Buffer.from('');
198-
fakeRequest.on('end', () => {
221+
fakeRequest.on('finish', () => {
199222
const responseBody = buff.toString();
200223
const json = JSON.parse(responseBody) as IExportLogsServiceRequest;
201224
const log1 = json.resourceLogs?.[0].scopeLogs?.[0].logRecords?.[0];
@@ -222,9 +245,11 @@ describe('OTLPLogExporter', () => {
222245
const spyLoggerError = sinon.stub(diag, 'error');
223246

224247
sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
225-
const mockRes = new MockedResponse(200);
226-
cb(mockRes);
227-
mockRes.send('success');
248+
queueMicrotask(() => {
249+
const mockRes = new MockedResponse(200);
250+
cb(mockRes);
251+
mockRes.send(Buffer.from('success'));
252+
});
228253
return fakeRequest as any;
229254
});
230255

@@ -237,9 +262,11 @@ describe('OTLPLogExporter', () => {
237262

238263
it('should log the error message', done => {
239264
sinon.stub(http, 'request').callsFake((options: any, cb: any) => {
240-
const mockResError = new MockedResponse(400);
241-
cb(mockResError);
242-
mockResError.send('failed');
265+
queueMicrotask(() => {
266+
const mockRes = new MockedResponse(400);
267+
cb(mockRes);
268+
mockRes.send(Buffer.from('failure'));
269+
});
243270

244271
return fakeRequest as any;
245272
});

experimental/packages/exporter-logs-otlp-proto/src/platform/node/OTLPLogExporter.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,14 @@ export class OTLPLogExporter
4545
implements LogRecordExporter
4646
{
4747
constructor(config: OTLPExporterConfigBase = {}) {
48-
super(config, ProtobufLogsSerializer, 'application/x-protobuf');
49-
const env = getEnv();
50-
this.headers = {
51-
...this.headers,
52-
...USER_AGENT,
48+
super(config, ProtobufLogsSerializer, {
5349
...baggageUtils.parseKeyPairsIntoRecord(
54-
env.OTEL_EXPORTER_OTLP_LOGS_HEADERS
50+
getEnv().OTEL_EXPORTER_OTLP_LOGS_HEADERS
5551
),
5652
...parseHeaders(config?.headers),
57-
};
53+
...USER_AGENT,
54+
'Content-Type': 'application/x-protobuf',
55+
});
5856
}
5957

6058
getDefaultUrl(config: OTLPExporterConfigBase): string {

experimental/packages/exporter-logs-otlp-proto/test/logHelper.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export class MockedResponse extends Stream {
175175
super();
176176
}
177177

178-
send(data: string) {
178+
send(data: Uint8Array) {
179179
this.emit('data', data);
180180
this.emit('end');
181181
}

0 commit comments

Comments
 (0)