|
1 | 1 | import { describe, expect, it, test, vi } from 'vitest'; |
2 | 2 | import { getCurrentScope } from '../../../src/currentScopes'; |
3 | 3 | import { setCurrentClient } from '../../../src/sdk'; |
4 | | -import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '../../../src/semanticAttributes'; |
| 4 | +import { |
| 5 | + SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT, |
| 6 | + SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE, |
| 7 | + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, |
| 8 | +} from '../../../src/semanticAttributes'; |
5 | 9 | import { _INTERNAL_setDeferSegmentSpanCapture, SentrySpan } from '../../../src/tracing/sentrySpan'; |
6 | 10 | import { SPAN_STATUS_ERROR } from '../../../src/tracing/spanstatus'; |
7 | | -import { markSpanForOtelSourceInference, spanSourceWasExplicitlySet } from '../../../src/tracing/utils'; |
| 11 | +import { |
| 12 | + markSpanAsTracerProviderSpan, |
| 13 | + markSpanForOtelSourceInference, |
| 14 | + spanSourceWasExplicitlySet, |
| 15 | +} from '../../../src/tracing/utils'; |
8 | 16 | import type { SpanJSON } from '../../../src/types/span'; |
9 | 17 | import { spanToJSON, TRACE_FLAG_NONE, TRACE_FLAG_SAMPLED } from '../../../src/utils/spanUtils'; |
10 | 18 | import { timestampInSeconds } from '../../../src/utils/time'; |
@@ -144,6 +152,61 @@ describe('SentrySpan', () => { |
144 | 152 | }); |
145 | 153 | }); |
146 | 154 |
|
| 155 | + describe('tracer-provider span sealing', () => { |
| 156 | + it('seals a tracer-provider span against all mutation after it ends', () => { |
| 157 | + const span = new SentrySpan({ name: 'original', startTimestamp: 1, attributes: { key: 'before' } }); |
| 158 | + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'before' }); |
| 159 | + span.addEvent('measurement', { |
| 160 | + [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: 1, |
| 161 | + [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond', |
| 162 | + }); |
| 163 | + const linked = new SentrySpan({ name: 'linked' }); |
| 164 | + |
| 165 | + markSpanAsTracerProviderSpan(span); |
| 166 | + span.end(); |
| 167 | + |
| 168 | + // Every mutator must no-op on a tracer-provider span once it has ended, mirroring OTel SDK spans. |
| 169 | + span.setAttribute('key', 'after'); |
| 170 | + span.setAttributes({ key2: 'after' }); |
| 171 | + span.setStatus({ code: SPAN_STATUS_ERROR, message: 'after' }); |
| 172 | + span.updateName('after'); |
| 173 | + span.updateStartTime(999); |
| 174 | + span.addLink({ context: linked.spanContext() }); |
| 175 | + span.addLinks([{ context: linked.spanContext() }]); |
| 176 | + span.addEvent('measurement', { |
| 177 | + [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_VALUE]: 2, |
| 178 | + [SEMANTIC_ATTRIBUTE_SENTRY_MEASUREMENT_UNIT]: 'millisecond', |
| 179 | + }); |
| 180 | + |
| 181 | + const json = spanToJSON(span); |
| 182 | + expect(json.data?.['key']).toBe('before'); |
| 183 | + expect(json.data?.['key2']).toBeUndefined(); |
| 184 | + expect(json.status).toBe('before'); |
| 185 | + expect(json.description).toBe('original'); |
| 186 | + expect(json.start_timestamp).toBe(1); |
| 187 | + expect(json.links).toBeUndefined(); |
| 188 | + expect(json.measurements).toEqual({ measurement: { value: 1, unit: 'millisecond' } }); |
| 189 | + }); |
| 190 | + |
| 191 | + it('keeps a span that is not a tracer-provider span mutable after it ends', () => { |
| 192 | + const span = new SentrySpan({ name: 'original', startTimestamp: 1, attributes: { key: 'before' } }); |
| 193 | + const linked = new SentrySpan({ name: 'linked' }); |
| 194 | + |
| 195 | + span.end(); |
| 196 | + |
| 197 | + span.setAttribute('key', 'after'); |
| 198 | + span.updateName('after'); |
| 199 | + span.updateStartTime(999); |
| 200 | + span.addLink({ context: linked.spanContext() }); |
| 201 | + |
| 202 | + const json = spanToJSON(span); |
| 203 | + expect(json.data?.['key']).toBe('after'); |
| 204 | + expect(json.description).toBe('after'); |
| 205 | + expect(json.start_timestamp).toBe(999); |
| 206 | + expect(json.links).toHaveLength(1); |
| 207 | + }); |
| 208 | + }); |
| 209 | + |
147 | 210 | describe('end', () => { |
148 | 211 | test('simple', () => { |
149 | 212 | const span = new SentrySpan({}); |
|
0 commit comments