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

Commit c5a7d07

Browse files
authored
Add support for gRPC tags propagation (#443)
* Tags: gRPC propagation * return null within the catch block
1 parent b5a49c1 commit c5a7d07

File tree

12 files changed

+311
-74
lines changed

12 files changed

+311
-74
lines changed

examples/tags/tag-context-example.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,40 @@
1414
* limitations under the License.
1515
*/
1616

17-
const core = require('@opencensus/core');
17+
const {globalStats, MeasureUnit, TagMap} = require('@opencensus/core');
1818

1919
const K1 = { name: 'k1' };
2020
const K2 = { name: 'k2' };
2121
const V1 = { value: 'v1' };
2222
const V2 = { value: 'v2' };
2323

24-
const mLatencyMs = core.globalStats.createMeasureDouble(
25-
'm1', core.MeasureUnit.MS, '1st test metric'
24+
const mLatencyMs = globalStats.createMeasureDouble(
25+
'm1', MeasureUnit.MS, '1st test metric'
2626
);
2727

2828
/** Main method. */
2929
function main () {
30-
const tags1 = new core.TagMap();
30+
const tags1 = new TagMap();
3131
tags1.set(K1, V1);
3232

33-
core.withTagContext(tags1, () => {
33+
globalStats.withTagContext(tags1, () => {
3434
console.log('Enter Scope 1');
3535
printMap('Add Tags', tags1.tags);
36-
printMap('Current Tags == Default + tags1:', core.getCurrentTagContext().tags);
36+
printMap('Current Tags == Default + tags1:',
37+
globalStats.getCurrentTagContext().tags);
3738

38-
const tags2 = new core.TagMap();
39+
const tags2 = new TagMap();
3940
tags2.set(K2, V2);
40-
core.withTagContext(tags2, () => {
41+
globalStats.withTagContext(tags2, () => {
4142
console.log('Enter Scope 2');
4243
printMap('Add Tags', tags2.tags);
43-
printMap('Current Tags == Default + tags1 + tags2:', core.getCurrentTagContext().tags);
44+
printMap('Current Tags == Default + tags1 + tags2:', globalStats.getCurrentTagContext().tags);
4445

4546
const measurement = { measure: mLatencyMs, value: 10 };
46-
core.globalStats.record([measurement]);
47+
globalStats.record([measurement]);
4748
console.log('Close Scope 2');
4849
});
49-
printMap('Current Tags == Default + tags1:', core.getCurrentTagContext().tags);
50+
printMap('Current Tags == Default + tags1:', globalStats.getCurrentTagContext().tags);
5051
console.log('Close Scope 1');
5152
});
5253
}

packages/opencensus-core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export * from './stats/bucket-boundaries';
7272
export * from './stats/metric-utils';
7373
export * from './tags/tag-map';
7474
export * from './tags/tagger';
75+
export * from './tags/propagation/binary-serializer';
7576
export * from './tags/propagation/text-format';
7677
export * from './resource/resource';
7778

packages/opencensus-core/src/internal/cls-ah.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class AsyncHooksNamespace implements CLSNamespace {
6464
runAndReturn<T>(fn: Func<T>): T {
6565
const oldContext = current;
6666
current = {};
67+
if (oldContext['current_tag_map']) {
68+
current['current_tag_map'] = oldContext['current_tag_map'];
69+
}
6770
const res = fn();
6871
current = oldContext;
6972
return res;

packages/opencensus-core/src/internal/cls.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,5 @@ export function destroyNamespace(): void {
5252
export function getNamespace(): CLS.Namespace {
5353
return cls.getNamespace(TRACE_NAMESPACE);
5454
}
55+
56+
export const contextManager = createNamespace();

packages/opencensus-core/src/stats/stats.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
import * as defaultLogger from '../common/console-logger';
1818
import * as loggerTypes from '../common/types';
1919
import {StatsEventListener} from '../exporters/types';
20+
import * as cls from '../internal/cls';
2021
import {Metric} from '../metrics/export/types';
2122
import {Metrics} from '../metrics/metrics';
2223
import {TagMap} from '../tags/tag-map';
23-
import {getCurrentTagContext} from '../tags/tagger';
24+
import * as tagger from '../tags/tagger';
2425
import {TagKey} from '../tags/types';
26+
2527
import {MetricProducerForStats} from './metric-producer';
2628
import {AggregationType, Measure, Measurement, MeasureType, MeasureUnit, Stats, View} from './types';
2729
import {BaseView} from './view';
@@ -35,13 +37,16 @@ export class BaseStats implements Stats {
3537
private logger: loggerTypes.Logger;
3638
/** Singleton instance */
3739
private static singletonInstance: BaseStats;
40+
/** Manage context automatic propagation */
41+
private contextManager: cls.Namespace;
3842

3943
/**
4044
* Creates stats
4145
* @param logger
4246
*/
4347
constructor(logger = defaultLogger) {
4448
this.logger = logger.logger();
49+
this.contextManager = cls.getNamespace();
4550

4651
// Create a new MetricProducerForStats and register it to
4752
// MetricProducerManager when Stats is initialized.
@@ -189,7 +194,7 @@ export class BaseStats implements Stats {
189194

190195
if (!tags) {
191196
// Record against implicit (current) context
192-
tags = getCurrentTagContext();
197+
tags = this.getCurrentTagContext();
193198
}
194199

195200
for (const measurement of measurements) {
@@ -216,4 +221,20 @@ export class BaseStats implements Stats {
216221
this.registeredViews = {};
217222
this.statsEventListeners = [];
218223
}
224+
225+
/**
226+
* Enters the scope of code where the given `TagMap` is in the current context
227+
* (replacing the previous `TagMap`).
228+
* @param tags The TagMap to be set to the current context.
229+
* @param fn Callback function.
230+
* @returns The callback return.
231+
*/
232+
withTagContext<T>(tags: TagMap, fn: cls.Func<T>): T {
233+
return tagger.withTagContext<T>(this.contextManager, tags, fn);
234+
}
235+
236+
/** Gets the current tag context. */
237+
getCurrentTagContext(): TagMap {
238+
return tagger.getCurrentTagContext(this.contextManager);
239+
}
219240
}

packages/opencensus-core/src/stats/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import {StatsEventListener} from '../exporters/types';
18+
import * as cls from '../internal/cls';
1819
import {Metric} from '../metrics/export/types';
1920
import {TagMap} from '../tags/tag-map';
2021
import {TagKey, TagValue} from '../tags/types';
@@ -98,6 +99,18 @@ export interface Stats {
9899
* @param exporter An stats exporter
99100
*/
100101
unregisterExporter(exporter: StatsEventListener): void;
102+
103+
/**
104+
* Enters the scope of code where the given `TagMap` is in the current context
105+
* (replacing the previous `TagMap`).
106+
* @param tags The TagMap to be set to the current context.
107+
* @param fn Callback function.
108+
* @returns The callback return.
109+
*/
110+
withTagContext<T>(tags: TagMap, fn: cls.Func<T>): T;
111+
112+
/** Gets the current tag context. */
113+
getCurrentTagContext(): TagMap;
101114
}
102115

103116
/**

packages/opencensus-core/src/tags/tagger.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,25 @@
1717
import * as cls from '../internal/cls';
1818
import {TagMap} from './tag-map';
1919

20-
const contextManager = cls.createNamespace();
2120
export const EMPTY_TAG_MAP = new TagMap();
2221
const CURRENT_TAG_MAP_KEY = 'current_tag_map';
2322

2423
/** Gets the current tag context. */
25-
export function getCurrentTagContext(): TagMap {
24+
export function getCurrentTagContext(contextManager: cls.Namespace): TagMap {
2625
const tagsFromContext = contextManager.get(CURRENT_TAG_MAP_KEY);
2726
if (tagsFromContext) {
28-
return tagsFromContext as TagMap;
27+
return makeDeepCopy(tagsFromContext as TagMap);
2928
}
30-
return EMPTY_TAG_MAP;
29+
return new TagMap();
3130
}
3231

3332
/**
3433
* Sets the current tag context.
3534
* @param tags The TagMap.
3635
*/
37-
export function setCurrentTagContext(tags: TagMap) {
38-
contextManager.set(CURRENT_TAG_MAP_KEY, tags);
36+
export function setCurrentTagContext(
37+
contextManager: cls.Namespace, tags: TagMap) {
38+
contextManager.set(CURRENT_TAG_MAP_KEY, makeDeepCopy(tags));
3939
}
4040

4141
/**
@@ -45,8 +45,9 @@ export function setCurrentTagContext(tags: TagMap) {
4545
* @param fn Callback function.
4646
* @returns The callback return.
4747
*/
48-
export function withTagContext<T>(tags: TagMap, fn: cls.Func<T>): T {
49-
const oldContext = getCurrentTagContext();
48+
export function withTagContext<T>(
49+
contextManager: cls.Namespace, tags: TagMap, fn: cls.Func<T>): T {
50+
const oldContext = getCurrentTagContext(contextManager);
5051
return contextManager.runAndReturn(() => {
5152
const newContext = new TagMap();
5253
for (const [tagKey, tagValue] of oldContext.tags) {
@@ -55,12 +56,21 @@ export function withTagContext<T>(tags: TagMap, fn: cls.Func<T>): T {
5556
for (const [tagKey, tagValue] of tags.tags) {
5657
newContext.set(tagKey, tagValue);
5758
}
58-
setCurrentTagContext(newContext);
59+
setCurrentTagContext(contextManager, newContext);
5960
return fn();
6061
});
6162
}
6263

6364
/** Clear the current tag context. */
64-
export function clear() {
65-
contextManager.set(CURRENT_TAG_MAP_KEY, EMPTY_TAG_MAP);
65+
export function clear(contextManager: cls.Namespace) {
66+
contextManager.set(CURRENT_TAG_MAP_KEY, new TagMap());
67+
}
68+
69+
function makeDeepCopy(tags: TagMap) {
70+
const tagsCopy = new TagMap();
71+
for (const [tagKey, valueWithMetadata] of tags.tagsWithMetadata) {
72+
tagsCopy.set(
73+
tagKey, valueWithMetadata.tagValue, valueWithMetadata.tagMetadata);
74+
}
75+
return tagsCopy;
6676
}

packages/opencensus-core/src/trace/model/tracer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export class CoreTracer implements types.Tracer {
5151
/** Constructs a new TraceImpl instance. */
5252
constructor() {
5353
this.activeLocal = false;
54-
this.contextManager = cls.createNamespace();
54+
this.contextManager = cls.getNamespace();
5555
this.clearCurrentTrace();
5656
this.activeTraceParams = {};
5757
}

packages/opencensus-core/test/test-stats.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ describe('Stats', () => {
232232
tags.set(tagKeys[0], {value: 'value1'});
233233
tags.set(tagKeys[1], {value: 'value2'});
234234
const measurement = {measure, value: 1};
235-
tagger.withTagContext(tags, () => {
235+
globalStats.withTagContext(tags, () => {
236236
globalStats.record([measurement]);
237237
});
238238

@@ -250,7 +250,7 @@ describe('Stats', () => {
250250
const UNKNOWN_TAG_VALUE: TagValue = null;
251251
globalStats.registerExporter(testExporter);
252252
const measurement = {measure, value: 2211};
253-
tagger.withTagContext(tagger.EMPTY_TAG_MAP, () => {
253+
globalStats.withTagContext(tagger.EMPTY_TAG_MAP, () => {
254254
globalStats.record([measurement]);
255255
});
256256

packages/opencensus-core/test/test-tagger.ts

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616

1717
import * as assert from 'assert';
1818
import {TagMap} from '../src';
19+
import * as cls from '../src/internal/cls';
1920
import * as tagger from '../src/tags/tagger';
2021

22+
const contextManager = cls.getNamespace();
23+
2124
describe('tagger()', () => {
2225
const tags1 = new TagMap();
2326
tags1.set({name: 'key1'}, {value: 'value1'});
@@ -54,57 +57,68 @@ describe('tagger()', () => {
5457
expectedTagsFrom1n3n4.set({name: 'key6'}, {value: 'value6'});
5558

5659
it('should return empty current tag context', () => {
57-
tagger.withTagContext(tagger.EMPTY_TAG_MAP, () => {
60+
tagger.withTagContext(contextManager, tagger.EMPTY_TAG_MAP, () => {
5861
assert.deepStrictEqual(
59-
tagger.getCurrentTagContext(), tagger.EMPTY_TAG_MAP);
62+
tagger.getCurrentTagContext(contextManager), tagger.EMPTY_TAG_MAP);
6063
});
6164
});
6265

6366
it('should set current tag context', () => {
64-
tagger.withTagContext(tags1, () => {
65-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tags1);
67+
tagger.withTagContext(contextManager, tags1, () => {
68+
assert.deepStrictEqual(
69+
tagger.getCurrentTagContext(contextManager), tags1);
6670
});
67-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tagger.EMPTY_TAG_MAP);
71+
assert.deepStrictEqual(
72+
tagger.getCurrentTagContext(contextManager), tagger.EMPTY_TAG_MAP);
6873
});
6974

7075
it('should set nested current tag context', () => {
71-
tagger.withTagContext(tags1, () => {
72-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tags1);
76+
tagger.withTagContext(contextManager, tags1, () => {
77+
assert.deepStrictEqual(
78+
tagger.getCurrentTagContext(contextManager), tags1);
7379

74-
tagger.withTagContext(tags2, () => {
80+
tagger.withTagContext(contextManager, tags2, () => {
7581
assert.deepStrictEqual(
76-
tagger.getCurrentTagContext(), expectedMergedTags);
82+
tagger.getCurrentTagContext(contextManager), expectedMergedTags);
7783
});
78-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tags1);
84+
assert.deepStrictEqual(
85+
tagger.getCurrentTagContext(contextManager), tags1);
7986
});
80-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tagger.EMPTY_TAG_MAP);
87+
assert.deepStrictEqual(
88+
tagger.getCurrentTagContext(contextManager), tagger.EMPTY_TAG_MAP);
8189
});
8290

8391
it('should resolve tag conflicts', () => {
84-
tagger.withTagContext(tags1, () => {
85-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tags1);
92+
tagger.withTagContext(contextManager, tags1, () => {
93+
assert.deepStrictEqual(
94+
tagger.getCurrentTagContext(contextManager), tags1);
8695

87-
tagger.withTagContext(tags3, () => {
96+
tagger.withTagContext(contextManager, tags3, () => {
8897
assert.deepStrictEqual(
89-
tagger.getCurrentTagContext(), expectedTagsFrom1n3);
98+
tagger.getCurrentTagContext(contextManager), expectedTagsFrom1n3);
9099

91-
tagger.withTagContext(tags4, () => {
100+
tagger.withTagContext(contextManager, tags4, () => {
92101
assert.deepStrictEqual(
93-
tagger.getCurrentTagContext(), expectedTagsFrom1n3n4);
102+
tagger.getCurrentTagContext(contextManager),
103+
expectedTagsFrom1n3n4);
94104
});
95105
});
96-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tags1);
106+
assert.deepStrictEqual(
107+
tagger.getCurrentTagContext(contextManager), tags1);
97108
});
98-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tagger.EMPTY_TAG_MAP);
109+
assert.deepStrictEqual(
110+
tagger.getCurrentTagContext(contextManager), tagger.EMPTY_TAG_MAP);
99111
});
100112

101113
it('should clear current tag context', () => {
102-
tagger.withTagContext(tags1, () => {
103-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tags1);
104-
tagger.clear();
114+
tagger.withTagContext(contextManager, tags1, () => {
115+
assert.deepStrictEqual(
116+
tagger.getCurrentTagContext(contextManager), tags1);
117+
tagger.clear(contextManager);
105118
assert.deepStrictEqual(
106-
tagger.getCurrentTagContext(), tagger.EMPTY_TAG_MAP);
119+
tagger.getCurrentTagContext(contextManager), tagger.EMPTY_TAG_MAP);
107120
});
108-
assert.deepStrictEqual(tagger.getCurrentTagContext(), tagger.EMPTY_TAG_MAP);
121+
assert.deepStrictEqual(
122+
tagger.getCurrentTagContext(contextManager), tagger.EMPTY_TAG_MAP);
109123
});
110124
});

0 commit comments

Comments
 (0)