diff --git a/packages/core/src/integrations/http/server-subscription.ts b/packages/core/src/integrations/http/server-subscription.ts index e5b37d3d04b2..86d7359aa119 100644 --- a/packages/core/src/integrations/http/server-subscription.ts +++ b/packages/core/src/integrations/http/server-subscription.ts @@ -37,6 +37,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, } from '../../semanticAttributes'; import { safeMathRandom } from '../../utils/randomSafeContext'; +import { SPAN_KIND } from '../../spanKind'; import type { SpanAttributes } from '../../types/span'; import type { SpanStatus } from '../../types/spanStatus'; @@ -277,10 +278,9 @@ function buildServerSpanWrap( return startSpanManual( { name, - // SpanKind.SERVER = 1; pass this so the OTel sampler infers - // op='http.server' rather than 'http', which it does for - // SpanKind.INTERNAL = 0, the default - kind: 1, + // Pass SERVER so the OTel sampler infers op='http.server' rather than + // 'http', which it does for the INTERNAL default. + kind: SPAN_KIND.SERVER, attributes: { // Sentry-specific attributes [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server', diff --git a/packages/core/src/shared-exports.ts b/packages/core/src/shared-exports.ts index e2160c9e14d9..824f8c0873d3 100644 --- a/packages/core/src/shared-exports.ts +++ b/packages/core/src/shared-exports.ts @@ -124,6 +124,8 @@ export { } from './utils/request'; export type { MaxRequestBodySize } from './utils/request'; export { DEFAULT_ENVIRONMENT, DEV_ENVIRONMENT } from './constants'; +export { SPAN_KIND } from './spanKind'; +export type { SpanKindValue } from './spanKind'; export { addBreadcrumb } from './breadcrumbs'; export { functionToStringIntegration } from './integrations/functiontostring'; // eslint-disable-next-line typescript/no-deprecated diff --git a/packages/core/src/spanKind.ts b/packages/core/src/spanKind.ts new file mode 100644 index 000000000000..3127d9205a9b --- /dev/null +++ b/packages/core/src/spanKind.ts @@ -0,0 +1,17 @@ +/** + * The kind of a span, mirroring OpenTelemetry's `SpanKind` enum values. + * + * Exported as a plain const object so SDK code can set a span's kind without + * importing `@opentelemetry/api` just for the enum. The numeric values must + * stay in sync with OpenTelemetry's `SpanKind` since they are passed through to + * the underlying OTel span and sampler. + */ +export const SPAN_KIND = { + INTERNAL: 0, + SERVER: 1, + CLIENT: 2, + PRODUCER: 3, + CONSUMER: 4, +} as const; + +export type SpanKindValue = (typeof SPAN_KIND)[keyof typeof SPAN_KIND]; diff --git a/packages/core/src/types/startSpanOptions.ts b/packages/core/src/types/startSpanOptions.ts index ba184152e486..391a4354722d 100644 --- a/packages/core/src/types/startSpanOptions.ts +++ b/packages/core/src/types/startSpanOptions.ts @@ -1,4 +1,5 @@ import type { Scope } from '../scope'; +import type { SpanKindValue } from '../spanKind'; import type { SpanLink } from './link'; import type { Span, SpanAttributes, SpanTimeInput } from './span'; @@ -40,7 +41,7 @@ export interface StartSpanOptions { * span kind on the underlying OTel span, which affects how the span is * displayed and sampled. */ - kind?: 0 | 1 | 2 | 3 | 4; + kind?: SpanKindValue; /** * If provided, make the new span a child of this span. diff --git a/packages/node/src/integrations/node-fetch/vendored/undici.ts b/packages/node/src/integrations/node-fetch/vendored/undici.ts index 10d6c568cb71..814613921a20 100644 --- a/packages/node/src/integrations/node-fetch/vendored/undici.ts +++ b/packages/node/src/integrations/node-fetch/vendored/undici.ts @@ -23,6 +23,7 @@ import { getTraceData, LRUMap, shouldPropagateTraceForUrl, + SPAN_KIND, SPAN_STATUS_ERROR, startInactiveSpan, withActiveSpan, @@ -53,9 +54,6 @@ import type { } from './internal-types'; import type { UndiciInstrumentationConfig, UndiciRequest } from './types'; -// `SpanKind.CLIENT`, inlined to avoid importing from `@opentelemetry/api`. -const SPAN_KIND_CLIENT = 2; - /** Replaces OTel's `safeExecuteInTheMiddle`: run `fn`, route any error to `onError`, and swallow it. */ function safeExecute(fn: () => T, onError: (error: unknown) => void): T | undefined { try { @@ -246,7 +244,7 @@ export class UndiciInstrumentation { const span = startInactiveSpan({ name: requestMethod === '_OTHER' ? 'HTTP' : requestMethod, - kind: SPAN_KIND_CLIENT, + kind: SPAN_KIND.CLIENT, attributes, }); diff --git a/packages/node/src/integrations/tracing/dataloader/vendored/instrumentation.ts b/packages/node/src/integrations/tracing/dataloader/vendored/instrumentation.ts index 8fee30f4d41f..4412510a1906 100644 --- a/packages/node/src/integrations/tracing/dataloader/vendored/instrumentation.ts +++ b/packages/node/src/integrations/tracing/dataloader/vendored/instrumentation.ts @@ -9,9 +9,14 @@ */ import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; -import { SpanKind } from '@opentelemetry/api'; import type { BatchLoadFn, DataLoader, DataLoaderConstructor } from './types'; -import { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core'; +import { + SDK_VERSION, + SEMANTIC_ATTRIBUTE_SENTRY_OP, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SPAN_KIND, + startSpan, +} from '@sentry/core'; const MODULE_NAME = 'dataloader'; const PACKAGE_NAME = '@sentry/instrumentation-dataloader'; @@ -152,7 +157,7 @@ export class DataloaderInstrumentation extends InstrumentationBase { return startSpan( { name: getSpanName(this, 'load'), - kind: SpanKind.CLIENT, + kind: SPAN_KIND.CLIENT, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, [SEMANTIC_ATTRIBUTE_SENTRY_OP]: getSpanOp('load'), @@ -190,7 +195,7 @@ export class DataloaderInstrumentation extends InstrumentationBase { return startSpan( { name: getSpanName(this, 'loadMany'), - kind: SpanKind.CLIENT, + kind: SPAN_KIND.CLIENT, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, [SEMANTIC_ATTRIBUTE_SENTRY_OP]: getSpanOp('loadMany'), @@ -216,7 +221,7 @@ export class DataloaderInstrumentation extends InstrumentationBase { return startSpan( { name: getSpanName(this, 'prime'), - kind: SpanKind.CLIENT, + kind: SPAN_KIND.CLIENT, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, [SEMANTIC_ATTRIBUTE_SENTRY_OP]: getSpanOp('prime'), @@ -242,7 +247,7 @@ export class DataloaderInstrumentation extends InstrumentationBase { return startSpan( { name: getSpanName(this, 'clear'), - kind: SpanKind.CLIENT, + kind: SPAN_KIND.CLIENT, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, [SEMANTIC_ATTRIBUTE_SENTRY_OP]: getSpanOp('clear'), @@ -268,7 +273,7 @@ export class DataloaderInstrumentation extends InstrumentationBase { return startSpan( { name: getSpanName(this, 'clearAll'), - kind: SpanKind.CLIENT, + kind: SPAN_KIND.CLIENT, attributes: { [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, [SEMANTIC_ATTRIBUTE_SENTRY_OP]: getSpanOp('clearAll'), diff --git a/packages/node/src/integrations/tracing/kafka/vendored/utils.ts b/packages/node/src/integrations/tracing/kafka/vendored/utils.ts index 9514856decb6..2e785bd3fc66 100644 --- a/packages/node/src/integrations/tracing/kafka/vendored/utils.ts +++ b/packages/node/src/integrations/tracing/kafka/vendored/utils.ts @@ -8,12 +8,13 @@ * - Span creation extracted here and migrated to the @sentry/core API; origin folded into span creation */ -import { SpanKind, TraceFlags } from '@opentelemetry/api'; +import { TraceFlags } from '@opentelemetry/api'; import type { Span, SpanAttributes, SpanLink } from '@sentry/core'; import { getTraceData, propagationContextFromHeaders, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SPAN_KIND, SPAN_STATUS_ERROR, startInactiveSpan, } from '@sentry/core'; @@ -96,7 +97,7 @@ export function startConsumerSpan({ topic, message, operationType, links, attrib return startInactiveSpan({ name: `${operationName} ${topic}`, - kind: operationType === MESSAGING_OPERATION_TYPE_VALUE_RECEIVE ? SpanKind.CLIENT : SpanKind.CONSUMER, + kind: operationType === MESSAGING_OPERATION_TYPE_VALUE_RECEIVE ? SPAN_KIND.CLIENT : SPAN_KIND.CONSUMER, links, attributes: { ...attributes, @@ -118,7 +119,7 @@ export function startConsumerSpan({ topic, message, operationType, links, attrib export function startProducerSpan(topic: string, message: Message): Span { const span = startInactiveSpan({ name: `send ${topic}`, - kind: SpanKind.PRODUCER, + kind: SPAN_KIND.PRODUCER, attributes: { [ATTR_MESSAGING_SYSTEM]: MESSAGING_SYSTEM_VALUE_KAFKA, [ATTR_MESSAGING_DESTINATION_NAME]: topic, diff --git a/packages/node/src/integrations/tracing/knex/vendored/instrumentation.ts b/packages/node/src/integrations/tracing/knex/vendored/instrumentation.ts index ae737a49fc50..2acd863b7838 100644 --- a/packages/node/src/integrations/tracing/knex/vendored/instrumentation.ts +++ b/packages/node/src/integrations/tracing/knex/vendored/instrumentation.ts @@ -11,7 +11,6 @@ /* oxlint-disable typescript/no-deprecated */ -import { SpanKind } from '@opentelemetry/api'; import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; import type { Span, SpanAttributes } from '@sentry/core'; @@ -19,6 +18,7 @@ import { getActiveSpan, SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SPAN_KIND, SPAN_STATUS_ERROR, startSpan, } from '@sentry/core'; @@ -143,7 +143,7 @@ export class KnexInstrumentation extends InstrumentationBase | undefined; diff --git a/packages/node/src/integrations/tracing/redis/vendored/redis-instrumentation.ts b/packages/node/src/integrations/tracing/redis/vendored/redis-instrumentation.ts index af284cee107c..50ced61861fc 100644 --- a/packages/node/src/integrations/tracing/redis/vendored/redis-instrumentation.ts +++ b/packages/node/src/integrations/tracing/redis/vendored/redis-instrumentation.ts @@ -9,7 +9,6 @@ * - Refactored to use Sentry's span APIs instead of OpenTelemetry tracing APIs */ -import { SpanKind } from '@opentelemetry/api'; import type { TracerProvider } from '@opentelemetry/api'; import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; import type { Span, SpanAttributes } from '@sentry/core'; @@ -18,6 +17,7 @@ import { getActiveSpan, SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SPAN_KIND, SPAN_STATUS_ERROR, startInactiveSpan, withActiveSpan, @@ -179,7 +179,7 @@ class RedisInstrumentationV2_V3 extends InstrumentationBase original.apply(this)); @@ -448,7 +448,7 @@ class RedisInstrumentationV4_V5 extends InstrumentationBase origFunction.apply(origThis, origArguments)); diff --git a/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts b/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts index dc226ab5bbf7..e201a430bec2 100644 --- a/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts +++ b/packages/node/src/integrations/tracing/tedious/vendored/instrumentation.ts @@ -9,7 +9,6 @@ * - Span creation migrated to the @sentry/core API; origin folded into span creation */ -import * as api from '@opentelemetry/api'; import { EventEmitter } from 'events'; import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; import { InstrumentationBase, InstrumentationNodeModuleDefinition, isWrapped } from '@opentelemetry/instrumentation'; @@ -25,9 +24,11 @@ import { } from './semconv'; import type * as tedious from './tedious-types'; import { getSpanName, once } from './utils'; +import type { SpanAttributes } from '@sentry/core'; import { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SPAN_KIND, SPAN_STATUS_ERROR, startInactiveSpan, withActiveSpan, @@ -136,7 +137,7 @@ export class TediousInstrumentation extends InstrumentationBase