Skip to content

Commit b58965c

Browse files
Peter Martonmayurkale22
authored andcommitted
Zipkin Exporter (open-telemetry#192)
* feat(zipkin-exporter): implement * fix(zipkin): use time fns * refactor(exporter-zipkin): linter fix
1 parent 7fc72dc commit b58965c

File tree

8 files changed

+1069
-0
lines changed

8 files changed

+1069
-0
lines changed

packages/opentelemetry-exporter-zipkin/package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"tdd": "yarn test -- --watch-extensions ts --watch",
1010
"clean": "rimraf build/*",
1111
"check": "gts check",
12+
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
1213
"compile": "tsc -p .",
1314
"fix": "gts fix"
1415
},
@@ -35,10 +36,12 @@
3536
},
3637
"devDependencies": {
3738
"@types/mocha": "^5.2.7",
39+
"@types/nock": "^10.0.3",
3840
"@types/node": "^12.6.9",
3941
"codecov": "^3.5.0",
4042
"gts": "^1.1.0",
4143
"mocha": "^6.2.0",
44+
"nock": "^10.0.6",
4245
"nyc": "^14.1.1",
4346
"tslint-microsoft-contrib": "^6.2.0",
4447
"tslint-consistent-codestyle":"^1.15.1",
@@ -47,5 +50,8 @@
4750
"typescript": "^3.5.3"
4851
},
4952
"dependencies": {
53+
"@opentelemetry/core": "^0.0.1",
54+
"@opentelemetry/basic-tracer": "^0.0.1",
55+
"@opentelemetry/types": "^0.0.1"
5056
}
5157
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16+
17+
export * from './zipkin';
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*!
2+
* Copyright 2019, 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 types from '@opentelemetry/types';
18+
import { ReadableSpan } from '@opentelemetry/basic-tracer';
19+
import { hrTimeToMilliseconds } from '@opentelemetry/core';
20+
import * as zipkinTypes from './types';
21+
22+
const ZIPKIN_SPAN_KIND_MAPPING = {
23+
[types.SpanKind.CLIENT]: zipkinTypes.SpanKind.CLIENT,
24+
[types.SpanKind.SERVER]: zipkinTypes.SpanKind.SERVER,
25+
[types.SpanKind.CONSUMER]: zipkinTypes.SpanKind.CONSUMER,
26+
[types.SpanKind.PRODUCER]: zipkinTypes.SpanKind.PRODUCER,
27+
// When absent, the span is local.
28+
[types.SpanKind.INTERNAL]: undefined,
29+
};
30+
31+
export const statusCodeTagName = 'ot.status_code';
32+
export const statusDescriptionTagName = 'ot.status_description';
33+
34+
/**
35+
* Translate OpenTelemetry ReadableSpan to ZipkinSpan format
36+
* @param span Span to be translated
37+
*/
38+
export function toZipkinSpan(
39+
span: ReadableSpan,
40+
serviceName: string,
41+
statusCodeTagName: string,
42+
statusDescriptionTagName: string
43+
): zipkinTypes.Span {
44+
const zipkinSpan: zipkinTypes.Span = {
45+
traceId: span.spanContext.traceId,
46+
parentId: span.parentSpanId,
47+
name: span.name,
48+
id: span.spanContext.spanId,
49+
kind: ZIPKIN_SPAN_KIND_MAPPING[span.kind],
50+
timestamp: hrTimeToMilliseconds(span.startTime),
51+
duration: hrTimeToMilliseconds(span.duration),
52+
localEndpoint: { serviceName },
53+
tags: _toZipkinTags(
54+
span.attributes,
55+
span.status,
56+
statusCodeTagName,
57+
statusDescriptionTagName
58+
),
59+
annotations: span.events.length
60+
? _toZipkinAnnotations(span.events)
61+
: undefined,
62+
};
63+
64+
return zipkinSpan;
65+
}
66+
67+
/** Converts OpenTelemetry Attributes and Status to Zipkin Tags format. */
68+
export function _toZipkinTags(
69+
attributes: types.Attributes,
70+
status: types.Status,
71+
statusCodeTagName: string,
72+
statusDescriptionTagName: string
73+
): zipkinTypes.Tags {
74+
const tags: { [key: string]: string } = {};
75+
for (const key of Object.keys(attributes)) {
76+
tags[key] = String(attributes[key]);
77+
}
78+
tags[statusCodeTagName] = String(types.CanonicalCode[status.code]);
79+
if (status.message) {
80+
tags[statusDescriptionTagName] = status.message;
81+
}
82+
return tags;
83+
}
84+
85+
/**
86+
* Converts OpenTelemetry Events to Zipkin Annotations format.
87+
*/
88+
export function _toZipkinAnnotations(
89+
events: types.TimedEvent[]
90+
): zipkinTypes.Annotation[] {
91+
return events.map(event => ({
92+
timestamp: hrTimeToMilliseconds(event.time),
93+
value: event.name,
94+
}));
95+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
/*!
2+
* Copyright 2019, 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 types from '@opentelemetry/types';
18+
19+
/**
20+
* Exporter config
21+
*/
22+
export interface ExporterConfig {
23+
logger?: types.Logger;
24+
serviceName: string;
25+
url?: string;
26+
// Initiates a request with spans in memory to the backend.
27+
forceFlush?: boolean;
28+
// Optional mapping overrides for OpenTelemetry status code and description.
29+
statusCodeTagName?: string;
30+
statusDescriptionTagName?: string;
31+
}
32+
33+
/**
34+
* Zipkin Span
35+
* @see https://github.com/openzipkin/zipkin-api/blob/master/zipkin2-api.yaml
36+
*/
37+
export interface Span {
38+
/**
39+
* Trace identifier, set on all spans within it.
40+
*/
41+
traceId: string;
42+
/**
43+
* The logical operation this span represents in lowercase (e.g. rpc method).
44+
* Leave absent if unknown.
45+
*/
46+
name: string;
47+
/**
48+
* The parent span ID or absent if this the root span in a trace.
49+
*/
50+
parentId?: string;
51+
/**
52+
* Unique 64bit identifier for this operation within the trace.
53+
*/
54+
id: string;
55+
/**
56+
* When present, kind clarifies timestamp, duration and remoteEndpoint.
57+
* When absent, the span is local or incomplete.
58+
*/
59+
kind?: SpanKind;
60+
/**
61+
* Epoch microseconds of the start of this span, possibly absent if
62+
* incomplete.
63+
*/
64+
timestamp: number;
65+
/**
66+
* Duration in microseconds of the critical path, if known.
67+
*/
68+
duration: number;
69+
/**
70+
* True is a request to store this span even if it overrides sampling policy.
71+
* This is true when the `X-B3-Flags` header has a value of 1.
72+
*/
73+
debug?: boolean;
74+
/**
75+
* True if we are contributing to a span started by another tracer (ex on a
76+
* different host).
77+
*/
78+
shared?: boolean;
79+
/**
80+
* The host that recorded this span, primarily for query by service name.
81+
*/
82+
localEndpoint: Endpoint;
83+
/**
84+
* Associates events that explain latency with the time they happened.
85+
*/
86+
annotations?: Annotation[];
87+
/**
88+
* Tags give your span context for search, viewing and analysis.
89+
*/
90+
tags: Tags;
91+
/**
92+
* TODO: `remoteEndpoint`, do we need to support it?
93+
* When an RPC (or messaging) span, indicates the other side of the
94+
* connection.
95+
*/
96+
}
97+
98+
/**
99+
* Associates an event that explains latency with a timestamp.
100+
* Unlike log statements, annotations are often codes. Ex. "ws" for WireSend
101+
* Zipkin v1 core annotations such as "cs" and "sr" have been replaced with
102+
* Span.Kind, which interprets timestamp and duration.
103+
*/
104+
export interface Annotation {
105+
/**
106+
* Epoch microseconds of this event.
107+
* For example, 1502787600000000 corresponds to 2017-08-15 09:00 UTC
108+
*/
109+
timestamp: number;
110+
/**
111+
* Usually a short tag indicating an event, like "error"
112+
* While possible to add larger data, such as garbage collection details, low
113+
* cardinality event names both keep the size of spans down and also are easy
114+
* to search against.
115+
*/
116+
value: string;
117+
}
118+
119+
/**
120+
* The network context of a node in the service graph.
121+
*/
122+
export interface Endpoint {
123+
/**
124+
* Lower-case label of this node in the service graph, such as "favstar".
125+
* Leave absent if unknown.
126+
* This is a primary label for trace lookup and aggregation, so it should be
127+
* intuitive and consistent. Many use a name from service discovery.
128+
*/
129+
serviceName?: string;
130+
/**
131+
* The text representation of the primary IPv4 address associated with this
132+
* connection. Ex. 192.168.99.100 Absent if unknown.
133+
*/
134+
ipv4?: string;
135+
/**
136+
* The text representation of the primary IPv6 address associated with a
137+
* connection. Ex. 2001:db8::c001 Absent if unknown.
138+
* Prefer using the ipv4 field for mapped addresses.
139+
*/
140+
port?: number;
141+
}
142+
143+
/**
144+
* Adds context to a span, for search, viewing and analysis.
145+
* For example, a key "your_app.version" would let you lookup traces by version.
146+
* A tag "sql.query" isn't searchable, but it can help in debugging when viewing
147+
* a trace.
148+
*/
149+
export interface Tags {
150+
[tagKey: string]: unknown;
151+
}
152+
153+
/**
154+
* When present, kind clarifies timestamp, duration and remoteEndpoint. When
155+
* absent, the span is local or incomplete. Unlike client and server, there
156+
* is no direct critical path latency relationship between producer and
157+
* consumer spans.
158+
* `CLIENT`
159+
* timestamp is the moment a request was sent to the server.
160+
* duration is the delay until a response or an error was received.
161+
* remoteEndpoint is the server.
162+
* `SERVER`
163+
* timestamp is the moment a client request was received.
164+
* duration is the delay until a response was sent or an error.
165+
* remoteEndpoint is the client.
166+
* `PRODUCER`
167+
* timestamp is the moment a message was sent to a destination.
168+
* duration is the delay sending the message, such as batching.
169+
* remoteEndpoint is the broker.
170+
* `CONSUMER`
171+
* timestamp is the moment a message was received from an origin.
172+
* duration is the delay consuming the message, such as from backlog.
173+
* remoteEndpoint - Represents the broker. Leave serviceName absent if unknown.
174+
*/
175+
export enum SpanKind {
176+
CLIENT = 'CLIENT',
177+
SERVER = 'SERVER',
178+
CONSUMER = 'CONSUMER',
179+
PRODUCER = 'PRODUCER',
180+
}

0 commit comments

Comments
 (0)