Skip to content

Commit e27f9fb

Browse files
authored
chore: adding interceptor for getting headers before each request (#2050)
* chore: adding interceptor for getting headers before each request * chore: renaming getHeadersBeforeSend into getExportRequestHeaders
1 parent 4ef22ca commit e27f9fb

File tree

9 files changed

+162
-5
lines changed

9 files changed

+162
-5
lines changed

examples/tracer-web/examples/zipkin/index.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
44

55
const provider = new WebTracerProvider();
66
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
7-
provider.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter()));
7+
provider.addSpanProcessor(new SimpleSpanProcessor(new ZipkinExporter({
8+
// testing interceptor
9+
// getExportRequestHeaders: ()=> {
10+
// return {
11+
// foo: 'bar',
12+
// }
13+
// }
14+
})));
815

916
provider.register();
1017

packages/opentelemetry-exporter-zipkin/README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ const options = {
3030
'my-header': 'header-value',
3131
},
3232
url: 'your-zipkin-url',
33-
serviceName: 'your-application-name'
33+
serviceName: 'your-application-name',
34+
// optional interceptor
35+
getExportRequestHeaders: () => {
36+
return {
37+
'my-header': 'header-value',
38+
}
39+
}
3440
}
3541
const exporter = new ZipkinExporter(options);
3642
```
@@ -46,6 +52,11 @@ You can use built-in `SimpleSpanProcessor` or `BatchSpanProcessor` or write your
4652
- [SimpleSpanProcessor](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#simple-processor): The implementation of `SpanProcessor` that passes ended span directly to the configured `SpanExporter`.
4753
- [BatchSpanProcessor](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#batching-processor): The implementation of the `SpanProcessor` that batches ended spans and pushes them to the configured `SpanExporter`. It is recommended to use this `SpanProcessor` for better performance and optimization.
4854

55+
### Options
56+
57+
- **getExportRequestHeaders** - optional interceptor that allows adding new headers everytime time the exporter is going to send spans.
58+
This is optional and can be used if headers are changing over time. This is a sync callback.
59+
4960
## Viewing your traces
5061

5162
Please visit the Zipkin UI endpoint <http://localhost:9411>

packages/opentelemetry-exporter-zipkin/src/platform/browser/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import * as zipkinTypes from '../../types';
2424

2525
/**
2626
* Prepares send function that will send spans to the remote Zipkin service.
27+
* @param urlStr - url to send spans
28+
* @param headers - headers
29+
* send
2730
*/
2831
export function prepareSend(urlStr: string, headers?: Record<string, string>) {
2932
let xhrHeaders: Record<string, string>;

packages/opentelemetry-exporter-zipkin/src/platform/node/util.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import * as zipkinTypes from '../../types';
2323

2424
/**
2525
* Prepares send function that will send spans to the remote Zipkin service.
26+
* @param urlStr - url to send spans
27+
* @param headers - headers
28+
* send
2629
*/
2730
export function prepareSend(urlStr: string, headers?: Record<string, string>) {
2831
const urlOpts = url.parse(urlStr);

packages/opentelemetry-exporter-zipkin/src/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ import { ExportResult } from '@opentelemetry/core';
2020
* Exporter config
2121
*/
2222
export interface ExporterConfig {
23-
headers?: { [key: string]: string };
23+
headers?: Record<string, string>;
2424
serviceName?: string;
2525
url?: string;
2626
// Optional mapping overrides for OpenTelemetry status code and description.
2727
statusCodeTagName?: string;
2828
statusDescriptionTagName?: string;
29+
getExportRequestHeaders?: () => Record<string, string> | undefined;
2930
}
3031

3132
/**
@@ -184,3 +185,5 @@ export type SendFunction = (
184185
zipkinSpans: Span[],
185186
done: (result: ExportResult) => void
186187
) => void;
188+
189+
export type GetHeaders = () => Record<string, string> | undefined;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import { GetHeaders } from './types';
17+
18+
export function prepareGetHeaders(
19+
getExportRequestHeaders: GetHeaders
20+
): () => Record<string, string> | undefined {
21+
return function () {
22+
return getExportRequestHeaders();
23+
};
24+
}

packages/opentelemetry-exporter-zipkin/src/zipkin.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
statusDescriptionTagName,
2626
} from './transform';
2727
import { SERVICE_RESOURCE } from '@opentelemetry/resources';
28+
import { prepareGetHeaders } from './utils';
2829

2930
/**
3031
* Zipkin Exporter
@@ -34,19 +35,27 @@ export class ZipkinExporter implements SpanExporter {
3435
private readonly DEFAULT_SERVICE_NAME = 'OpenTelemetry Service';
3536
private readonly _statusCodeTagName: string;
3637
private readonly _statusDescriptionTagName: string;
38+
private _urlStr: string;
3739
private _send: zipkinTypes.SendFunction;
40+
private _getHeaders: zipkinTypes.GetHeaders | undefined;
3841
private _serviceName?: string;
3942
private _isShutdown: boolean;
4043
private _sendingPromises: Promise<unknown>[] = [];
4144

4245
constructor(config: zipkinTypes.ExporterConfig = {}) {
43-
const urlStr = config.url || ZipkinExporter.DEFAULT_URL;
44-
this._send = prepareSend(urlStr, config.headers);
46+
this._urlStr = config.url || ZipkinExporter.DEFAULT_URL;
47+
this._send = prepareSend(this._urlStr, config.headers);
4548
this._serviceName = config.serviceName;
4649
this._statusCodeTagName = config.statusCodeTagName || statusCodeTagName;
4750
this._statusDescriptionTagName =
4851
config.statusDescriptionTagName || statusDescriptionTagName;
4952
this._isShutdown = false;
53+
if (typeof config.getExportRequestHeaders === 'function') {
54+
this._getHeaders = prepareGetHeaders(config.getExportRequestHeaders);
55+
} else {
56+
// noop
57+
this._beforeSend = function () {};
58+
}
5059
}
5160

5261
/**
@@ -96,6 +105,18 @@ export class ZipkinExporter implements SpanExporter {
96105
});
97106
}
98107

108+
/**
109+
* if user defines getExportRequestHeaders in config then this will be called
110+
* everytime before send, otherwise it will be replaced with noop in
111+
* constructor
112+
* @default noop
113+
*/
114+
private _beforeSend() {
115+
if (this._getHeaders) {
116+
this._send = prepareSend(this._urlStr, this._getHeaders());
117+
}
118+
}
119+
99120
/**
100121
* Transform spans and sends to Zipkin service.
101122
*/
@@ -116,6 +137,7 @@ export class ZipkinExporter implements SpanExporter {
116137
this._statusDescriptionTagName
117138
)
118139
);
140+
this._beforeSend();
119141
return this._send(zipkinSpans, (result: ExportResult) => {
120142
if (done) {
121143
return done(result);

packages/opentelemetry-exporter-zipkin/test/browser/zipkin.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,40 @@ describe('Zipkin Exporter - web', () => {
9797
});
9898
});
9999
});
100+
describe('when getExportRequestHeaders is defined', () => {
101+
let server: any;
102+
beforeEach(() => {
103+
server = sinon.fakeServer.create();
104+
spySend.restore();
105+
});
106+
107+
afterEach(() => {
108+
server.restore();
109+
});
110+
111+
it('should add headers from callback', done => {
112+
zipkinExporter = new ZipkinExporter({
113+
getExportRequestHeaders: () => {
114+
return {
115+
foo1: 'bar1',
116+
foo2: 'bar2',
117+
};
118+
},
119+
});
120+
zipkinExporter.export(spans, () => {});
121+
122+
setTimeout(() => {
123+
const [{ requestHeaders }] = server.requests;
124+
125+
ensureHeadersContain(requestHeaders, {
126+
foo1: 'bar1',
127+
foo2: 'bar2',
128+
});
129+
130+
done();
131+
});
132+
});
133+
});
100134

101135
describe('export with custom headers', () => {
102136
let server: any;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import * as assert from 'assert';
18+
import { ZipkinExporter } from '../../src';
19+
import * as sinon from 'sinon';
20+
import { mockedReadableSpan } from '../helper';
21+
22+
describe('zipkin - header interceptor', () => {
23+
describe('getExportRequestHeaders', () => {
24+
describe('when callback is defined', () => {
25+
it('should call callback before sending', () => {
26+
const getExportRequestHeaders = sinon.spy();
27+
const span = Object.assign({}, mockedReadableSpan);
28+
const exporter = new ZipkinExporter({
29+
getExportRequestHeaders,
30+
});
31+
const oldFunction = exporter['_send'];
32+
exporter.export([span], () => {});
33+
34+
assert.strictEqual(getExportRequestHeaders.callCount, 1);
35+
assert.notStrictEqual(exporter['_getHeaders'], undefined);
36+
assert.notStrictEqual(oldFunction, exporter['_send']);
37+
});
38+
});
39+
describe('when callback is NOT defined', () => {
40+
it('should call callback before sending', () => {
41+
const span = Object.assign({}, mockedReadableSpan);
42+
const exporter = new ZipkinExporter();
43+
const oldFunction = exporter['_send'];
44+
assert.strictEqual(exporter['_getHeaders'], undefined);
45+
exporter.export([span], () => {});
46+
assert.strictEqual(oldFunction, exporter['_send']);
47+
});
48+
});
49+
});
50+
});

0 commit comments

Comments
 (0)