Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add instrumentation library and update collector exporter #1171

Merged
merged 20 commits into from
Jun 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
mwear marked this conversation as resolved.
Show resolved Hide resolved
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