Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/core/src/shared-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export {
} from './utils/request';
export type { MaxRequestBodySize } from './utils/request';
export { DEFAULT_ENVIRONMENT, DEV_ENVIRONMENT } from './constants';
export { SPAN_KIND } from './spanKind';
export { SPAN_KIND, spanKindToName } from './spanKind';
export type { SpanKindValue } from './spanKind';
export { addBreadcrumb } from './breadcrumbs';
export { functionToStringIntegration } from './integrations/functiontostring';
Expand Down
19 changes: 19 additions & 0 deletions packages/core/src/spanKind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,22 @@ export const SPAN_KIND = {
} as const;

export type SpanKindValue = (typeof SPAN_KIND)[keyof typeof SPAN_KIND];

// Reverse of SPAN_KIND (value → name), for the `otel.kind` attribute. The numeric keys come from
// SPAN_KIND so they stay in sync; `satisfies` ensures every kind has a name.
const SPAN_KIND_NAME = {
[SPAN_KIND.INTERNAL]: 'INTERNAL',
[SPAN_KIND.SERVER]: 'SERVER',
[SPAN_KIND.CLIENT]: 'CLIENT',
[SPAN_KIND.PRODUCER]: 'PRODUCER',
[SPAN_KIND.CONSUMER]: 'CONSUMER',
} as const satisfies Record<SpanKindValue, string>;

/**
* Resolve the string name of a span kind value (e.g. `1` → `'SERVER'`), mirroring the reverse
* mapping of OpenTelemetry's `SpanKind` enum. Used for the `otel.kind` span attribute, so SDK
* code doesn't need to import `@opentelemetry/api` just for that reverse lookup.
*/
export function spanKindToName(kind: number): (typeof SPAN_KIND_NAME)[SpanKindValue] | undefined {
return SPAN_KIND_NAME[kind as SpanKindValue];
}
16 changes: 16 additions & 0 deletions packages/core/test/lib/spanKind.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { describe, expect, it } from 'vitest';
import { SPAN_KIND, spanKindToName } from '../../src/spanKind';

describe('spanKindToName', () => {
it('resolves each span kind value to its name', () => {
expect(spanKindToName(SPAN_KIND.INTERNAL)).toBe('INTERNAL');
expect(spanKindToName(SPAN_KIND.SERVER)).toBe('SERVER');
expect(spanKindToName(SPAN_KIND.CLIENT)).toBe('CLIENT');
expect(spanKindToName(SPAN_KIND.PRODUCER)).toBe('PRODUCER');
expect(spanKindToName(SPAN_KIND.CONSUMER)).toBe('CONSUMER');
});

it('returns undefined for an unknown kind value', () => {
expect(spanKindToName(99)).toBeUndefined();
});
});
10 changes: 6 additions & 4 deletions packages/opentelemetry/src/spanProcessor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Context } from '@opentelemetry/api';
import { ROOT_CONTEXT, SpanKind, trace } from '@opentelemetry/api';
import { ROOT_CONTEXT, trace } from '@opentelemetry/api';
import type { ReadableSpan, Span, SpanProcessor as SpanProcessorInterface } from '@opentelemetry/sdk-trace-base';
import type { Client, SpanAttributes, StreamedSpanJSON } from '@sentry/core';
import {
Expand All @@ -14,6 +14,8 @@ import {
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,
setCapturedScopesOnSpan,
SPAN_KIND,
spanKindToName,
} from '@sentry/core';
import { SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE } from './semanticAttributes';
import { SentrySpanExporter } from './spanExporter';
Expand Down Expand Up @@ -121,7 +123,7 @@ function backfillStreamedSpanDataFromOtel(spanJSON: StreamedSpanJSON, hint?: { s
return;
}

const kind = hint?.spanKind ?? SpanKind.INTERNAL;
const kind = hint?.spanKind ?? SPAN_KIND.INTERNAL;
const { op, description, source, data } = inferSpanData(spanJSON.name, attributes as unknown as SpanAttributes, kind);

spanJSON.name = description;
Expand All @@ -132,9 +134,9 @@ function backfillStreamedSpanDataFromOtel(spanJSON: StreamedSpanJSON, hint?: { s
...data,
});

if (kind !== SpanKind.INTERNAL) {
if (kind !== SPAN_KIND.INTERNAL) {
safeSetSpanJSONAttributes(spanJSON, {
'otel.kind': SpanKind[kind],
'otel.kind': spanKindToName(kind),
Comment thread
andreiborza marked this conversation as resolved.
});
}
}
Loading