feat(api): add attributes argument to recordException API (#4071)
Co-authored-by: Marc Pichler <marc.pichler@dynatrace.com>
This commit is contained in:
parent
c84637f264
commit
cd4998a4b5
|
|
@ -11,6 +11,7 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/
|
||||||
|
|
||||||
### :rocket: (Enhancement)
|
### :rocket: (Enhancement)
|
||||||
|
|
||||||
|
* feat(api): add attributes argument to recordException API [#4071](https://github.com/open-telemetry/opentelemetry-js/pull/4071)
|
||||||
* feat(sdk-metrics): implement MetricProducer specification [#4007](https://github.com/open-telemetry/opentelemetry-js/pull/4007)
|
* feat(sdk-metrics): implement MetricProducer specification [#4007](https://github.com/open-telemetry/opentelemetry-js/pull/4007)
|
||||||
* feat: update PeriodicExportingMetricReader and PrometheusExporter to accept optional metric producers [#4077](https://github.com/open-telemetry/opentelemetry-js/pull/4077) @aabmass
|
* feat: update PeriodicExportingMetricReader and PrometheusExporter to accept optional metric producers [#4077](https://github.com/open-telemetry/opentelemetry-js/pull/4077) @aabmass
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### :rocket: (Enhancement)
|
||||||
|
|
||||||
|
* feat(api): add attributes argument to recordException API [#4071](https://github.com/open-telemetry/opentelemetry-js/pull/4071)
|
||||||
|
|
||||||
## 1.4.1
|
## 1.4.1
|
||||||
|
|
||||||
### :bug: (Bug Fix)
|
### :bug: (Bug Fix)
|
||||||
|
|
|
||||||
|
|
@ -71,5 +71,9 @@ export class NonRecordingSpan implements Span {
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default does nothing
|
// By default does nothing
|
||||||
recordException(_exception: Exception, _time?: TimeInput): void {}
|
recordException(
|
||||||
|
_exception: Exception,
|
||||||
|
_attributesOrStartTime?: SpanAttributes | TimeInput,
|
||||||
|
_time?: TimeInput
|
||||||
|
): void {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,4 +126,17 @@ export interface Span {
|
||||||
* use the current time.
|
* use the current time.
|
||||||
*/
|
*/
|
||||||
recordException(exception: Exception, time?: TimeInput): void;
|
recordException(exception: Exception, time?: TimeInput): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets exception as a span event
|
||||||
|
* @param exception the exception the only accepted values are string or Error
|
||||||
|
* @param [attributes] the attributes that will be added to the error event.
|
||||||
|
* @param [time] the time to set as Span's event time. If not provided,
|
||||||
|
* use the current time.
|
||||||
|
*/
|
||||||
|
recordException(
|
||||||
|
exception: Exception,
|
||||||
|
attributes?: SpanAttributes,
|
||||||
|
time?: TimeInput
|
||||||
|
): void;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,18 @@ export class Span implements APISpan, ReadableSpan {
|
||||||
return this._ended === false;
|
return this._ended === false;
|
||||||
}
|
}
|
||||||
|
|
||||||
recordException(exception: Exception, time?: TimeInput): void {
|
recordException(
|
||||||
|
exception: Exception,
|
||||||
|
attributesOrStartTime?: SpanAttributes | TimeInput,
|
||||||
|
timeStamp?: TimeInput
|
||||||
|
): void {
|
||||||
|
if (isTimeInput(attributesOrStartTime)) {
|
||||||
|
if (!isTimeInput(timeStamp)) {
|
||||||
|
timeStamp = attributesOrStartTime;
|
||||||
|
}
|
||||||
|
attributesOrStartTime = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const attributes: SpanAttributes = {};
|
const attributes: SpanAttributes = {};
|
||||||
if (typeof exception === 'string') {
|
if (typeof exception === 'string') {
|
||||||
attributes[SemanticAttributes.EXCEPTION_MESSAGE] = exception;
|
attributes[SemanticAttributes.EXCEPTION_MESSAGE] = exception;
|
||||||
|
|
@ -290,13 +301,16 @@ export class Span implements APISpan, ReadableSpan {
|
||||||
attributes[SemanticAttributes.EXCEPTION_STACKTRACE] = exception.stack;
|
attributes[SemanticAttributes.EXCEPTION_STACKTRACE] = exception.stack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (attributesOrStartTime) {
|
||||||
|
Object.assign(attributes, sanitizeAttributes(attributesOrStartTime));
|
||||||
|
}
|
||||||
|
|
||||||
// these are minimum requirements from spec
|
// these are minimum requirements from spec
|
||||||
if (
|
if (
|
||||||
attributes[SemanticAttributes.EXCEPTION_TYPE] ||
|
attributes[SemanticAttributes.EXCEPTION_TYPE] ||
|
||||||
attributes[SemanticAttributes.EXCEPTION_MESSAGE]
|
attributes[SemanticAttributes.EXCEPTION_MESSAGE]
|
||||||
) {
|
) {
|
||||||
this.addEvent(ExceptionEventName, attributes, time);
|
this.addEvent(ExceptionEventName, attributes, timeStamp);
|
||||||
} else {
|
} else {
|
||||||
diag.warn(`Failed to record an exception ${exception}`);
|
diag.warn(`Failed to record an exception ${exception}`);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1203,6 +1203,77 @@ describe('Span', () => {
|
||||||
const event = span.events[0];
|
const event = span.events[0];
|
||||||
assert.deepStrictEqual(event.time, [0, 123]);
|
assert.deepStrictEqual(event.time, [0, 123]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should record an exception with provided time as a 3rd arg', () => {
|
||||||
|
const span = new Span(
|
||||||
|
tracer,
|
||||||
|
ROOT_CONTEXT,
|
||||||
|
name,
|
||||||
|
spanContext,
|
||||||
|
SpanKind.CLIENT
|
||||||
|
);
|
||||||
|
// @ts-expect-error writing readonly property. performance time origin is mocked to return ms value of [1,1]
|
||||||
|
span['_performanceOffset'] = 0;
|
||||||
|
assert.strictEqual(span.events.length, 0);
|
||||||
|
span.recordException('boom', undefined, [0, 123]);
|
||||||
|
const event = span.events[0];
|
||||||
|
assert.deepStrictEqual(event.time, [0, 123]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when attributes are provided', () => {
|
||||||
|
it('should sanitized and merge attributes when provided', () => {
|
||||||
|
const span = new Span(
|
||||||
|
tracer,
|
||||||
|
ROOT_CONTEXT,
|
||||||
|
name,
|
||||||
|
spanContext,
|
||||||
|
SpanKind.CLIENT
|
||||||
|
);
|
||||||
|
// @ts-expect-error writing readonly property. performance time origin is mocked to return ms value of [1,1]
|
||||||
|
span['_performanceOffset'] = 0;
|
||||||
|
assert.strictEqual(span.events.length, 0);
|
||||||
|
const exception = { code: 'Error', message: 'boom', stack: 'bar' };
|
||||||
|
span.recordException(exception, {
|
||||||
|
...validAttributes,
|
||||||
|
...invalidAttributes,
|
||||||
|
} as unknown as SpanAttributes);
|
||||||
|
const event = span.events[0];
|
||||||
|
assert.deepStrictEqual(event.attributes, {
|
||||||
|
[SemanticAttributes.EXCEPTION_TYPE]: 'Error',
|
||||||
|
[SemanticAttributes.EXCEPTION_MESSAGE]: 'boom',
|
||||||
|
[SemanticAttributes.EXCEPTION_STACKTRACE]: 'bar',
|
||||||
|
...validAttributes,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prioritize the provided attributes over generated', () => {
|
||||||
|
const span = new Span(
|
||||||
|
tracer,
|
||||||
|
ROOT_CONTEXT,
|
||||||
|
name,
|
||||||
|
spanContext,
|
||||||
|
SpanKind.CLIENT
|
||||||
|
);
|
||||||
|
// @ts-expect-error writing readonly property. performance time origin is mocked to return ms value of [1,1]
|
||||||
|
span['_performanceOffset'] = 0;
|
||||||
|
assert.strictEqual(span.events.length, 0);
|
||||||
|
const exception = { code: 'Error', message: 'boom', stack: 'bar' };
|
||||||
|
span.recordException(exception, {
|
||||||
|
[SemanticAttributes.EXCEPTION_TYPE]: 'OverrideError',
|
||||||
|
[SemanticAttributes.EXCEPTION_MESSAGE]: 'override-boom',
|
||||||
|
[SemanticAttributes.EXCEPTION_STACKTRACE]: 'override-bar',
|
||||||
|
...validAttributes,
|
||||||
|
...invalidAttributes,
|
||||||
|
} as unknown as SpanAttributes);
|
||||||
|
const event = span.events[0];
|
||||||
|
assert.deepStrictEqual(event.attributes, {
|
||||||
|
...validAttributes,
|
||||||
|
[SemanticAttributes.EXCEPTION_TYPE]: 'OverrideError',
|
||||||
|
[SemanticAttributes.EXCEPTION_MESSAGE]: 'override-boom',
|
||||||
|
[SemanticAttributes.EXCEPTION_STACKTRACE]: 'override-bar',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when exception code is numeric', () => {
|
describe('when exception code is numeric', () => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue