diff --git a/MIGRATION.md b/MIGRATION.md index f8d892e7e70f..b5b6d4da060b 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -205,6 +205,7 @@ In v8, the Span class is heavily reworked. The following properties & methods ar - `span.transaction`: Use `getRootSpan` utility function instead. - `span.spanRecorder`: Span recording will be handled internally by the SDK. - `span.status`: Use `.setStatus` to set or update and `spanToJSON()` to read the span status. +- `span.op`: Use `startSpan` functions to set, `setAttribute()` to update and `spanToJSON` to read the span operation. - `transaction.setMetadata()`: Use attributes instead, or set data on the scope. - `transaction.metadata`: Use attributes instead, or set data on the scope. - `transaction.setContext()`: Set context on the surrounding scope instead. diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts index c0832eb2d054..b2346db58450 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/middleware.test.ts @@ -63,7 +63,13 @@ test('Should trace outgoing fetch requests inside middleware and create breadcru expect(middlewareTransaction.spans).toEqual( expect.arrayContaining([ { - data: { 'http.method': 'GET', 'http.response.status_code': 200, type: 'fetch', url: 'http://localhost:3030/' }, + data: { + 'http.method': 'GET', + 'http.response.status_code': 200, + type: 'fetch', + url: 'http://localhost:3030/', + 'sentry.op': 'http.client', + }, description: 'GET http://localhost:3030/', op: 'http.client', origin: 'auto.http.wintercg_fetch', diff --git a/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts b/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts index cb3685ae8939..4c9310228eb3 100644 --- a/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/propagation.test.ts @@ -63,6 +63,7 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { url: 'http://localhost:3030/test-outgoing-http', 'otel.kind': 'SERVER', 'http.response.status_code': 200, + 'sentry.op': 'http.server', }, op: 'http.server', span_id: expect.any(String), @@ -85,6 +86,7 @@ test('Propagates trace for outgoing http requests', async ({ baseURL }) => { url: 'http://localhost:3030/test-inbound-headers', 'otel.kind': 'SERVER', 'http.response.status_code': 200, + 'sentry.op': 'http.server', }, op: 'http.server', parent_span_id: outgoingHttpSpanId, @@ -156,6 +158,7 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { url: 'http://localhost:3030/test-outgoing-fetch', 'otel.kind': 'SERVER', 'http.response.status_code': 200, + 'sentry.op': 'http.server', }, op: 'http.server', span_id: expect.any(String), @@ -178,6 +181,7 @@ test('Propagates trace for outgoing fetch requests', async ({ baseURL }) => { url: 'http://localhost:3030/test-inbound-headers', 'otel.kind': 'SERVER', 'http.response.status_code': 200, + 'sentry.op': 'http.server', }, op: 'http.server', parent_span_id: outgoingHttpSpanId, diff --git a/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts b/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts index e65a4c35b042..e29637a87df8 100644 --- a/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-experimental-fastify-app/tests/transactions.test.ts @@ -28,6 +28,7 @@ test('Sends an API route transaction', async ({ baseURL }) => { url: 'http://localhost:3030/test-transaction', 'otel.kind': 'SERVER', 'http.response.status_code': 200, + 'sentry.op': 'http.server', }, op: 'http.server', span_id: expect.any(String), diff --git a/packages/core/src/semanticAttributes.ts b/packages/core/src/semanticAttributes.ts index 6239e6f6acf7..884eb0e5e9ef 100644 --- a/packages/core/src/semanticAttributes.ts +++ b/packages/core/src/semanticAttributes.ts @@ -9,3 +9,8 @@ export const SEMANTIC_ATTRIBUTE_SENTRY_SOURCE = 'sentry.source'; * Use this attribute to represent the sample rate used for a span. */ export const SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE = 'sentry.sample_rate'; + +/** + * Use this attribute to represent the operation of a span. + */ +export const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op'; diff --git a/packages/core/src/tracing/idletransaction.ts b/packages/core/src/tracing/idletransaction.ts index f7ff2e48e9ad..c764dc4b098d 100644 --- a/packages/core/src/tracing/idletransaction.ts +++ b/packages/core/src/tracing/idletransaction.ts @@ -148,6 +148,7 @@ export class IdleTransaction extends Transaction { this._finished = true; this.activities = {}; + // eslint-disable-next-line deprecation/deprecation if (this.op === 'ui.action.click') { this.setAttribute(FINISH_REASON_TAG, this._finishReason); } @@ -155,6 +156,7 @@ export class IdleTransaction extends Transaction { // eslint-disable-next-line deprecation/deprecation if (this.spanRecorder) { DEBUG_BUILD && + // eslint-disable-next-line deprecation/deprecation logger.log('[Tracing] finishing IdleTransaction', new Date(endTimestampInS * 1000).toISOString(), this.op); for (const callback of this._beforeFinishCallbacks) { diff --git a/packages/core/src/tracing/sampling.ts b/packages/core/src/tracing/sampling.ts index f14aeb131db4..427a7076d6d0 100644 --- a/packages/core/src/tracing/sampling.ts +++ b/packages/core/src/tracing/sampling.ts @@ -95,6 +95,7 @@ export function sampleTransaction( } DEBUG_BUILD && + // eslint-disable-next-line deprecation/deprecation logger.log(`[Tracing] starting ${transaction.op} transaction - ${spanToJSON(transaction).description}`); return transaction; } diff --git a/packages/core/src/tracing/span.ts b/packages/core/src/tracing/span.ts index 3253f1580148..82f93ff6a38e 100644 --- a/packages/core/src/tracing/span.ts +++ b/packages/core/src/tracing/span.ts @@ -16,6 +16,7 @@ import type { import { dropUndefinedKeys, logger, timestampInSeconds, uuid4 } from '@sentry/utils'; import { DEBUG_BUILD } from '../debug-build'; +import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../semanticAttributes'; import { getRootSpan } from '../utils/getRootSpan'; import { TRACE_FLAG_NONE, @@ -67,11 +68,6 @@ export class Span implements SpanInterface { */ public parentSpanId?: string; - /** - * @inheritDoc - */ - public op?: string; - /** * Tags for the span. * @deprecated Use `getSpanAttributes(span)` instead. @@ -158,7 +154,7 @@ export class Span implements SpanInterface { this._sampled = spanContext.sampled; } if (spanContext.op) { - this.op = spanContext.op; + this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, spanContext.op); } if (spanContext.status) { this._status = spanContext.status; @@ -317,6 +313,25 @@ export class Span implements SpanInterface { this._status = status; } + /** + * Operation of the span + * + * @deprecated Use `spanToJSON().op` to read the op instead. + */ + public get op(): string | undefined { + return this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] as string | undefined; + } + + /** + * Operation of the span + * + * @deprecated Use `startSpan()` functions to set or `span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'op') + * to update the span instead. + */ + public set op(op: string | undefined) { + this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, op); + } + /* eslint-enable @typescript-eslint/member-ordering */ /** @inheritdoc */ @@ -512,6 +527,7 @@ export class Span implements SpanInterface { data: this._getData(), description: this._name, endTimestamp: this._endTime, + // eslint-disable-next-line deprecation/deprecation op: this.op, parentSpanId: this.parentSpanId, sampled: this._sampled, @@ -535,6 +551,7 @@ export class Span implements SpanInterface { // eslint-disable-next-line deprecation/deprecation this._name = spanContext.name || spanContext.description; this._endTime = spanContext.endTimestamp; + // eslint-disable-next-line deprecation/deprecation this.op = spanContext.op; this.parentSpanId = spanContext.parentSpanId; this._sampled = spanContext.sampled; @@ -569,7 +586,7 @@ export class Span implements SpanInterface { return dropUndefinedKeys({ data: this._getData(), description: this._name, - op: this.op, + op: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] as string | undefined, parent_span_id: this.parentSpanId, span_id: this._spanId, start_timestamp: this._startTime, diff --git a/packages/core/src/tracing/transaction.ts b/packages/core/src/tracing/transaction.ts index 38b1661f25f1..490714636fe9 100644 --- a/packages/core/src/tracing/transaction.ts +++ b/packages/core/src/tracing/transaction.ts @@ -344,6 +344,7 @@ export class Transaction extends SpanClass implements TransactionInterface { transaction.measurements = this._measurements; } + // eslint-disable-next-line deprecation/deprecation DEBUG_BUILD && logger.log(`[Tracing] Finishing ${this.op} transaction: ${this._name}.`); return transaction; diff --git a/packages/core/test/lib/utils/spanUtils.test.ts b/packages/core/test/lib/utils/spanUtils.test.ts index 82978854353a..5699fa391c2b 100644 --- a/packages/core/test/lib/utils/spanUtils.test.ts +++ b/packages/core/test/lib/utils/spanUtils.test.ts @@ -87,6 +87,9 @@ describe('spanToJSON', () => { origin: 'auto', start_timestamp: 123, timestamp: 456, + data: { + 'sentry.op': 'test op', + }, }); }); diff --git a/packages/nextjs/test/integration/test/client/tracingFetch.test.ts b/packages/nextjs/test/integration/test/client/tracingFetch.test.ts index 0a6c2af8c5f3..579ccf4ca547 100644 --- a/packages/nextjs/test/integration/test/client/tracingFetch.test.ts +++ b/packages/nextjs/test/integration/test/client/tracingFetch.test.ts @@ -37,6 +37,7 @@ test('should correctly instrument `fetch` for performance tracing', async ({ pag type: 'fetch', 'http.response_content_length': expect.any(Number), 'http.response.status_code': 200, + 'sentry.op': 'http.client', }, description: 'GET http://example.com', op: 'http.client', diff --git a/packages/node-experimental/test/integration/transactions.test.ts b/packages/node-experimental/test/integration/transactions.test.ts index 374f104a5c2d..8a9464c1fd03 100644 --- a/packages/node-experimental/test/integration/transactions.test.ts +++ b/packages/node-experimental/test/integration/transactions.test.ts @@ -84,7 +84,7 @@ describe('Integration | Transactions', () => { }, runtime: { name: 'node', version: expect.any(String) }, trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op' }, op: 'test op', span_id: expect.any(String), status: 'ok', @@ -244,7 +244,7 @@ describe('Integration | Transactions', () => { }, }), trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op' }, op: 'test op', span_id: expect.any(String), status: 'ok', @@ -286,7 +286,7 @@ describe('Integration | Transactions', () => { }, }), trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op b' }, op: 'test op b', span_id: expect.any(String), status: 'ok', @@ -363,7 +363,7 @@ describe('Integration | Transactions', () => { attributes: {}, }), trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op' }, op: 'test op', span_id: expect.any(String), parent_span_id: parentSpanId, diff --git a/packages/node/test/integrations/http.test.ts b/packages/node/test/integrations/http.test.ts index b768d60100a9..57b7fe22d19a 100644 --- a/packages/node/test/integrations/http.test.ts +++ b/packages/node/test/integrations/http.test.ts @@ -79,7 +79,9 @@ describe('tracing', () => { // our span is at index 1 because the transaction itself is at index 0 expect(spanToJSON(spans[1]).description).toEqual('GET http://dogs.are.great/'); + // eslint-disable-next-line deprecation/deprecation expect(spans[1].op).toEqual('http.client'); + expect(spanToJSON(spans[1]).op).toEqual('http.client'); }); it("doesn't create a span for outgoing sentry requests", () => { @@ -283,7 +285,9 @@ describe('tracing', () => { // our span is at index 1 because the transaction itself is at index 0 expect(spanToJSON(spans[1]).description).toEqual('GET http://dogs.are.great/spaniel'); + // eslint-disable-next-line deprecation/deprecation expect(spans[1].op).toEqual('http.client'); + expect(spanToJSON(spans[1]).op).toEqual('http.client'); const spanAttributes = spanToJSON(spans[1]).data || {}; @@ -308,7 +312,9 @@ describe('tracing', () => { // our span is at index 1 because the transaction itself is at index 0 expect(spanToJSON(spans[1]).description).toEqual('GET http://dogs.are.great/spaniel'); + // eslint-disable-next-line deprecation/deprecation expect(spans[1].op).toEqual('http.client'); + expect(spanToJSON(spans[1]).op).toEqual('http.client'); expect(spanAttributes['http.method']).toEqual('GET'); expect(spanAttributes.url).toEqual('http://dogs.are.great/spaniel'); expect(spanAttributes['http.query']).toEqual('tail=wag&cute=true'); @@ -391,6 +397,7 @@ describe('tracing', () => { const request = http.get(url); // There should be no http spans + // eslint-disable-next-line deprecation/deprecation const httpSpans = spans.filter(span => span.op?.startsWith('http')); expect(httpSpans.length).toBe(0); @@ -497,6 +504,7 @@ describe('tracing', () => { const request = http.get(url); // There should be no http spans + // eslint-disable-next-line deprecation/deprecation const httpSpans = spans.filter(span => span.op?.startsWith('http')); expect(httpSpans.length).toBe(0); diff --git a/packages/opentelemetry-node/src/spanprocessor.ts b/packages/opentelemetry-node/src/spanprocessor.ts index 8e7b54684469..b415a3eac730 100644 --- a/packages/opentelemetry-node/src/spanprocessor.ts +++ b/packages/opentelemetry-node/src/spanprocessor.ts @@ -3,6 +3,7 @@ import { SpanKind, context, trace } from '@opentelemetry/api'; import { suppressTracing } from '@opentelemetry/core'; import type { Span as OtelSpan, SpanProcessor as OtelSpanProcessor } from '@opentelemetry/sdk-trace-base'; import { + SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Transaction, addEventProcessor, @@ -221,7 +222,7 @@ function updateTransactionWithOtelData(transaction: Transaction, otelSpan: OtelS transaction.setStatus(mapOtelStatus(otelSpan)); - transaction.op = op; + transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, op); transaction.updateName(description); transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source); } diff --git a/packages/opentelemetry-node/test/spanprocessor.test.ts b/packages/opentelemetry-node/test/spanprocessor.test.ts index 08cc38db0011..c70134fcf9ad 100644 --- a/packages/opentelemetry-node/test/spanprocessor.test.ts +++ b/packages/opentelemetry-node/test/spanprocessor.test.ts @@ -560,6 +560,7 @@ describe('SentrySpanProcessor', () => { 'http.url': 'http://example.com/my/route/123', 'otel.kind': 'INTERNAL', url: 'http://example.com/my/route/123', + 'sentry.op': 'http', }); parentOtelSpan.end(); @@ -580,7 +581,7 @@ describe('SentrySpanProcessor', () => { child.end(); - const { description, data } = spanToJSON(sentrySpan!); + const { description, data, op } = spanToJSON(sentrySpan!); expect(description).toBe('GET http://example.com/my/route/123'); expect(data).toEqual({ @@ -589,7 +590,9 @@ describe('SentrySpanProcessor', () => { 'http.url': 'http://example.com/my/route/123', 'otel.kind': 'INTERNAL', url: 'http://example.com/my/route/123', + 'sentry.op': 'http', }); + expect(op).toBe('http'); parentOtelSpan.end(); }); @@ -609,7 +612,7 @@ describe('SentrySpanProcessor', () => { child.end(); - const { description, data } = spanToJSON(sentrySpan!); + const { description, data, op } = spanToJSON(sentrySpan!); expect(description).toBe('GET http://example.com/my/route/123'); expect(data).toEqual({ @@ -620,7 +623,9 @@ describe('SentrySpanProcessor', () => { url: 'http://example.com/my/route/123', 'http.query': '?what=123', 'http.fragment': '#myHash', + 'sentry.op': 'http', }); + expect(op).toBe('http'); parentOtelSpan.end(); }); @@ -780,7 +785,10 @@ describe('SentrySpanProcessor', () => { parentOtelSpan.setAttribute(SemanticAttributes.FAAS_TRIGGER, 'test faas trigger'); parentOtelSpan.end(); + // eslint-disable-next-line deprecation/deprecation expect(transaction.op).toBe('test faas trigger'); + expect(spanToJSON(transaction).op).toBe('test faas trigger'); + expect(spanToJSON(transaction).description).toBe('test operation'); }); }); diff --git a/packages/opentelemetry/test/integration/transactions.test.ts b/packages/opentelemetry/test/integration/transactions.test.ts index 78a9aa18fde7..cf172d048b59 100644 --- a/packages/opentelemetry/test/integration/transactions.test.ts +++ b/packages/opentelemetry/test/integration/transactions.test.ts @@ -83,7 +83,7 @@ describe('Integration | Transactions', () => { }, }, trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op' }, op: 'test op', span_id: expect.any(String), status: 'ok', @@ -144,7 +144,9 @@ describe('Integration | Transactions', () => { // This is the same behavior as for the "regular" SDKs expect(spans.map(span => spanToJSON(span))).toEqual([ { - data: { 'otel.kind': 'INTERNAL' }, + data: { + 'otel.kind': 'INTERNAL', + }, description: 'inner span 1', origin: 'manual', parent_span_id: expect.any(String), @@ -236,7 +238,7 @@ describe('Integration | Transactions', () => { }, }), trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op' }, op: 'test op', span_id: expect.any(String), status: 'ok', @@ -278,7 +280,7 @@ describe('Integration | Transactions', () => { }, }), trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { 'otel.kind': 'INTERNAL', 'sentry.op': 'test op b' }, op: 'test op b', span_id: expect.any(String), status: 'ok', @@ -355,7 +357,10 @@ describe('Integration | Transactions', () => { attributes: {}, }), trace: { - data: { 'otel.kind': 'INTERNAL' }, + data: { + 'otel.kind': 'INTERNAL', + 'sentry.op': 'test op', + }, op: 'test op', span_id: expect.any(String), parent_span_id: parentSpanId, diff --git a/packages/tracing-internal/src/browser/backgroundtab.ts b/packages/tracing-internal/src/browser/backgroundtab.ts index 5d9fb29cd08e..95f33c0c9fd3 100644 --- a/packages/tracing-internal/src/browser/backgroundtab.ts +++ b/packages/tracing-internal/src/browser/backgroundtab.ts @@ -17,13 +17,13 @@ export function registerBackgroundTabDetection(): void { if (WINDOW.document.hidden && activeTransaction) { const statusType: SpanStatusType = 'cancelled'; + const { op, status } = spanToJSON(activeTransaction); + DEBUG_BUILD && - logger.log( - `[Tracing] Transaction: ${statusType} -> since tab moved to the background, op: ${activeTransaction.op}`, - ); + logger.log(`[Tracing] Transaction: ${statusType} -> since tab moved to the background, op: ${op}`); // We should not set status if it is already set, this prevent important statuses like // error or data loss from being overwritten on transaction. - if (!spanToJSON(activeTransaction).status) { + if (!status) { activeTransaction.setStatus(statusType); } // TODO: Can we rewrite this to an attribute? diff --git a/packages/tracing-internal/src/browser/metrics/index.ts b/packages/tracing-internal/src/browser/metrics/index.ts index 5c93537946ba..198ce7e61ebe 100644 --- a/packages/tracing-internal/src/browser/metrics/index.ts +++ b/packages/tracing-internal/src/browser/metrics/index.ts @@ -1,10 +1,10 @@ /* eslint-disable max-lines */ import type { IdleTransaction, Transaction } from '@sentry/core'; -import { spanToJSON } from '@sentry/core'; import { getActiveTransaction, setMeasurement } from '@sentry/core'; import type { Measurements, SpanContext } from '@sentry/types'; import { browserPerformanceTimeOrigin, getComponentName, htmlTreeAsString, logger } from '@sentry/utils'; +import { spanToJSON } from '@sentry/core'; import { DEBUG_BUILD } from '../../common/debug-build'; import { addClsInstrumentationHandler, @@ -186,13 +186,14 @@ export function addPerformanceEntries(transaction: Transaction): void { let responseStartTimestamp: number | undefined; let requestStartTimestamp: number | undefined; - const transactionStartTime = spanToJSON(transaction).start_timestamp; + const { op, start_timestamp: transactionStartTime } = spanToJSON(transaction); // eslint-disable-next-line @typescript-eslint/no-explicit-any performanceEntries.slice(_performanceCursor).forEach((entry: Record) => { const startTime = msToSec(entry.startTime); const duration = msToSec(entry.duration); + // eslint-disable-next-line deprecation/deprecation if (transaction.op === 'navigation' && transactionStartTime && timeOrigin + startTime < transactionStartTime) { return; } @@ -239,7 +240,7 @@ export function addPerformanceEntries(transaction: Transaction): void { _trackNavigator(transaction); // Measurements are only available for pageload transactions - if (transaction.op === 'pageload') { + if (op === 'pageload') { // Generate TTFB (Time to First Byte), which measured as the time between the beginning of the transaction and the // start of the response in milliseconds if (typeof responseStartTimestamp === 'number' && transactionStartTime) { diff --git a/packages/tracing-internal/test/browser/request.test.ts b/packages/tracing-internal/test/browser/request.test.ts index 8bf28befb886..6641be671bfc 100644 --- a/packages/tracing-internal/test/browser/request.test.ts +++ b/packages/tracing-internal/test/browser/request.test.ts @@ -263,7 +263,9 @@ describe('callbacks', () => { 'http.response.status_code': 404, type: 'fetch', url: 'http://dogs.are.great/', + 'sentry.op': 'http.client', }); + expect(finishedSpan.op).toBe('http.client'); }); }); diff --git a/packages/tracing/test/span.test.ts b/packages/tracing/test/span.test.ts index 1e6ade7d4dec..873c139e41c9 100644 --- a/packages/tracing/test/span.test.ts +++ b/packages/tracing/test/span.test.ts @@ -484,6 +484,9 @@ describe('Span', () => { startTimestamp: expect.any(Number), tags: {}, traceId: expect.any(String), + data: { + 'sentry.op': 'op', + }, }); }); @@ -535,6 +538,9 @@ describe('Span', () => { tags: { tag1: 'bye', }, + data: { + ...span.toContext().data, + }, }; if (newContext.data) newContext.data.data1 = 'bar'; @@ -548,7 +554,7 @@ describe('Span', () => { expect(span.op).toBe('new-op'); expect(span.sampled).toBe(true); expect(span.tags).toStrictEqual({ tag1: 'bye' }); - expect(span.data).toStrictEqual({ data0: 'foo', data1: 'bar' }); + expect(span.data).toStrictEqual({ data0: 'foo', data1: 'bar', 'sentry.op': 'op' }); }); });