Skip to content

feat(performance): Adds exclusive time and measurements to spans #10704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
5 changes: 5 additions & 0 deletions packages/core/src/semanticAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ export const SEMANTIC_ATTRIBUTE_SENTRY_OP = 'sentry.op';
* Use this attribute to represent the origin of a span.
*/
export const SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN = 'sentry.origin';

/**
* Use this attribute to represent measurements of a span.
*/
export const SEMANTIC_ATTRIBUTE_MEASUREMENTS = 'measurements';
13 changes: 12 additions & 1 deletion packages/core/src/tracing/span.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable max-lines */
import type {
Instrumenter,
Measurements,
Primitive,
Span as SpanInterface,
SpanAttributeValue,
Expand All @@ -17,7 +18,11 @@ import { dropUndefinedKeys, logger, timestampInSeconds, uuid4 } from '@sentry/ut

import { DEBUG_BUILD } from '../debug-build';
import { getMetricSummaryJsonForSpan } from '../metrics/metric-summary';
import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes';
import {
SEMANTIC_ATTRIBUTE_MEASUREMENTS,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
} from '../semanticAttributes';
import { getRootSpan } from '../utils/getRootSpan';
import {
TRACE_FLAG_NONE,
Expand Down Expand Up @@ -115,6 +120,7 @@ export class Span implements SpanInterface {
protected _endTime?: number;
/** Internal keeper of the status */
protected _status?: SpanStatusType | string;
protected _exclusiveTime?: number;

private _logMessage?: string;

Expand Down Expand Up @@ -159,6 +165,9 @@ export class Span implements SpanInterface {
if (spanContext.endTimestamp) {
this._endTime = spanContext.endTimestamp;
}
if (spanContext.exclusiveTime) {
this._exclusiveTime = spanContext.exclusiveTime;
}
}

// This rule conflicts with another eslint rule :(
Expand Down Expand Up @@ -626,6 +635,8 @@ export class Span implements SpanInterface {
trace_id: this._traceId,
origin: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined,
_metrics_summary: getMetricSummaryJsonForSpan(this),
exclusive_time: this._exclusiveTime,
measurements: this._attributes[SEMANTIC_ATTRIBUTE_MEASUREMENTS] as Measurements | undefined,
});
}

Expand Down
3 changes: 0 additions & 3 deletions packages/core/test/lib/tracing/span.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,6 @@ describe('span', () => {
it('disallows invalid attribute types', () => {
const span = new Span();

/** @ts-expect-error this is invalid */
span.setAttribute('str', {});

/** @ts-expect-error this is invalid */
span.setAttribute('str', null);

Expand Down
10 changes: 9 additions & 1 deletion packages/types/src/span.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { TraceContext } from './context';
import type { Instrumenter } from './instrumenter';
import type { Measurements } from './measurement';
import type { Primitive } from './misc';
import type { HrTime } from './opentelemetry';
import type { Transaction } from './transaction';
Expand All @@ -21,13 +22,15 @@ export type SpanAttributeValue =
| boolean
| Array<null | undefined | string>
| Array<null | undefined | number>
| Array<null | undefined | boolean>;
| Array<null | undefined | boolean>
| Measurements;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks OTEL compatibility unfortunately. We'll just add them to span data directly for now, but we need a bigger strategy afterwards.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think we'll probably have to flatten measurements into the attributes, or something similar in the future


export type SpanAttributes = Partial<{
'sentry.origin': string;
'sentry.op': string;
'sentry.source': string;
'sentry.sample_rate': number;
measurements: Measurements;
}> &
Record<string, SpanAttributeValue | undefined>;

Expand Down Expand Up @@ -178,6 +181,11 @@ export interface SpanContext {
* The origin of the span, giving context about what created the span.
*/
origin?: SpanOrigin;

/**
* Exclusive time in milliseconds.
*/
exclusiveTime?: number;
}

/** Span holding trace_id, span_id */
Expand Down