Skip to content

Commit 6c113d7

Browse files
committed
feat(opentelemetry-js): infer zipkin service name from resource
1 parent f08b2a0 commit 6c113d7

File tree

2 files changed

+168
-1
lines changed

2 files changed

+168
-1
lines changed

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

+13-1
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,17 @@ import {
2727
statusDescriptionTagName,
2828
} from './transform';
2929
import { OT_REQUEST_HEADER } from './utils';
30+
import { SERVICE_RESOURCE } from '@opentelemetry/resources';
3031
/**
3132
* Zipkin Exporter
3233
*/
3334
export class ZipkinExporter implements SpanExporter {
3435
static readonly DEFAULT_URL = 'http://localhost:9411/api/v2/spans';
3536
private readonly _logger: api.Logger;
36-
private readonly _serviceName: string;
3737
private readonly _statusCodeTagName: string;
3838
private readonly _statusDescriptionTagName: string;
3939
private readonly _reqOpts: http.RequestOptions;
40+
private _serviceName: string;
4041
private _isShutdown: boolean;
4142

4243
constructor(config: zipkinTypes.ExporterConfig) {
@@ -68,6 +69,17 @@ export class ZipkinExporter implements SpanExporter {
6869
spans: ReadableSpan[],
6970
resultCallback: (result: ExportResult) => void
7071
) {
72+
if (typeof this._serviceName !== 'string') {
73+
if (
74+
typeof spans[0].resource.labels[SERVICE_RESOURCE.NAME] !== 'undefined'
75+
) {
76+
this._serviceName = spans[0].resource.labels[
77+
SERVICE_RESOURCE.NAME
78+
].toString();
79+
} else {
80+
this._serviceName = 'Unnamed Service';
81+
}
82+
}
7183
this._logger.debug('Zipkin exporter export');
7284
if (this._isShutdown) {
7385
setTimeout(() => resultCallback(ExportResult.FAILED_NOT_RETRYABLE));

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

+155
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { ZipkinExporter } from '../src';
2828
import * as zipkinTypes from '../src/types';
2929
import { OT_REQUEST_HEADER } from '../src/utils';
3030
import { TraceFlags } from '@opentelemetry/api';
31+
import { SERVICE_RESOURCE } from '@opentelemetry/resources';
3132

3233
const MICROS_PER_SECS = 1e6;
3334

@@ -331,6 +332,160 @@ describe('ZipkinExporter', () => {
331332
done();
332333
});
333334
});
335+
336+
it('should set serviceName to "Unnamed service" by default', () => {
337+
const scope = nock('http://localhost:9411')
338+
.post('/api/v2/spans')
339+
.replyWithError(new Error('My Socket Error'));
340+
341+
const parentSpanId = '5c1c63257de34c67';
342+
const startTime = 1566156729709;
343+
const duration = 2000;
344+
345+
const span1: ReadableSpan = {
346+
name: 'my-span',
347+
kind: api.SpanKind.INTERNAL,
348+
parentSpanId,
349+
spanContext: {
350+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
351+
spanId: '6e0c63257de34c92',
352+
traceFlags: TraceFlags.NONE,
353+
},
354+
startTime: [startTime, 0],
355+
endTime: [startTime + duration, 0],
356+
ended: true,
357+
duration: [duration, 0],
358+
status: {
359+
code: api.CanonicalCode.OK,
360+
},
361+
attributes: {
362+
key1: 'value1',
363+
key2: 'value2',
364+
},
365+
links: [],
366+
events: [
367+
{
368+
name: 'my-event',
369+
time: [startTime + 10, 0],
370+
attributes: { key3: 'value3' },
371+
},
372+
],
373+
resource: Resource.empty(),
374+
};
375+
const span2: ReadableSpan = {
376+
name: 'my-span',
377+
kind: api.SpanKind.SERVER,
378+
spanContext: {
379+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
380+
spanId: '6e0c63257de34c92',
381+
traceFlags: TraceFlags.NONE,
382+
},
383+
startTime: [startTime, 0],
384+
endTime: [startTime + duration, 0],
385+
ended: true,
386+
duration: [duration, 0],
387+
status: {
388+
code: api.CanonicalCode.OK,
389+
},
390+
attributes: {},
391+
links: [],
392+
events: [],
393+
resource: Resource.empty(),
394+
};
395+
396+
const exporter = new ZipkinExporter({
397+
serviceName: 'my-service',
398+
});
399+
400+
delete exporter['_serviceName'];
401+
402+
exporter.export([span1, span2], (result: ExportResult) => {
403+
scope.done();
404+
assert.equal(exporter['_serviceName'], 'Unnamed Service');
405+
});
406+
});
407+
408+
it('should set serviceName if resource has one', () => {
409+
const resource_service_name = 'resource_service_name';
410+
411+
const scope = nock('http://localhost:9411')
412+
.post('/api/v2/spans')
413+
.replyWithError(new Error('My Socket Error'));
414+
415+
const parentSpanId = '5c1c63257de34c67';
416+
const startTime = 1566156729709;
417+
const duration = 2000;
418+
419+
const span1: ReadableSpan = {
420+
name: 'my-span',
421+
kind: api.SpanKind.INTERNAL,
422+
parentSpanId,
423+
spanContext: {
424+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
425+
spanId: '6e0c63257de34c92',
426+
traceFlags: TraceFlags.NONE,
427+
},
428+
startTime: [startTime, 0],
429+
endTime: [startTime + duration, 0],
430+
ended: true,
431+
duration: [duration, 0],
432+
status: {
433+
code: api.CanonicalCode.OK,
434+
},
435+
attributes: {
436+
key1: 'value1',
437+
key2: 'value2',
438+
},
439+
links: [],
440+
events: [
441+
{
442+
name: 'my-event',
443+
time: [startTime + 10, 0],
444+
attributes: { key3: 'value3' },
445+
},
446+
],
447+
resource: new Resource({
448+
[SERVICE_RESOURCE.NAME]: resource_service_name,
449+
}),
450+
};
451+
const span2: ReadableSpan = {
452+
name: 'my-span',
453+
kind: api.SpanKind.SERVER,
454+
spanContext: {
455+
traceId: 'd4cda95b652f4a1592b449d5929fda1b',
456+
spanId: '6e0c63257de34c92',
457+
traceFlags: TraceFlags.NONE,
458+
},
459+
startTime: [startTime, 0],
460+
endTime: [startTime + duration, 0],
461+
ended: true,
462+
duration: [duration, 0],
463+
status: {
464+
code: api.CanonicalCode.OK,
465+
},
466+
attributes: {},
467+
links: [],
468+
events: [],
469+
resource: Resource.empty(),
470+
};
471+
472+
const exporter = new ZipkinExporter({
473+
serviceName: 'my-service',
474+
});
475+
476+
delete exporter['_serviceName'];
477+
478+
exporter.export([span1, span2], (result: ExportResult) => {
479+
scope.done();
480+
assert.equal(exporter['_serviceName'], resource_service_name);
481+
482+
// checking if service name remains consistent in further exports
483+
exporter.export([span2], (result: ExportResult) => {
484+
scope.done();
485+
assert.equal(exporter['_serviceName'], resource_service_name);
486+
});
487+
});
488+
});
334489
});
335490

336491
describe('shutdown', () => {

0 commit comments

Comments
 (0)