Skip to content

Commit

Permalink
feat: add instrumentation library and update collector exporter (open…
Browse files Browse the repository at this point in the history
…-telemetry#1171)

Co-authored-by: Daniel Dyla <dyladan@users.noreply.github.com>
  • Loading branch information
mwear and dyladan committed Jun 23, 2020
1 parent 33a1297 commit badbb9d
Show file tree
Hide file tree
Showing 19 changed files with 410 additions and 44 deletions.
10 changes: 10 additions & 0 deletions packages/opentelemetry-core/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,13 @@ export interface ShimWrapped {
__unwrap: Function;
__original: Function;
}

/**
* An instrumentation library consists of the name and version used to
* obtain a tracer or meter from a provider. This metadata is made available
* on ReadableSpan and MetricRecord for use by the export pipeline.
*/
export interface InstrumentationLibrary {
readonly name: string;
readonly version: string;
}
77 changes: 57 additions & 20 deletions packages/opentelemetry-exporter-collector/src/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
} from './CollectorExporterBase';
import { COLLECTOR_SPAN_KIND_MAPPING, opentelemetryProto } from './types';
import ValueType = opentelemetryProto.common.v1.ValueType;
import { InstrumentationLibrary } from '@opentelemetry/core';

/**
* Converts attributes
Expand Down Expand Up @@ -202,11 +203,10 @@ export function toCollectorExportTraceServiceRequest<
collectorExporterBase: CollectorExporterBase<T>,
name = ''
): opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest {
const spansToBeSent: opentelemetryProto.trace.v1.Span[] = spans.map(span =>
toCollectorSpan(span)
);
const resource: Resource =
spans.length > 0 ? spans[0].resource : Resource.empty();
const groupedSpans: Map<
Resource,
Map<core.InstrumentationLibrary, ReadableSpan[]>
> = groupSpansByResourceAndLibrary(spans);

const additionalAttributes = Object.assign(
{},
Expand All @@ -215,23 +215,60 @@ export function toCollectorExportTraceServiceRequest<
'service.name': collectorExporterBase.serviceName,
}
);
const protoResource: opentelemetryProto.resource.v1.Resource = toCollectorResource(
resource,
additionalAttributes
);
const instrumentationLibrarySpans: opentelemetryProto.trace.v1.InstrumentationLibrarySpans = {
spans: spansToBeSent,
instrumentationLibrary: {
name: name || `${core.SDK_INFO.NAME} - ${core.SDK_INFO.LANGUAGE}`,
version: core.SDK_INFO.VERSION,
},
};
const resourceSpan: opentelemetryProto.trace.v1.ResourceSpans = {
resource: protoResource,
instrumentationLibrarySpans: [instrumentationLibrarySpans],

return {
resourceSpans: toCollectorResourceSpans(groupedSpans, additionalAttributes),
};
}

/**
* Takes an array of spans and groups them by resource and instrumentation
* library
* @param spans spans
*/
export function groupSpansByResourceAndLibrary(
spans: ReadableSpan[]
): Map<Resource, Map<core.InstrumentationLibrary, ReadableSpan[]>> {
return spans.reduce((spanMap, span) => {
//group by resource
let resourceSpans = spanMap.get(span.resource);
if (!resourceSpans) {
resourceSpans = new Map<core.InstrumentationLibrary, ReadableSpan[]>();
spanMap.set(span.resource, resourceSpans);
}
//group by instrumentation library
let libSpans = resourceSpans.get(span.instrumentationLibrary);
if (!libSpans) {
libSpans = new Array<ReadableSpan>();
resourceSpans.set(span.instrumentationLibrary, libSpans);
}
libSpans.push(span);
return spanMap;
}, new Map<Resource, Map<core.InstrumentationLibrary, ReadableSpan[]>>());
}

function toCollectorInstrumentationLibrarySpans(
instrumentationLibrary: InstrumentationLibrary,
spans: ReadableSpan[]
): opentelemetryProto.trace.v1.InstrumentationLibrarySpans {
return {
resourceSpans: [resourceSpan],
spans: spans.map(toCollectorSpan),
instrumentationLibrary,
};
}

function toCollectorResourceSpans(
groupedSpans: Map<Resource, Map<core.InstrumentationLibrary, ReadableSpan[]>>,
baseAttributes: Attributes
): opentelemetryProto.trace.v1.ResourceSpans[] {
return Array.from(groupedSpans, ([resource, libSpans]) => {
return {
resource: toCollectorResource(resource, baseAttributes),
instrumentationLibrarySpans: Array.from(
libSpans,
([instrumentationLibrary, spans]) =>
toCollectorInstrumentationLibrarySpans(instrumentationLibrary, spans)
),
};
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@
import { Attributes, TimedEvent } from '@opentelemetry/api';
import * as assert from 'assert';
import * as transform from '../../src/transform';
import { ensureSpanIsCorrect, mockedReadableSpan } from '../helper';
import {
ensureSpanIsCorrect,
mockedReadableSpan,
mockedResources,
mockedInstrumentationLibraries,
multiResourceTrace,
multiInstrumentationLibraryTrace,
} from '../helper';
import { Resource } from '@opentelemetry/resources';

describe('transform', () => {
Expand Down Expand Up @@ -119,4 +126,45 @@ describe('transform', () => {
});
});
});

describe('groupSpansByResourceAndLibrary', () => {
it('should group by resource', () => {
const [resource1, resource2] = mockedResources;
const [instrumentationLibrary] = mockedInstrumentationLibraries;
const [span1, span2, span3] = multiResourceTrace;

const expected = new Map([
[resource1, new Map([[instrumentationLibrary, [span1]]])],
[resource2, new Map([[instrumentationLibrary, [span2, span3]]])],
]);

const result = transform.groupSpansByResourceAndLibrary(
multiResourceTrace
);

assert.deepStrictEqual(result, expected);
});

it('should group by instrumentation library', () => {
const [resource] = mockedResources;
const [lib1, lib2] = mockedInstrumentationLibraries;
const [span1, span2, span3] = multiInstrumentationLibraryTrace;

const expected = new Map([
[
resource,
new Map([
[lib1, [span1, span2]],
[lib2, [span3]],
]),
],
]);

const result = transform.groupSpansByResourceAndLibrary(
multiInstrumentationLibraryTrace
);

assert.deepStrictEqual(result, expected);
});
});
});
111 changes: 111 additions & 0 deletions packages/opentelemetry-exporter-collector/test/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Resource } from '@opentelemetry/resources';
import * as assert from 'assert';
import { opentelemetryProto } from '../src/types';
import * as collectorTypes from '../src/types';
import { InstrumentationLibrary } from '@opentelemetry/core';
import * as grpc from 'grpc';

if (typeof Buffer === 'undefined') {
Expand Down Expand Up @@ -106,8 +107,118 @@ export const mockedReadableSpan: ReadableSpan = {
version: 1,
cost: 112.12,
}),
instrumentationLibrary: { name: 'default', version: '0.0.1' },
};

export const mockedResources: Resource[] = [
new Resource({ name: 'resource 1' }),
new Resource({ name: 'resource 2' }),
];

export const mockedInstrumentationLibraries: InstrumentationLibrary[] = [
{
name: 'lib1',
version: '0.0.1',
},
{
name: 'lib2',
version: '0.0.2',
},
];

export const basicTrace: ReadableSpan[] = [
{
name: 'span1',
kind: 0,
spanContext: {
traceId: '1f1008dc8e270e85c40a0d7c3939b278',
spanId: '5e107261f64fa53e',
traceFlags: TraceFlags.SAMPLED,
},
parentSpanId: '78a8915098864388',
startTime: [1574120165, 429803070],
endTime: [1574120165, 438688070],
ended: true,
status: { code: 0 },
attributes: {},
links: [],
events: [],
duration: [0, 8885000],
resource: mockedResources[0],
instrumentationLibrary: mockedInstrumentationLibraries[0],
},
{
name: 'span2',
kind: 0,
spanContext: {
traceId: '1f1008dc8e270e85c40a0d7c3939b278',
spanId: 'f64fa53e5e107261',
traceFlags: TraceFlags.SAMPLED,
},
parentSpanId: '78a8915098864388',
startTime: [1575120165, 439803070],
endTime: [1575120165, 448688070],
ended: true,
status: { code: 0 },
attributes: {},
links: [],
events: [],
duration: [0, 8775000],
resource: mockedResources[0],
instrumentationLibrary: mockedInstrumentationLibraries[0],
},
{
name: 'span3',
kind: 0,
spanContext: {
traceId: '1f1008dc8e270e85c40a0d7c3939b278',
spanId: '07261f64fa53e5e1',
traceFlags: TraceFlags.SAMPLED,
},
parentSpanId: 'a891578098864388',
startTime: [1575120165, 439803070],
endTime: [1575120165, 448688070],
ended: true,
status: { code: 0 },
attributes: {},
links: [],
events: [],
duration: [0, 8775000],
resource: mockedResources[0],
instrumentationLibrary: mockedInstrumentationLibraries[0],
},
];

export const multiResourceTrace: ReadableSpan[] = [
{
...basicTrace[0],
resource: mockedResources[0],
},
{
...basicTrace[1],
resource: mockedResources[1],
},
{
...basicTrace[2],
resource: mockedResources[1],
},
];

export const multiInstrumentationLibraryTrace: ReadableSpan[] = [
{
...basicTrace[0],
instrumentationLibrary: mockedInstrumentationLibraries[0],
},
{
...basicTrace[1],
instrumentationLibrary: mockedInstrumentationLibraries[0],
},
{
...basicTrace[2],
instrumentationLibrary: mockedInstrumentationLibraries[1],
},
];

export function ensureExportedEventsAreCorrect(
events: opentelemetryProto.trace.v1.Span.Event[]
) {
Expand Down
8 changes: 8 additions & 0 deletions packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ describe('JaegerExporter', () => {
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
instrumentationLibrary: {
name: 'default',
version: '0.0.1',
},
};

exporter.export([readableSpan], (result: ExportResult) => {
Expand Down Expand Up @@ -194,6 +198,10 @@ describe('JaegerExporter', () => {
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
instrumentationLibrary: {
name: 'default',
version: '0.0.1',
},
};
exporter.export([readableSpan], () => {});
});
Expand Down
16 changes: 16 additions & 0 deletions packages/opentelemetry-exporter-jaeger/test/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ describe('transform', () => {
version: 1,
cost: 112.12,
}),
instrumentationLibrary: {
name: 'default',
version: '0.0.1',
},
};

const thriftSpan = spanToThrift(readableSpan);
Expand Down Expand Up @@ -169,6 +173,10 @@ describe('transform', () => {
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
instrumentationLibrary: {
name: 'default',
version: '0.0.1',
},
};

const thriftSpan = spanToThrift(readableSpan);
Expand Down Expand Up @@ -234,6 +242,10 @@ describe('transform', () => {
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
instrumentationLibrary: {
name: 'default',
version: '0.0.1',
},
};

const thriftSpan = spanToThrift(readableSpan);
Expand Down Expand Up @@ -273,6 +285,10 @@ describe('transform', () => {
events: [],
duration: [32, 800000000],
resource: Resource.empty(),
instrumentationLibrary: {
name: 'default',
version: '0.0.1',
},
};

const thriftSpan = spanToThrift(readableSpan);
Expand Down
Loading

0 comments on commit badbb9d

Please sign in to comment.