Skip to content

Commit f1be9ff

Browse files
committed
feat: log exceptions for the logging hook
Signed-off-by: Lukas Reining <[email protected]>
1 parent 5af9edb commit f1be9ff

File tree

2 files changed

+45
-9
lines changed

2 files changed

+45
-9
lines changed

libs/hooks/open-telemetry/src/lib/otel-hook.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export type OpenTelemetryHookOptions = {
3737
* will not be recorded on the active span.
3838
* By default, exceptions are recorded on the active span, if there is one.
3939
*/
40-
excludeExceptionsFromTrace?: boolean;
40+
excludeExceptions?: boolean;
4141

4242
/**
4343
* Takes a telemetry event and returns a telemetry event.
@@ -54,7 +54,7 @@ export abstract class OpenTelemetryHook {
5454
protected abstract name: string;
5555

5656
protected attributesToExclude: TelemetryAttributesNames[];
57-
protected excludeExceptionsFromTrace: boolean;
57+
protected excludeExceptions: boolean;
5858
protected safeAttributeMapper: AttributeMapper;
5959
protected safeEventMutator: EventMutator;
6060

@@ -76,7 +76,7 @@ export abstract class OpenTelemetryHook {
7676
}
7777
};
7878
this.attributesToExclude = options?.excludeAttributes ?? [];
79-
this.excludeExceptionsFromTrace = options?.excludeExceptionsFromTrace ?? false;
79+
this.excludeExceptions = options?.excludeExceptions ?? false;
8080
}
8181

8282
protected toEvaluationEvent(

libs/hooks/open-telemetry/src/lib/traces/tracing-hook.ts

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import type { BaseHook, HookContext, EvaluationDetails, FlagValue, Logger } from '@openfeature/core';
2-
import type { Span } from '@opentelemetry/api';
2+
import type { Attributes, Exception, Span } from '@opentelemetry/api';
33
import { trace } from '@opentelemetry/api';
4-
import type { EventLogger } from '@opentelemetry/api-events';
4+
import type { EventLogger, Event } from '@opentelemetry/api-events';
55
import { events } from '@opentelemetry/api-events';
6+
import {
7+
ATTR_EXCEPTION_MESSAGE,
8+
ATTR_EXCEPTION_STACKTRACE,
9+
ATTR_EXCEPTION_TYPE,
10+
} from '@opentelemetry/semantic-conventions';
611
import type { OpenTelemetryHookOptions } from '../otel-hook';
712
import { OpenTelemetryHook } from '../otel-hook';
813

@@ -27,10 +32,41 @@ export class EventHook extends OpenTelemetryHook implements BaseHook {
2732
}
2833

2934
error(_: HookContext, err: Error) {
30-
if (!this.excludeExceptionsFromTrace) {
31-
trace.getActiveSpan()?.recordException(err);
35+
if (!this.excludeExceptions) {
36+
this.eventLogger.emit(this.toExceptionLogEvent(err));
3237
}
3338
}
39+
40+
/**
41+
* Converts an exception to an OpenTelemetry log event.
42+
* The event is compatible to https://opentelemetry.io/docs/specs/semconv/exceptions/exceptions-logs/
43+
* The mapping code is adapted from the OpenTelemetry JS SDK:
44+
* https://github.com/open-telemetry/opentelemetry-js/blob/09bf31eb966bab627e76a6c5c05c6e51ccd2f387/packages/opentelemetry-sdk-trace-base/src/Span.ts#L330
45+
* @private
46+
*/
47+
private toExceptionLogEvent(exception: Exception): Event {
48+
const attributes: Attributes = {};
49+
if (typeof exception === 'string') {
50+
attributes[ATTR_EXCEPTION_MESSAGE] = exception;
51+
} else if (exception) {
52+
if (exception.code) {
53+
attributes[ATTR_EXCEPTION_TYPE] = exception.code.toString();
54+
} else if (exception.name) {
55+
attributes[ATTR_EXCEPTION_TYPE] = exception.name;
56+
}
57+
if (exception.message) {
58+
attributes[ATTR_EXCEPTION_MESSAGE] = exception.message;
59+
}
60+
if (exception.stack) {
61+
attributes[ATTR_EXCEPTION_STACKTRACE] = exception.stack;
62+
}
63+
}
64+
65+
return {
66+
name: 'exception',
67+
attributes,
68+
};
69+
}
3470
}
3571

3672
/**
@@ -58,7 +94,7 @@ export class SpanEventHook extends OpenTelemetryHook implements BaseHook {
5894
}
5995

6096
error(_: HookContext, err: Error) {
61-
if (!this.excludeExceptionsFromTrace) {
97+
if (!this.excludeExceptions) {
6298
trace.getActiveSpan()?.recordException(err);
6399
}
64100
}
@@ -105,7 +141,7 @@ export class SpanHook extends OpenTelemetryHook implements BaseHook {
105141
}
106142

107143
error(hookContext: Readonly<HookContext<FlagValue, SpanAttributesTracingHookData>>, err: Error) {
108-
if (!this.excludeExceptionsFromTrace) {
144+
if (!this.excludeExceptions) {
109145
const currentSpan = hookContext.hookData.get(HookContextSpanKey) ?? trace.getActiveSpan();
110146
currentSpan?.recordException(err);
111147
}

0 commit comments

Comments
 (0)