This repository has been archived by the owner on May 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 145
/
span.js
274 lines (253 loc) · 8.65 KB
/
span.js
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
'use strict';
import Tracer from './tracer';
let defaultTracer = require('./default_tracer');
const kKeyRegExp = new RegExp(/^[a-z0-9][-a-z0-9]*/);
/**
* Span represents a logical unit of work as part of a broader Trace. Examples
* of span might include remote procedure calls or a in-process function calls
* to sub-components. A Trace has a single, top-level "root" Span that in turn
* may have zero or more child Spans, which in turn may have children.
*/
export default class Span {
// ---------------------------------------------------------------------- //
// OpenTracing API methods
// ---------------------------------------------------------------------- //
/**
* Returns the Tracer object used to create this Span.
*
* @return {Tracer}
*/
tracer() {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 0) {
throw new Error('Invalid number of arguments');
}
}
if (this._imp) {
return new Tracer(this._imp.tracer());
}
return defaultTracer;
}
/**
* Sets the string name for the logical operation this span represents.
*
* @param {string} name
*/
setOperationName(name) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 1) {
throw new Error('Invalid number of arguments');
}
if (typeof name !== 'string' || name.length > 0) {
throw new Error('Name must be a string of length > 0');
}
}
if (this._imp) {
this._imp.setOperationName(name);
}
return this;
}
/**
* Adds a single tag to the span. See `AddTags()` for details.
*
* @param {string} key
* @param {any} value
*/
setTag(key, value) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 2) {
throw new Error('Invalid number of arguments');
}
if (typeof key !== 'string') {
throw new Error('Tag key must be a string');
}
}
this.addTags({ [key] : value });
return this;
}
/**
* Adds the given key value pairs to the set of span tags.
*
* Multiple calls to addTags() results in the tags being the superset of
* all calls.
*
* The behavior of setting the same key multiple times on the same span
* is undefined.
*
* The supported type of the values is implementation-dependent.
* Implementations are expected to safely handle all types of values but
* may choose to ignore unrecognized / unhandle-able values (e.g. objects
* with cyclic references, function objects).
*
* @return {[type]} [description]
*/
addTags(keyValuePairs) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 1) {
throw new Error('Invalid number of arguments');
}
if (typeof keyValuePairs !== 'object') {
throw new Error('Invalid argument type');
}
}
if (!this._imp) {
return;
}
this._imp.addTags(keyValuePairs);
return this;
}
/**
* Set an arbitrary key-value string pair that will be carried along the
* full path of a trace.
*
* All spans created as children of this span will inherit the baggage items
* of this span.
*
* Baggage items are copied between all spans, both in-process and across
* distributed requests, therefore this feature should be used with care to
* ensure undue overhead is not incurred.
*
* Keys are case insensitive and must match the regular expresssion
* `[a-z0-9][-a-z0-9]*`.
*
* @param {string} key
* @param {string} value
*/
setBaggageItem(key, value) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 2) {
throw new Error('Expected 2 arguments');
}
if (typeof key !== 'string' || key.length === 0) {
throw new Error('Key must be a string');
}
if (!kKeyRegExp.test(key)) {
throw new Error('Invalid trace key');
}
let valueType = typeof value;
if (value !== null &&
valueType !== 'boolean' &&
valueType !== 'number' &&
valueType !== 'string') {
throw new Error('Trace attribute values can only be basic types');
}
}
if (this._imp) {
this._imp.setBaggageItem(key, value);
}
return this;
}
/**
* Returns the value for the given baggage item key.
*
* @param {string} key
* The key for the given trace attribute.
* @return {string}
* String value for the given key, or undefined if the key does not
* correspond to a set trace attribute.
*/
getBaggageItem(key) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 1) {
throw new Error('Expected 1 arguments');
}
if (typeof key !== 'string' || key.length === 0) {
throw new Error('Key must be a string');
}
if (!kKeyRegExp.test(key)) {
throw new Error('Invalid trace key');
}
}
if (!this._imp) {
return undefined;
}
return this._imp.getBaggageItem(key);
}
/**
* Explicitly create a log record associated with the span.
*
* @param {object} fields - object containing the log record properties
* @param {number} [fields.timestamp] - optional field specifying the
* timestamp in milliseconds as a Unix timestamp. Fractional values
* are allowed so that timestamps with sub-millisecond accuracy
* can be represented. If not specified, the implementation is
* expected to use it's notion of the current time of the call.
* @param {string} [fields.event] - the event name
* @param {object} [fields.payload] - an arbitrary structured payload. It is
* implementation-dependent how this will be processed.
*/
log(fields) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length !== 1) {
throw new Error('Invalid number of arguments');
}
if (typeof fields !== 'object') {
throw new Error('Expected fields to be an object');
}
}
if (!this._imp) {
return;
}
this._imp.log(fields);
return this;
}
/**
* Logs a event with an optional payload.
*
* @param {string} eventName - string associated with the log record
* @param {object} [payload] - arbitrary payload object associated with the
* log record.
*/
logEvent(eventName, payload) {
return this.log({
'event' : eventName,
'payload' : payload,
});
}
/**
* Indicates that the unit of work represented by the span is complete or
* has otherwise been terminated.
*
* All Span objects must have finish() called on them before they are
* reported to the backend implementation.
*
* Once `finish()` is called on a Span object, the behavior of all methods
* on the object is considered undefined.
*
* @param {Number} finishTime
* Optional finish time in milliseconds as a Unix timestamp. Decimal
* values are supported for timestamps with sub-millisecond accuracy.
* If not specified, the current time (as defined by the
* implementation) will be used.
*/
finish(finishTime) {
if (API_CONFORMANCE_CHECKS) {
if (arguments.length > 1) {
throw new Error('Invalid arguments');
}
if (arguments.length === 1 && typeof finishTime !== 'number') {
throw new Error('Unexpected argument type');
}
}
if (!this._imp) {
return;
}
this._imp.finish(finishTime);
}
// ---------------------------------------------------------------------- //
// Private and non-standard methods
// ---------------------------------------------------------------------- //
/**
* Constructs a new Span object. This method should not be called directly.
*/
constructor(imp) {
this._imp = imp;
}
/**
* Returns the Span implementation object. The returned object is by its
* nature entirely implementation-dependent.
*/
imp() {
return this._imp;
}
}