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

Commit 57b1da5

Browse files
authored
Tracing: Add code and message to Span -> Status (#328)
* Add code and message to Span->Status * Use enum(CanonicalCode) for status->code * Update CHANGELOG
1 parent 94cc98c commit 57b1da5

File tree

16 files changed

+250
-85
lines changed

16 files changed

+250
-85
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ All notable changes to this project will be documented in this file.
1111
- Add ignoreIncomingPaths and ignoreOutgoingUrls support to the http and https tracing instrumentations.
1212
- Add ```opencensus-resource-util``` to auto detect AWS, GCE and Kubernetes(K8S) monitored resource, based on the environment where the application is running.
1313
- Add optional `uncompressedSize` and `compressedSize` fields to `MessageEvent` interface.
14+
- Add a ```setStatus``` method in the Span.
1415

1516
**This release has multiple breaking changes. Please test your code accordingly after upgrading.**
1617

1718
- Modify `Logger` interface: `level` made optional, `silly` removed.
1819
- The ```new Stats()``` has been deprecated on Stats class. The global singleton ```globalStats``` object should be used instead. Also, ```registerView()``` is separated out from ```createView()```.
1920
- Use ```TagKey```, ```TagValue``` and ```TagMap``` to create the tag keys, tag values.
21+
- The `status` field on `Span` is no longer a number, use `CanonicalCode` instead.
2022

2123
##### Old code
2224
```js

packages/opencensus-core/src/trace/model/span-base.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import {Clock} from '../../internal/clock';
1818
import {randomSpanId} from '../../internal/util';
1919
import * as types from './types';
2020

21+
const STATUS_OK = {
22+
code: types.CanonicalCode.OK
23+
};
2124

2225
/** Defines a base model for spans. */
2326
export abstract class SpanBase implements types.Span {
@@ -52,7 +55,7 @@ export abstract class SpanBase implements types.Span {
5255
/** Kind of span. */
5356
kind: string = null;
5457
/** A final status for this span */
55-
status: number;
58+
status: types.Status = STATUS_OK;
5659
/** set isRootSpan */
5760
abstract get isRootSpan(): boolean;
5861

@@ -183,6 +186,15 @@ export abstract class SpanBase implements types.Span {
183186
} as types.MessageEvent);
184187
}
185188

189+
/**
190+
* Sets a status to the span.
191+
* @param code The canonical status code.
192+
* @param message optional A developer-facing error message.
193+
*/
194+
setStatus(code: types.CanonicalCode, message?: string) {
195+
this.status = {code, message};
196+
}
197+
186198
/** Starts the span. */
187199
start() {
188200
if (this.started) {

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

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,152 @@ export interface Attributes {
3030
[attributeKey: string]: string|number|boolean;
3131
}
3232

33+
/**
34+
* The status of a Span by providing a standard CanonicalCode in conjunction
35+
* with an optional descriptive message.
36+
*/
37+
export interface Status {
38+
/** The canonical code of this message. */
39+
code: CanonicalCode;
40+
/** A developer-facing error message. */
41+
message?: string;
42+
}
43+
44+
/** An enumeration of canonical status codes. */
45+
export enum CanonicalCode {
46+
/**
47+
* Not an error; returned on success
48+
*/
49+
OK = 0,
50+
/**
51+
* The operation was cancelled (typically by the caller).
52+
*/
53+
CANCELLED = 1,
54+
/**
55+
* Unknown error. An example of where this error may be returned is
56+
* if a status value received from another address space belongs to
57+
* an error-space that is not known in this address space. Also
58+
* errors raised by APIs that do not return enough error information
59+
* may be converted to this error.
60+
*/
61+
UNKNOWN = 2,
62+
/**
63+
* Client specified an invalid argument. Note that this differs
64+
* from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments
65+
* that are problematic regardless of the state of the system
66+
* (e.g., a malformed file name).
67+
*/
68+
INVALID_ARGUMENT = 3,
69+
/**
70+
* Deadline expired before operation could complete. For operations
71+
* that change the state of the system, this error may be returned
72+
* even if the operation has completed successfully. For example, a
73+
* successful response from a server could have been delayed long
74+
* enough for the deadline to expire.
75+
*/
76+
DEADLINE_EXCEEDED = 4,
77+
/**
78+
* Some requested entity (e.g., file or directory) was not found.
79+
*/
80+
NOT_FOUND = 5,
81+
/**
82+
* Some entity that we attempted to create (e.g., file or directory)
83+
* already exists.
84+
*/
85+
ALREADY_EXISTS = 6,
86+
/**
87+
* The caller does not have permission to execute the specified
88+
* operation. PERMISSION_DENIED must not be used for rejections
89+
* caused by exhausting some resource (use RESOURCE_EXHAUSTED
90+
* instead for those errors). PERMISSION_DENIED must not be
91+
* used if the caller can not be identified (use UNAUTHENTICATED
92+
* instead for those errors).
93+
*/
94+
PERMISSION_DENIED = 7,
95+
/**
96+
* Some resource has been exhausted, perhaps a per-user quota, or
97+
* perhaps the entire file system is out of space.
98+
*/
99+
RESOURCE_EXHAUSTED = 8,
100+
/**
101+
* Operation was rejected because the system is not in a state
102+
* required for the operation's execution. For example, directory
103+
* to be deleted may be non-empty, an rmdir operation is applied to
104+
* a non-directory, etc.
105+
*
106+
* A litmus test that may help a service implementor in deciding
107+
* between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE:
108+
*
109+
* - Use UNAVAILABLE if the client can retry just the failing call.
110+
* - Use ABORTED if the client should retry at a higher-level
111+
* (e.g., restarting a read-modify-write sequence).
112+
* - Use FAILED_PRECONDITION if the client should not retry until
113+
* the system state has been explicitly fixed. E.g., if an "rmdir"
114+
* fails because the directory is non-empty, FAILED_PRECONDITION
115+
* should be returned since the client should not retry unless
116+
* they have first fixed up the directory by deleting files from it.
117+
* - Use FAILED_PRECONDITION if the client performs conditional
118+
* REST Get/Update/Delete on a resource and the resource on the
119+
* server does not match the condition. E.g., conflicting
120+
* read-modify-write on the same resource.
121+
*/
122+
FAILED_PRECONDITION = 9,
123+
/**
124+
* The operation was aborted, typically due to a concurrency issue
125+
* like sequencer check failures, transaction aborts, etc.
126+
*
127+
* See litmus test above for deciding between FAILED_PRECONDITION,
128+
* ABORTED, and UNAVAILABLE.
129+
*/
130+
ABORTED = 10,
131+
/**
132+
* Operation was attempted past the valid range. E.g., seeking or
133+
* reading past end of file.
134+
*
135+
* Unlike INVALID_ARGUMENT, this error indicates a problem that may
136+
* be fixed if the system state changes. For example, a 32-bit file
137+
* system will generate INVALID_ARGUMENT if asked to read at an
138+
* offset that is not in the range [0,2^32-1], but it will generate
139+
* OUT_OF_RANGE if asked to read from an offset past the current
140+
* file size.
141+
*
142+
* There is a fair bit of overlap between FAILED_PRECONDITION and
143+
* OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific
144+
* error) when it applies so that callers who are iterating through
145+
* a space can easily look for an OUT_OF_RANGE error to detect when
146+
* they are done.
147+
*/
148+
OUT_OF_RANGE = 11,
149+
/**
150+
* Operation is not implemented or not supported/enabled in this service.
151+
*/
152+
UNIMPLEMENTED = 12,
153+
/**
154+
* Internal errors. Means some invariants expected by underlying
155+
* system has been broken. If you see one of these errors,
156+
* something is very broken.
157+
*/
158+
INTERNAL = 13,
159+
/**
160+
* The service is currently unavailable. This is a most likely a
161+
* transient condition and may be corrected by retrying with
162+
* a backoff.
163+
*
164+
* See litmus test above for deciding between FAILED_PRECONDITION,
165+
* ABORTED, and UNAVAILABLE.
166+
*/
167+
UNAVAILABLE = 14,
168+
/**
169+
* Unrecoverable data loss or corruption.
170+
*/
171+
DATA_LOSS = 15,
172+
/**
173+
* The request does not have valid authentication credentials for the
174+
* operation.
175+
*/
176+
UNAUTHENTICATED = 16,
177+
}
178+
33179
/** A text annotation with a set of attributes. */
34180
export interface Annotation {
35181
/** A user-supplied message describing the event. */
@@ -124,7 +270,7 @@ export interface Span {
124270
logger: loggerTypes.Logger;
125271

126272
/** A final status for this span */
127-
status: number;
273+
status: Status;
128274

129275
/** A set of attributes, each in the format [KEY]:[VALUE] */
130276
attributes: Attributes;
@@ -209,6 +355,13 @@ export interface Span {
209355
*/
210356
addMessageEvent(type: string, id: string, timestamp?: number): void;
211357

358+
/**
359+
* Sets a status to the span.
360+
* @param code The canonical status code.
361+
* @param message optional A developer-facing error message.
362+
*/
363+
setStatus(code: CanonicalCode, message?: string): void;
364+
212365
/** Starts a span. */
213366
start(): void;
214367

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,32 @@ describe('Span', () => {
258258
assert.ok(instanceOfLink(span.messageEvents[0]));
259259
});
260260
});
261+
262+
describe('setStatus()', () => {
263+
it('should return default status', () => {
264+
const rootSpan = new RootSpan(tracer);
265+
rootSpan.start();
266+
267+
const span = new Span(rootSpan);
268+
span.start();
269+
270+
assert.equal(rootSpan.status.code, 0);
271+
assert.equal(rootSpan.status.message, null);
272+
assert.equal(span.status.code, 0);
273+
assert.equal(span.status.message, null);
274+
});
275+
276+
it('should set an error status', () => {
277+
const rootSpan = new RootSpan(tracer);
278+
rootSpan.start();
279+
const span = new Span(rootSpan);
280+
span.start();
281+
span.setStatus(types.CanonicalCode.PERMISSION_DENIED, 'This is an error');
282+
283+
assert.equal(rootSpan.status.code, 0);
284+
assert.equal(rootSpan.status.message, null);
285+
assert.equal(span.status.code, 7);
286+
assert.equal(span.status.message, 'This is an error');
287+
});
288+
});
261289
});

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ export class InstanaTraceExporter implements Exporter {
110110
duration: span.duration,
111111
name: span.name,
112112
type: spanKindTranslation[span.kind] || span.kind,
113-
error: span.status != null && span.status !== 0,
113+
error: span.status != null && span.status.code !== 0,
114114
data: Object.keys(span.attributes)
115115
.reduce(
116116
(agg: {[k: string]: string}, key) => {

packages/opencensus-exporter-ocagent/src/adapters.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,6 @@ const adaptTimeEvents =
193193
};
194194
};
195195

196-
/**
197-
* Adapts a statusCode number to a `opencensus.proto.trace.v1.Status` type.
198-
* @param statusCode number
199-
* @returns opencensus.proto.trace.v1.Status
200-
*/
201-
const adaptStatus = (statusCode: number): opencensus.proto.trace.v1.Status => {
202-
return {code: statusCode, message: null};
203-
};
204-
205196
/**
206197
* Adapts a traceState string to a `opencensus.proto.trace.v1.Span.Tracestate`
207198
* type. The tracestate is a comma-delimited set of equals-delimited key-value
@@ -285,7 +276,7 @@ export const adaptSpan = (span: Span): opencensus.proto.trace.v1.Span => {
285276
stackTrace: null, // Unsupported by nodejs
286277
timeEvents: adaptTimeEvents(span.annotations, span.messageEvents),
287278
links: adaptLinks(span.links),
288-
status: adaptStatus(span.status),
279+
status: span.status,
289280
sameProcessAsParentSpan: adaptBoolean(!span.remoteParent),
290281
childSpanCount: null,
291282
};

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

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

1717
import * as protoLoader from '@grpc/proto-loader';
18-
import {RootSpan, TraceOptions, Tracing} from '@opencensus/core';
18+
import {CanonicalCode, RootSpan, TraceOptions, Tracing} from '@opencensus/core';
1919
import * as nodeTracing from '@opencensus/nodejs';
2020
import * as assert from 'assert';
2121
import {EventEmitter} from 'events';
@@ -328,7 +328,7 @@ describe('OpenCensus Agent Exporter', () => {
328328

329329
tracing.tracer.startRootSpan(rootSpanOptions, (rootSpan: RootSpan) => {
330330
// Status
331-
rootSpan.status = 200;
331+
rootSpan.setStatus(CanonicalCode.OK);
332332

333333
// Attribute
334334
rootSpan.addAttribute('my_attribute_string', 'bar2');
@@ -385,12 +385,11 @@ describe('OpenCensus Agent Exporter', () => {
385385
span.tracestate.entries,
386386
[{key: 'foo', value: 'bar'}, {key: 'baz', value: 'buzz'}]);
387387

388-
// Status
389388
if (!span.status) {
390389
assert.fail('span.status is null or undefined');
391-
return;
390+
} else {
391+
assert.deepEqual(span.status, {code: 0, message: ''});
392392
}
393-
assert.equal(span.status.code, 200);
394393

395394
// Attributes
396395
if (!span.attributes) {
@@ -507,4 +506,4 @@ describe('OpenCensus Agent Exporter', () => {
507506
rootSpan.end();
508507
});
509508
});
510-
});
509+
});

packages/opencensus-exporter-zpages/src/zpages-frontend/page-handlers/tracez.page-handler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export class TracezPageHandler {
144144

145145
// Building span list
146146
for (const span of spans) {
147-
if (span.status && span.status !== 0) {
147+
if (span.status && span.status.code !== 0) {
148148
spanCell.ERRORS += 1;
149149
} else if (span.ended) {
150150
const durationNs =
@@ -208,14 +208,14 @@ export class TracezPageHandler {
208208
if (this.traceMap.has(params.tracename)) {
209209
for (const span of this.traceMap.get(params.tracename)!) {
210210
if (params.type === 'ERRORS') {
211-
if (span.status !== 0) {
211+
if (span.status.code !== 0) {
212212
traceList.push(span);
213213
}
214214
} else if (params.type === 'RUNNING') {
215215
if (span.started && !span.ended) {
216216
traceList.push(span);
217217
}
218-
} else if (span.ended && span.status === 0) {
218+
} else if (span.ended && span.status.code === 0) {
219219
const durationNs =
220220
LatencyBucketBoundaries.millisecondsToNanos(span.duration);
221221
const latency =

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,9 @@ export class ZpagesExporter implements Exporter, StatsEventListener {
139139
* @param trace the rootSpan to be sent to the array list
140140
*/
141141
private sendTrace(trace: RootSpan) {
142-
/** If there is no status, put status 0 (OK) */
143-
if (!trace.status) {
144-
trace.status = 0;
145-
}
146142
this.pushSpan(trace);
147143

148144
for (const span of trace.spans) {
149-
/** If there is no status, put status 0 (OK) */
150-
if (!span.status) {
151-
span.status = 0;
152-
}
153145
this.pushSpan(span);
154146
}
155147
this.logger.debug('Z-PAGES: trace added');

0 commit comments

Comments
 (0)