forked from opentracing/opentracing-javascript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
zone_scope_manager.ts
122 lines (106 loc) · 3.89 KB
/
zone_scope_manager.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import BaseScope from './base_scope';
import Span from './span';
import Scope from './scope';
import ScopeManager from './scope_manager';
import {ZoneSpec} from './zone_types';
const defaultZoneName = 'opentracing';
const propertyKey = 'opentracing';
class PropertyData {
readonly tasks = new WeakMap<Task, Span | null>();
constructor(public span: Span | null) {
}
};
type Property = {
owner: ZoneScopeManager,
data: PropertyData,
};
/**
* ScopeManager using {@link Zone.js|https://github.com/angular/zone.js}.
*
* It works only for code initiated from a set-up zone:
*
* Zone.current.fork(scopeManager.zoneSpec()).run(() => {
* // code
* });
*/
export class ZoneScopeManager implements ScopeManager {
private scope: Scope | null = null;
constructor(private readonly name: string = defaultZoneName) {
}
private readonly _setScopeAndSpan = (scope: Scope | null) => {
const data = this._data(Zone.current);
if (data) {
data.span = scope && scope.span();
this.scope = scope;
} else {
console.warn('Scopes should be in an Opentracing zone');
}
}
private _localScope(span: Span | null) {
return new BaseScope(span, false, this.scope, this._setScope);
}
private readonly _setScope = (scope: Scope | null) => this.scope = scope;
private _data(zone: Zone): PropertyData | null {
for (; zone = zone.getZoneWith(propertyKey); zone = zone.parent) {
const {data, owner} = <Property>zone.get(propertyKey);
if (this === owner) {
return data;
}
}
return null;
}
private _property(span: Span | null): Property {
return {data: new PropertyData(span), owner: this};
}
activate(span: Span, finishOnClose: boolean) {
return new BaseScope(span, finishOnClose, this.scope, this._setScopeAndSpan);
}
active() {
return this.scope;
}
zoneSpec(): ZoneSpec {
return {
name: this.name,
onCancelTask: (parent, current, target, task) => {
const {tasks} = this._data(target)!;
tasks.delete(task);
return parent.cancelTask(target, task);
},
onFork: (parent, current, target, spec) => {
const {span} = this._data(target)!;
return parent.fork(target, spec).fork({
name: this.name,
properties: {
[propertyKey]: this._property(span),
},
});
},
onInvokeTask: (parent, current, target, task, applyThis, applyArgs) => {
const {tasks} = this._data(target)!;
const span = tasks.get(task);
if (span === undefined) {
console.warn('Could not find span for task');
return parent.invokeTask(target, task, applyThis, applyArgs);
}
return this._localScope(span).run(() => parent.invokeTask(target, task, applyThis, applyArgs));
},
onIntercept: (parent, current, target, delegate, source) => {
const {span} = this._data(target)!;
const manager = this;
const wrappedDelegate = function() {
return manager._localScope(span).run(Function.apply.bind(delegate, this, arguments));
};
return parent.intercept(target, wrappedDelegate, source);
},
onScheduleTask: (parent, current, target, task) => {
const {span, tasks} = this._data(target)!;
tasks.set(task, span);
return parent.scheduleTask(target, task);
},
properties: {
[propertyKey]: this._property(null),
},
};
}
}
export default ZoneScopeManager;