Skip to content
This repository was archived by the owner on Oct 3, 2023. It is now read-only.

Commit 5882009

Browse files
justindsmithkjin
authored andcommitted
chore: add type definitions for exporter-jaeger (#93)
The JaegerTraceExporterOptions accepts `tags` as a Tag array, but was processing those tags for the process information as if they were an object / Record instead of a Tag array. This was leading to the process key-value inside Jaeger to be the array index as key and the value as the key-value object. We now use the proper key-value information from the input to place into the process tags. There were two approaches we could have taken here: 1. To leave the input as a Tag array and process the input properly in the code or 2. To change the input to a key-value record / object (Record<string, TagValue), which would be handled properly by the existing code. We have chosen approach #1 because a Jaeger process tag CAN support multiple tags with the same key name, which would not be supported in approach #2. There is a chance that (because we were not previously exporting typescript types) users were passing in a Record format instead of Array, and thus this might be seen as a breaking change. A test has been added to validate the process information to ensure proper format. Also included are sticter typing for all thrift types, removing all `any` references and replacing with valid types.
1 parent c7226d6 commit 5882009

File tree

4 files changed

+127
-26
lines changed

4 files changed

+127
-26
lines changed

packages/opencensus-exporter-jaeger/src/jaeger-driver/index.ts

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,77 @@ export const Utils = requireJaegerClientModule('util');
3030
// tslint:disable-next-line:variable-name
3131
export const ThriftUtils = requireJaegerClientModule('thrift');
3232

33+
export type TagValue = string|number|boolean;
34+
3335
export type Tag = {
3436
key: string,
35-
// tslint:disable-next-line:no-any
36-
value: any
37+
value: TagValue
3738
};
3839

39-
export type Process = {
40-
serviceName: string,
41-
tags: Tag[]
40+
export type Log = {
41+
timestamp: number,
42+
fields: Tag[]
4243
};
4344

4445
export type SenderCallback = (numSpans: number, err?: string) => void;
4546

47+
export type ThriftProcess = {
48+
serviceName: string,
49+
tags: ThriftTag[]
50+
};
51+
52+
export type ThriftTag = {
53+
key: string,
54+
vType: string,
55+
vStr: string,
56+
vDouble: number,
57+
vBool: boolean
58+
};
59+
60+
export type ThriftLog = {
61+
timestamp: number,
62+
fields: ThriftTag[]
63+
};
64+
65+
export enum ThriftReferenceType {
66+
CHILD_OF = 'CHILD_OF',
67+
FOLLOWS_FROM = 'FOLLOWS_FROM'
68+
}
69+
70+
export type ThriftReference = {
71+
traceIdLow: Buffer,
72+
traceIdHigh: Buffer,
73+
spanId: Buffer,
74+
refType: ThriftReferenceType
75+
};
76+
77+
export type ThriftSpan = {
78+
traceIdLow: Buffer,
79+
traceIdHigh: Buffer,
80+
spanId: Buffer,
81+
parentSpanId: string|Buffer,
82+
operationName: string,
83+
references: ThriftReference[],
84+
flags: number,
85+
startTime: number, // milliseconds
86+
duration: number, // milliseconds
87+
tags: ThriftTag[],
88+
logs: ThriftLog[],
89+
};
90+
4691
/**
4792
* Translate opencensus Span to Jeager Thrift Span
4893
* @param span
4994
*/
50-
export function spanToThrift(span: Span) {
51-
const tags = [];
95+
export function spanToThrift(span: Span): ThriftSpan {
96+
const tags: Tag[] = [];
5297
if (span.attributes) {
5398
Object.keys(span.attributes).forEach(key => {
5499
tags.push({'key': key, 'value': span.attributes[key]});
55100
});
56101
}
57102

58-
const logs = [];
103+
const logs: Log[] = [];
59104
if (span.messageEvents) {
60105
span.messageEvents.forEach(msg => {
61106
logs.push({
@@ -70,7 +115,7 @@ export function spanToThrift(span: Span) {
70115

71116
if (span.annotations) {
72117
span.annotations.forEach(ann => {
73-
const tags = [];
118+
const tags: Tag[] = [];
74119
Object.keys(ann.attributes).forEach(key => {
75120
tags.push({'key': key, 'value': ann.attributes[key]});
76121
});
@@ -83,16 +128,17 @@ export function spanToThrift(span: Span) {
83128
}
84129

85130
const unsigned = true;
86-
const parentSpan = span.parentSpanId ? Utils.encodeInt64(span.parentSpanId) :
87-
ThriftUtils.emptyBuffer;
131+
const parentSpan: string|Buffer = span.parentSpanId ?
132+
Utils.encodeInt64(span.parentSpanId) :
133+
ThriftUtils.emptyBuffer;
88134

89135
const traceId =
90136
`00000000000000000000000000000000${span.spanContext.traceId}`.slice(-32);
91137

92138
const high = traceId.slice(0, 16);
93139
const low = traceId.slice(16);
94-
const spanTags = ThriftUtils.getThriftTags(tags);
95-
const spanLogs = ThriftUtils.getThriftLogs(logs);
140+
const spanTags: ThriftTag[] = ThriftUtils.getThriftTags(tags);
141+
const spanLogs: ThriftLog[] = ThriftUtils.getThriftLogs(logs);
96142

97143
return {
98144
traceIdLow: Utils.encodeInt64(low),

packages/opencensus-exporter-jaeger/src/jaeger.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {Exporter, ExporterBuffer, ExporterConfig, RootSpan, Span} from '@opencen
1818
import {logger, Logger} from '@opencensus/core';
1919
import * as os from 'os';
2020

21-
import {Process, spanToThrift, Tag, ThriftUtils, UDPSender, Utils} from './jaeger-driver';
21+
import {spanToThrift, Tag, TagValue, ThriftProcess, ThriftUtils, UDPSender, Utils} from './jaeger-driver';
2222

2323
/**
2424
* Options for Jaeger configuration
@@ -43,7 +43,7 @@ export class JaegerTraceExporter implements Exporter {
4343
// ip of the process.
4444
static readonly PROCESS_IP = 'ip';
4545

46-
private process: Process;
46+
private process: ThriftProcess;
4747
private logger: Logger;
4848
sender: typeof UDPSender;
4949
queue: Span[] = [];
@@ -65,13 +65,17 @@ export class JaegerTraceExporter implements Exporter {
6565
this.bufferTimeout = options.bufferTimeout;
6666
this.bufferSize = options.bufferSize;
6767
this.sender = new UDPSender(options);
68-
const tags = options.tags || [];
69-
tags[JaegerTraceExporter.JAEGER_OPENCENSUS_EXPORTER_VERSION_TAG_KEY] =
68+
const tags: Tag[] = options.tags || [];
69+
70+
const defaultTags: Record<string, TagValue> = {};
71+
defaultTags[JaegerTraceExporter
72+
.JAEGER_OPENCENSUS_EXPORTER_VERSION_TAG_KEY] =
7073
`opencensus-exporter-jaeger-${pjson.version}`;
71-
tags[JaegerTraceExporter.TRACER_HOSTNAME_TAG_KEY] = os.hostname();
72-
tags[JaegerTraceExporter.PROCESS_IP] = Utils.ipToInt(Utils.myIp());
74+
defaultTags[JaegerTraceExporter.TRACER_HOSTNAME_TAG_KEY] = os.hostname();
75+
defaultTags[JaegerTraceExporter.PROCESS_IP] = Utils.ipToInt(Utils.myIp());
7376

74-
const _tags = Utils.convertObjectToTags(tags);
77+
// Merge the user given tags and the default tags
78+
const _tags: Tag[] = [...tags, ...Utils.convertObjectToTags(defaultTags)];
7579
this.process = {
7680
serviceName: options.serviceName,
7781
tags: ThriftUtils.getThriftTags(_tags),

packages/opencensus-exporter-jaeger/test/test-jaeger.ts

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {spanToThrift, ThriftUtils, UDPSender} from '../src/jaeger-driver';
2727

2828
const DEFAULT_BUFFER_TIMEOUT = 10; // time in milliseconds
2929

30-
import {Process} from '../src/jaeger-driver';
30+
import {ThriftProcess} from '../src/jaeger-driver';
3131
import {SenderCallback} from '../src/jaeger-driver';
3232

3333

@@ -75,6 +75,44 @@ describe('Jaeger Exporter', () => {
7575
exporter.close();
7676
});
7777

78+
describe('exporter configuration', () => {
79+
it('should contain process information', () => {
80+
const process: ThriftProcess = exporter.sender._process;
81+
82+
// Service name
83+
assert.strictEqual(process.serviceName, 'opencensus-exporter-jaeger');
84+
85+
// Tags. Validate that both the user-given and default tags are present.
86+
let testVersionSeen = false;
87+
let testExporterVersionSeen = false;
88+
let testHostnameSeen = false;
89+
let testProcessIpSeen = false;
90+
process.tags.forEach((tag) => {
91+
if (tag.key === 'opencensus-exporter-jeager' &&
92+
tag.vType === 'STRING' && tag.vStr === '0.0.1') {
93+
testVersionSeen = true;
94+
return;
95+
}
96+
if (tag.key ===
97+
JaegerTraceExporter.JAEGER_OPENCENSUS_EXPORTER_VERSION_TAG_KEY) {
98+
testExporterVersionSeen = true;
99+
return;
100+
}
101+
if (tag.key === JaegerTraceExporter.TRACER_HOSTNAME_TAG_KEY) {
102+
testHostnameSeen = true;
103+
return;
104+
}
105+
if (tag.key === JaegerTraceExporter.PROCESS_IP) {
106+
testProcessIpSeen = true;
107+
return;
108+
}
109+
});
110+
assert.ok(
111+
testVersionSeen && testExporterVersionSeen && testHostnameSeen &&
112+
testProcessIpSeen);
113+
});
114+
});
115+
78116
/* Should export spans to Jeager */
79117
describe('test spans are valid', () => {
80118
it('should encode as thrift', () => {
@@ -114,7 +152,7 @@ describe('Jaeger Exporter', () => {
114152
}
115153
});
116154

117-
assert.strictEqual(true, testBoolSeen && testStringSeen && testNumSeen);
155+
assert.ok(testBoolSeen && testStringSeen && testNumSeen);
118156

119157
assert.strictEqual(thriftSpan.logs.length, 1);
120158
thriftSpan.logs.forEach((log) => {
@@ -131,7 +169,7 @@ describe('Jaeger Exporter', () => {
131169
errorSeen = true;
132170
return;
133171
}
134-
assert.strictEqual(true, descriptionSeen && errorSeen);
172+
assert.ok(descriptionSeen && errorSeen);
135173
});
136174
});
137175
});
@@ -174,14 +212,27 @@ describe('Jaeger Exporter', () => {
174212

175213

176214
function mockUDPSender(exporter: JaegerTraceExporter) {
215+
// Get the process of the current sender and pass to the mock sender. The
216+
// process is constructed and attached to the sender at exporter construction
217+
// time at initialization time, so there is no way to intercept the process.
218+
const process: ThriftProcess = exporter.sender._process;
219+
177220
exporter.sender = new MockedUDPSender();
221+
exporter.sender.setProcess(process);
178222
}
179223

180224

181225
class MockedUDPSender extends UDPSender {
182-
queue = [];
226+
// tslint:disable-next-line:no-any
227+
queue: any = [];
183228

184-
setProcess(process: Process): void {}
229+
// Holds the initialized process information. Name matches the associated
230+
// UDPSender property.
231+
_process: ThriftProcess;
232+
233+
setProcess(process: ThriftProcess): void {
234+
this._process = process;
235+
}
185236

186237
// tslint:disable-next-line:no-any
187238
append(span: any, callback?: SenderCallback): void {

packages/opencensus-exporter-jaeger/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"extends": "./node_modules/gts/tsconfig-google.json",
23
"compilerOptions": {
34
"rootDir": ".",
45
"outDir": "build",
@@ -14,5 +15,4 @@
1415
"src/**/*.ts",
1516
"test/**/*.ts"
1617
]
17-
1818
}

0 commit comments

Comments
 (0)