Skip to content

Commit ba9bd08

Browse files
committed
ref(core): Ensure error span status is always valid
1 parent fb0329c commit ba9bd08

6 files changed

Lines changed: 40 additions & 29 deletions

File tree

packages/core/src/tracing/index.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,14 @@ export { startIdleSpan, TRACING_DEFAULTS } from './idleSpan';
1313
export { SentrySpan } from './sentrySpan';
1414
export { _INTERNAL_setDeferSegmentSpanCapture } from './deferSegmentSpanCapture';
1515
export { SentryNonRecordingSpan } from './sentryNonRecordingSpan';
16-
export { setHttpStatus, getSpanStatusFromHttpCode } from './spanstatus';
17-
export { SPAN_STATUS_ERROR, SPAN_STATUS_OK, SPAN_STATUS_UNSET } from './spanstatus';
16+
export {
17+
setHttpStatus,
18+
getSpanStatusFromHttpCode,
19+
isStatusErrorMessageValid,
20+
SPAN_STATUS_ERROR,
21+
SPAN_STATUS_OK,
22+
SPAN_STATUS_UNSET,
23+
} from './spanstatus';
1824
export {
1925
startSpan,
2026
startInactiveSpan,

packages/core/src/tracing/spanstatus.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import type { Span } from '../types/span';
2-
import type { SpanStatus } from '../types/spanStatus';
2+
import type { SpanStatusType } from '../types/spanStatus';
3+
import { SPAN_STATUS_TYPES, type SpanStatus } from '../types/spanStatus';
34

45
export const SPAN_STATUS_UNSET = 0;
56
export const SPAN_STATUS_OK = 1;
67
export const SPAN_STATUS_ERROR = 2;
78

9+
export function isStatusErrorMessageValid(message: string): boolean {
10+
return SPAN_STATUS_TYPES.includes(message as SpanStatusType);
11+
}
12+
813
/**
914
* Converts a HTTP status code into a sentry status with a message.
1015
*

packages/core/src/types/spanStatus.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
1-
export type SpanStatusType =
1+
export const SPAN_STATUS_TYPES = [
22
/** The operation completed successfully. */
3-
| 'ok'
3+
'ok',
44
/** Deadline expired before operation could complete. */
5-
| 'deadline_exceeded'
5+
'deadline_exceeded',
66
/** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */
7-
| 'unauthenticated'
7+
'unauthenticated',
88
/** 403 Forbidden */
9-
| 'permission_denied'
9+
'permission_denied',
1010
/** 404 Not Found. Some requested entity (file or directory) was not found. */
11-
| 'not_found'
11+
'not_found',
1212
/** 429 Too Many Requests */
13-
| 'resource_exhausted'
13+
'resource_exhausted',
1414
/** Client specified an invalid argument. 4xx. */
15-
| 'invalid_argument'
15+
'invalid_argument',
1616
/** 501 Not Implemented */
17-
| 'unimplemented'
17+
'unimplemented',
1818
/** 503 Service Unavailable */
19-
| 'unavailable'
19+
'unavailable',
2020
/** Other/generic 5xx. */
21-
| 'internal_error'
21+
'internal_error',
2222
/** Unknown. Any non-standard HTTP status code. */
23-
| 'unknown_error'
23+
'unknown_error',
2424
/** The operation was cancelled (typically by the user). */
25-
| 'cancelled'
25+
'cancelled',
2626
/** Already exists (409) */
27-
| 'already_exists'
27+
'already_exists',
2828
/** Operation was rejected because the system is not in a state required for the operation's */
29-
| 'failed_precondition'
29+
'failed_precondition',
3030
/** The operation was aborted, typically due to a concurrency issue. */
31-
| 'aborted'
31+
'aborted',
3232
/** Operation was attempted past the valid range. */
33-
| 'out_of_range'
33+
'out_of_range',
3434
/** Unrecoverable data loss or corruption */
35-
| 'data_loss';
35+
'data_loss',
36+
] as const;
37+
38+
export type SpanStatusType = (typeof SPAN_STATUS_TYPES)[number];
3639

3740
// These are aligned with OpenTelemetry span status codes
3841
const SPAN_STATUS_UNSET = 0;

packages/core/src/utils/spanUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
SEMANTIC_ATTRIBUTE_SENTRY_STATUS_MESSAGE,
1313
} from '../semanticAttributes';
1414
import type { SentrySpan } from '../tracing/sentrySpan';
15-
import { SPAN_STATUS_OK, SPAN_STATUS_UNSET } from '../tracing/spanstatus';
15+
import { isStatusErrorMessageValid, SPAN_STATUS_OK, SPAN_STATUS_UNSET } from '../tracing/spanstatus';
1616
import { getCapturedScopesOnSpan } from '../tracing/utils';
1717
import type { TraceContext } from '../types/context';
1818
import type { SpanLink, SpanLinkJSON } from '../types/link';
@@ -326,7 +326,7 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
326326
return 'ok';
327327
}
328328

329-
return status.message || 'internal_error';
329+
return status.message && isStatusErrorMessageValid(status.message) ? status.message : 'internal_error';
330330
}
331331

332332
/**

packages/opentelemetry/src/applyOtelSpanData.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@ import {
1212
spanToJSON,
1313
SPAN_STATUS_ERROR,
1414
SPAN_STATUS_OK,
15+
isStatusErrorMessageValid,
1516
} from '@sentry/core';
1617
import type { Span, SpanAttributes } from '@sentry/core';
17-
import { inferStatusFromAttributes, isStatusErrorMessageValid } from './utils/mapStatus';
18+
import { inferStatusFromAttributes } from './utils/mapStatus';
1819
import { inferSpanData } from './utils/parseSpanDescription';
1920

2021
type SentrySpanWithOtelKind = Span & { kind?: SpanKind };

packages/opentelemetry/src/utils/mapStatus.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SpanStatusCode } from '@opentelemetry/api';
22
import { HTTP_RESPONSE_STATUS_CODE, HTTP_STATUS_CODE, RPC_GRPC_STATUS_CODE } from '@sentry/conventions/attributes';
33
import type { SpanAttributes, SpanStatus } from '@sentry/core';
4-
import { getSpanStatusFromHttpCode, SPAN_STATUS_ERROR, SPAN_STATUS_OK } from '@sentry/core';
4+
import { getSpanStatusFromHttpCode, isStatusErrorMessageValid, SPAN_STATUS_ERROR, SPAN_STATUS_OK } from '@sentry/core';
55
import type { AbstractSpan } from '../types';
66
import { spanHasAttributes, spanHasStatus } from './spanTypes';
77

@@ -25,10 +25,6 @@ const canonicalGrpcErrorCodesMap: Record<string, SpanStatus['message']> = {
2525
'16': 'unauthenticated',
2626
} as const;
2727

28-
export const isStatusErrorMessageValid = (message: string): boolean => {
29-
return Object.values(canonicalGrpcErrorCodesMap).includes(message as SpanStatus['message']);
30-
};
31-
3228
/**
3329
* Get a Sentry span status from an otel span.
3430
*/

0 commit comments

Comments
 (0)