Skip to content

Commit

Permalink
feat(core): Deprecate span.toTraceparent() in favor of `spanToTrace…
Browse files Browse the repository at this point in the history
…Header()` util (#10031)

Instead, there is a new util `spanToTraceHeader(span)` which can be
used. This is done to align the Span schema with OpenTelemetry.

Open question: Do we need to re-export this from all our packages, so
users can also use this directly?
  • Loading branch information
mydea authored and anonrig committed Jan 3, 2024
1 parent e89df35 commit ddf1132
Show file tree
Hide file tree
Showing 22 changed files with 89 additions and 30 deletions.
1 change: 1 addition & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ In v8, the Span class is heavily reworked. The following properties & methods ar
* `span.toContext()`: Access the fields directly instead.
* `span.updateWithContext(newSpanContext)`: Update the fields directly instead.
* `span.setName(newName)`: Use `span.updateName(newName)` instead.
* `span.toTraceparent()`: use `spanToTraceHeader(span)` util instead.

## Deprecate `pushScope` & `popScope` in favor of `withScope`

Expand Down
4 changes: 2 additions & 2 deletions packages/astro/src/server/meta.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getDynamicSamplingContextFromClient } from '@sentry/core';
import { getDynamicSamplingContextFromClient, spanToTraceHeader } from '@sentry/core';
import type { Client, Scope, Span } from '@sentry/types';
import {
TRACEPARENT_REGEXP,
Expand Down Expand Up @@ -30,7 +30,7 @@ export function getTracingMetaTags(
const { dsc, sampled, traceId } = scope.getPropagationContext();
const transaction = span?.transaction;

const sentryTrace = span ? span.toTraceparent() : generateSentryTraceHeader(traceId, undefined, sampled);
const sentryTrace = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, undefined, sampled);

const dynamicSamplingContext = transaction
? transaction.getDynamicSamplingContext()
Expand Down
12 changes: 9 additions & 3 deletions packages/astro/test/server/meta.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { vi } from 'vitest';
import { getTracingMetaTags, isValidBaggageString } from '../../src/server/meta';

const mockedSpan = {
toTraceparent: () => '12345678901234567890123456789012-1234567890123456-1',
sampled: true,
traceId: '12345678901234567890123456789012',
spanId: '1234567890123456',
transaction: {
getDynamicSamplingContext: () => ({
environment: 'production',
Expand Down Expand Up @@ -68,7 +70,9 @@ describe('getTracingMetaTags', () => {
const tags = getTracingMetaTags(
// @ts-expect-error - only passing a partial span object
{
toTraceparent: () => '12345678901234567890123456789012-1234567890123456-1',
sampled: true,
traceId: '12345678901234567890123456789012',
spanId: '1234567890123456',
transaction: undefined,
},
mockedScope,
Expand All @@ -89,7 +93,9 @@ describe('getTracingMetaTags', () => {
const tags = getTracingMetaTags(
// @ts-expect-error - only passing a partial span object
{
toTraceparent: () => '12345678901234567890123456789012-1234567890123456-1',
sampled: true,
traceId: '12345678901234567890123456789012',
spanId: '1234567890123456',
transaction: undefined,
},
mockedScope,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export { prepareEvent } from './utils/prepareEvent';
export { createCheckInEnvelope } from './checkin';
export { hasTracingEnabled } from './utils/hasTracingEnabled';
export { isSentryRequestUrl } from './utils/isSentryRequestUrl';
export { spanToTraceHeader } from './utils/spanUtils';
export { DEFAULT_ENVIRONMENT } from './constants';
export { ModuleMetadata } from './integrations/metadata';
export { RequestData } from './integrations/requestdata';
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/tracing/hubextensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { logger } from '@sentry/utils';
import { DEBUG_BUILD } from '../debug-build';
import type { Hub } from '../hub';
import { getMainCarrier } from '../hub';
import { spanToTraceHeader } from '../utils/spanUtils';
import { registerErrorInstrumentation } from './errors';
import { IdleTransaction } from './idletransaction';
import { sampleTransaction } from './sampling';
Expand All @@ -16,7 +17,7 @@ function traceHeaders(this: Hub): { [key: string]: string } {

return span
? {
'sentry-trace': span.toTraceparent(),
'sentry-trace': spanToTraceHeader(span),
}
: {};
}
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/tracing/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import type {
TraceContext,
Transaction,
} from '@sentry/types';
import { dropUndefinedKeys, generateSentryTraceHeader, logger, timestampInSeconds, uuid4 } from '@sentry/utils';
import { dropUndefinedKeys, logger, timestampInSeconds, uuid4 } from '@sentry/utils';

import { DEBUG_BUILD } from '../debug-build';
import { spanToTraceHeader } from '../utils/spanUtils';
import { ensureTimestampInSeconds } from './utils';

/**
Expand Down Expand Up @@ -320,7 +321,7 @@ export class Span implements SpanInterface {
* @inheritDoc
*/
public toTraceparent(): string {
return generateSentryTraceHeader(this.traceId, this.spanId, this.sampled);
return spanToTraceHeader(this);
}

/**
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/utils/spanUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { Span } from '@sentry/types';
import { generateSentryTraceHeader } from '@sentry/utils';

/**
* Convert a Span to a Sentry trace header.
*/
export function spanToTraceHeader(span: Span): string {
return generateSentryTraceHeader(span.traceId, span.spanId, span.sampled);
}
13 changes: 13 additions & 0 deletions packages/core/test/lib/utils/spanUtils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { TRACEPARENT_REGEXP } from '@sentry/utils';
import { Span, spanToTraceHeader } from '../../../src';

describe('spanToTraceHeader', () => {
test('simple', () => {
const span = new Span();
expect(spanToTraceHeader(span)).toMatch(TRACEPARENT_REGEXP);
});
test('with sample', () => {
const span = new Span({ sampled: true });
expect(spanToTraceHeader(span)).toMatch(TRACEPARENT_REGEXP);
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addTracingExtensions, getClient, getCurrentScope } from '@sentry/core';
import { addTracingExtensions, getClient, getCurrentScope, spanToTraceHeader } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type App from 'next/app';

Expand Down Expand Up @@ -63,7 +63,7 @@ export function wrapAppGetInitialPropsWithSentry(origAppGetInitialProps: AppGetI
}

if (requestTransaction) {
appGetInitialProps.pageProps._sentryTraceData = requestTransaction.toTraceparent();
appGetInitialProps.pageProps._sentryTraceData = spanToTraceHeader(requestTransaction);

const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
appGetInitialProps.pageProps._sentryBaggage =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addTracingExtensions, getClient, getCurrentScope } from '@sentry/core';
import { addTracingExtensions, getClient, getCurrentScope, spanToTraceHeader } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type { NextPageContext } from 'next';
import type { ErrorProps } from 'next/error';
Expand Down Expand Up @@ -55,7 +55,7 @@ export function wrapErrorGetInitialPropsWithSentry(

const requestTransaction = getTransactionFromRequest(req) ?? getCurrentScope().getTransaction();
if (requestTransaction) {
errorGetInitialProps._sentryTraceData = requestTransaction.toTraceparent();
errorGetInitialProps._sentryTraceData = spanToTraceHeader(requestTransaction);

const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
errorGetInitialProps._sentryBaggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
Expand Down
4 changes: 2 additions & 2 deletions packages/nextjs/src/common/wrapGetInitialPropsWithSentry.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addTracingExtensions, getClient, getCurrentScope } from '@sentry/core';
import { addTracingExtensions, getClient, getCurrentScope, spanToTraceHeader } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type { NextPage } from 'next';

Expand Down Expand Up @@ -51,7 +51,7 @@ export function wrapGetInitialPropsWithSentry(origGetInitialProps: GetInitialPro

const requestTransaction = getTransactionFromRequest(req) ?? getCurrentScope().getTransaction();
if (requestTransaction) {
initialProps._sentryTraceData = requestTransaction.toTraceparent();
initialProps._sentryTraceData = spanToTraceHeader(requestTransaction);

const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
initialProps._sentryBaggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { addTracingExtensions, getClient, getCurrentScope } from '@sentry/core';
import { addTracingExtensions, getClient, getCurrentScope, spanToTraceHeader } from '@sentry/core';
import { dynamicSamplingContextToSentryBaggageHeader } from '@sentry/utils';
import type { GetServerSideProps } from 'next';

Expand Down Expand Up @@ -48,7 +48,7 @@ export function wrapGetServerSidePropsWithSentry(
if (serverSideProps && 'props' in serverSideProps) {
const requestTransaction = getTransactionFromRequest(req) ?? getCurrentScope().getTransaction();
if (requestTransaction) {
serverSideProps.props._sentryTraceData = requestTransaction.toTraceparent();
serverSideProps.props._sentryTraceData = spanToTraceHeader(requestTransaction);

const dynamicSamplingContext = requestTransaction.getDynamicSamplingContext();
serverSideProps.props._sentryBaggage = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
Expand Down
3 changes: 2 additions & 1 deletion packages/node/src/integrations/hapi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
convertIntegrationFnToClass,
getActiveTransaction,
getCurrentScope,
spanToTraceHeader,
startTransaction,
} from '@sentry/core';
import type { IntegrationFn } from '@sentry/types';
Expand Down Expand Up @@ -93,7 +94,7 @@ export const hapiTracingPlugin = {

if (request.response && isResponseObject(request.response) && transaction) {
const response = request.response as ResponseObject;
response.header('sentry-trace', transaction.toTraceparent());
response.header('sentry-trace', spanToTraceHeader(transaction));

const dynamicSamplingContext = dynamicSamplingContextToSentryBaggageHeader(
transaction.getDynamicSamplingContext(),
Expand Down
3 changes: 2 additions & 1 deletion packages/node/src/integrations/http.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type * as http from 'http';
import type * as https from 'https';
import type { Hub } from '@sentry/core';
import { spanToTraceHeader } from '@sentry/core';
import { addBreadcrumb, getClient, getCurrentScope } from '@sentry/core';
import { getCurrentHub, getDynamicSamplingContextFromClient, isSentryRequestUrl } from '@sentry/core';
import type {
Expand Down Expand Up @@ -260,7 +261,7 @@ function _createWrappedRequestMethodFactory(

if (shouldAttachTraceData(rawRequestUrl)) {
if (requestSpan) {
const sentryTraceHeader = requestSpan.toTraceparent();
const sentryTraceHeader = spanToTraceHeader(requestSpan);
const dynamicSamplingContext = requestSpan?.transaction?.getDynamicSamplingContext();
addHeadersToRequestOptions(requestOptions, requestUrl, sentryTraceHeader, dynamicSamplingContext);
} else {
Expand Down
3 changes: 2 additions & 1 deletion packages/node/src/integrations/undici/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
getCurrentScope,
getDynamicSamplingContextFromClient,
isSentryRequestUrl,
spanToTraceHeader,
} from '@sentry/core';
import type { EventProcessor, Integration, Span } from '@sentry/types';
import {
Expand Down Expand Up @@ -183,7 +184,7 @@ export class Undici implements Integration {
const dynamicSamplingContext = span?.transaction?.getDynamicSamplingContext();
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);

setHeadersOnRequest(request, span.toTraceparent(), sentryBaggageHeader);
setHeadersOnRequest(request, spanToTraceHeader(span), sentryBaggageHeader);
} else {
const { traceId, sampled, dsc } = scope.getPropagationContext();
const sentryTrace = generateSentryTraceHeader(traceId, undefined, sampled);
Expand Down
3 changes: 2 additions & 1 deletion packages/node/test/integrations/undici.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as http from 'http';
import type { Transaction } from '@sentry/core';
import { spanToTraceHeader } from '@sentry/core';
import { Hub, makeMain, runWithAsyncContext } from '@sentry/core';
import type { fetch as FetchType } from 'undici';

Expand Down Expand Up @@ -207,7 +208,7 @@ conditionalTest({ min: 16 })('Undici integration', () => {
expect(transaction.spanRecorder?.spans.length).toBe(2);
const span = transaction.spanRecorder?.spans[1];

expect(requestHeaders['sentry-trace']).toEqual(span?.toTraceparent());
expect(requestHeaders['sentry-trace']).toEqual(spanToTraceHeader(span!));
expect(requestHeaders['baggage']).toEqual(
`sentry-environment=production,sentry-public_key=0,sentry-trace_id=${transaction.traceId},sentry-sample_rate=1,sentry-transaction=test-transaction`,
);
Expand Down
3 changes: 2 additions & 1 deletion packages/opentelemetry-node/src/propagator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Baggage, Context, TextMapGetter, TextMapSetter } from '@opentelemetry/api';
import { TraceFlags, isSpanContextValid, propagation, trace } from '@opentelemetry/api';
import { W3CBaggagePropagator, isTracingSuppressed } from '@opentelemetry/core';
import { spanToTraceHeader } from '@sentry/core';
import {
SENTRY_BAGGAGE_KEY_PREFIX,
baggageHeaderToDynamicSamplingContext,
Expand Down Expand Up @@ -32,7 +33,7 @@ export class SentryPropagator extends W3CBaggagePropagator {

const span = getSentrySpan(spanContext.spanId);
if (span) {
setter.set(carrier, SENTRY_TRACE_HEADER, span.toTraceparent());
setter.set(carrier, SENTRY_TRACE_HEADER, spanToTraceHeader(span));

if (span.transaction) {
const dynamicSamplingContext = span.transaction.getDynamicSamplingContext();
Expand Down
11 changes: 9 additions & 2 deletions packages/remix/src/utils/instrumentServer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
/* eslint-disable max-lines */
import { getActiveTransaction, getClient, getCurrentScope, hasTracingEnabled, runWithAsyncContext } from '@sentry/core';
import {
getActiveTransaction,
getClient,
getCurrentScope,
hasTracingEnabled,
runWithAsyncContext,
spanToTraceHeader,
} from '@sentry/core';
import type { Hub } from '@sentry/node';
import { captureException, getCurrentHub } from '@sentry/node';
import type { Transaction, TransactionSource, WrappedFunction } from '@sentry/types';
Expand Down Expand Up @@ -293,7 +300,7 @@ function getTraceAndBaggage(): {
const dynamicSamplingContext = transaction.getDynamicSamplingContext();

return {
sentryTrace: span.toTraceparent(),
sentryTrace: spanToTraceHeader(span),
sentryBaggage: dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext),
};
}
Expand Down
4 changes: 2 additions & 2 deletions packages/sveltekit/src/server/handle.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getCurrentScope } from '@sentry/core';
import { getCurrentScope, spanToTraceHeader } from '@sentry/core';
import { getActiveTransaction, runWithAsyncContext, startSpan } from '@sentry/core';
import { captureException } from '@sentry/node';
/* eslint-disable @sentry-internal/sdk/no-optional-chaining */
Expand Down Expand Up @@ -97,7 +97,7 @@ export function addSentryCodeToPage(options: SentryHandleOptions): NonNullable<R
return ({ html }) => {
const transaction = getActiveTransaction();
if (transaction) {
const traceparentData = transaction.toTraceparent();
const traceparentData = spanToTraceHeader(transaction);
const dynamicSamplingContext = dynamicSamplingContextToSentryBaggageHeader(
transaction.getDynamicSamplingContext(),
);
Expand Down
10 changes: 8 additions & 2 deletions packages/tracing-internal/src/browser/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
/* eslint-disable max-lines */
import { getClient, getCurrentScope, getDynamicSamplingContextFromClient, hasTracingEnabled } from '@sentry/core';
import {
getClient,
getCurrentScope,
getDynamicSamplingContextFromClient,
hasTracingEnabled,
spanToTraceHeader,
} from '@sentry/core';
import type { HandlerDataXhr, SentryWrappedXMLHttpRequest, Span } from '@sentry/types';
import {
BAGGAGE_HEADER_NAME,
Expand Down Expand Up @@ -291,7 +297,7 @@ export function xhrCallback(
const transaction = span && span.transaction;
const dynamicSamplingContext = transaction && transaction.getDynamicSamplingContext();
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
setHeaderOnXhr(xhr, span.toTraceparent(), sentryBaggageHeader);
setHeaderOnXhr(xhr, spanToTraceHeader(span), sentryBaggageHeader);
} else {
const client = getClient();
const { traceId, sampled, dsc } = scope.getPropagationContext();
Expand Down
10 changes: 8 additions & 2 deletions packages/tracing-internal/src/common/fetch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { getClient, getCurrentScope, getDynamicSamplingContextFromClient, hasTracingEnabled } from '@sentry/core';
import {
getClient,
getCurrentScope,
getDynamicSamplingContextFromClient,
hasTracingEnabled,
spanToTraceHeader,
} from '@sentry/core';
import type { Client, HandlerDataFetch, Scope, Span, SpanOrigin } from '@sentry/types';
import {
BAGGAGE_HEADER_NAME,
Expand Down Expand Up @@ -128,7 +134,7 @@ export function addTracingHeadersToFetchRequest(

const { traceId, sampled, dsc } = scope.getPropagationContext();

const sentryTraceHeader = span ? span.toTraceparent() : generateSentryTraceHeader(traceId, undefined, sampled);
const sentryTraceHeader = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, undefined, sampled);
const dynamicSamplingContext = transaction
? transaction.getDynamicSamplingContext()
: dsc
Expand Down
5 changes: 4 additions & 1 deletion packages/types/src/span.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ export interface Span extends SpanContext {
*/
isSuccess(): boolean;

/** Return a traceparent compatible header string */
/**
* Return a traceparent compatible header string.
* @deprecated Use `spanToTraceHeader()` instead.
*/
toTraceparent(): string;

/**
Expand Down

0 comments on commit ddf1132

Please sign in to comment.