Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
GEN_AI_USAGE_OUTPUT_TOKENS,
GEN_AI_USAGE_TOTAL_TOKENS,
} from '@sentry/conventions/attributes';
import { GEN_AI_EMBEDDINGS } from '@sentry/conventions/op';
import {
GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE,
GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE,
GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE,
} from '../../../../../packages/server-utils/src/ai/core/gen-ai-attributes';
Expand Down Expand Up @@ -315,7 +315,7 @@ describe('LangChain integration', () => {
);
expect(successfulSpans).toHaveLength(2);
for (const span of successfulSpans) {
expect(span.attributes['sentry.op'].value).toBe(GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE);
expect(span.attributes['sentry.op'].value).toBe(GEN_AI_EMBEDDINGS);
expect(span.attributes['sentry.origin'].value).toBe('auto.ai.langchain');
expect(span.attributes[GEN_AI_OPERATION_NAME].value).toBe('embeddings');
expect(span.attributes[GEN_AI_PROVIDER_NAME].value).toBe('openai');
Expand All @@ -326,7 +326,7 @@ describe('LangChain integration', () => {
const errorSpan = container.items.find(span => span.name === 'embeddings error-model');
expect(errorSpan).toBeDefined();
expect(errorSpan!.status).toBe('error');
expect(errorSpan!.attributes['sentry.op'].value).toBe(GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE);
expect(errorSpan!.attributes['sentry.op'].value).toBe(GEN_AI_EMBEDDINGS);
expect(errorSpan!.attributes[GEN_AI_PROVIDER_NAME].value).toBe('openai');
},
})
Expand All @@ -342,7 +342,7 @@ describe('LangChain integration', () => {
// The scenario makes 3 embedding calls (2 successful + 1 error).
expect(container.items).toHaveLength(3);
for (const span of container.items) {
expect(span.attributes['sentry.op'].value).toBe(GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE);
expect(span.attributes['sentry.op'].value).toBe(GEN_AI_EMBEDDINGS);
}
},
})
Expand Down
5 changes: 2 additions & 3 deletions packages/angular/src/tracing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
URL_PATH,
URL_TEMPLATE,
} from '@sentry/conventions/attributes';
import { FUNCTION } from '@sentry/conventions/op';
import { FUNCTION, ROUTER } from '@sentry/conventions/op';
import type { Integration, Span } from '@sentry/core';
import {
debug,
Expand Down Expand Up @@ -151,8 +151,7 @@ export class TraceService implements OnDestroy {
// known at `ResolveEnd`, well after this span starts, so there is nothing but the fallback.
name: hasSpanStreamingEnabled(client) ? ROUTER_SPAN_NAME_FALLBACK : `${navigationEvent.url}`,
attributes: {
// TODO(conventions): Replace `'router'` with the `router` span op constant once it is released in `@sentry/conventions`.
[SENTRY_OP]: 'router',
[SENTRY_OP]: ROUTER,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.angular',
[URL_FULL]: strippedUrl,
...(navigationEvent.navigationTrigger && {
Expand Down
3 changes: 2 additions & 1 deletion packages/astro/src/server/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
URL_PATH,
URL_QUERY,
} from '@sentry/conventions/attributes';
import { HTTP_SERVER } from '@sentry/conventions/op';
import type { Span, SpanAttributes } from '@sentry/core';
import {
addNonEnumerableProperty,
Expand Down Expand Up @@ -220,6 +221,7 @@ async function instrumentRequestStartHttpServerSpan(
// invoke the catch block if next() throws

const attributes: SpanAttributes = {
[SENTRY_OP]: HTTP_SERVER,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.astro',
[SENTRY_SEGMENT_NAME_SOURCE]: source,
[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: method,
Expand Down Expand Up @@ -252,7 +254,6 @@ async function instrumentRequestStartHttpServerSpan(
{
attributes,
name,
op: 'http.server',
},
async span => {
try {
Expand Down
3 changes: 2 additions & 1 deletion packages/astro/src/server/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { HTTP_SERVER } from '@sentry/conventions/op';
import { applySdkMetadata } from '@sentry/core';
import type { NodeClient, NodeOptions } from '@sentry/node';
import { init as initNodeSdk } from '@sentry/node';
Expand All @@ -19,7 +20,7 @@ export function init(options: NodeOptions): NodeClient | undefined {
// we want to drop them
// this is the case with http.server spans of prerendered pages
// we do not care about those, as they are effectively static
{ op: 'http.server', attributes: { 'sentry.origin': 'auto.http.http_server' } },
{ op: HTTP_SERVER, attributes: { 'sentry.origin': 'auto.http.http_server' } },
];

return initNodeSdk(opts);
Expand Down
4 changes: 2 additions & 2 deletions packages/astro/test/server/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ describe('sentryMiddleware', () => {
expect(startSpanSpy).toHaveBeenCalledWith(
{
attributes: {
'sentry.op': 'http.server',
'sentry.origin': 'auto.http.astro',
method: 'GET',
[URL_FULL]: 'https://mydomain.io/users/123/details',
Expand All @@ -125,7 +126,6 @@ describe('sentryMiddleware', () => {
'http.route': '/users/[id]/details',
},
name: 'GET /users/[id]/details',
op: 'http.server',
},
expect.any(Function), // the `next` function
);
Expand Down Expand Up @@ -218,6 +218,7 @@ describe('sentryMiddleware', () => {
expect(startSpanSpy).toHaveBeenCalledWith(
{
attributes: {
'sentry.op': 'http.server',
'sentry.origin': 'auto.http.astro',
method: 'GET',
[URL_FULL]: 'http://localhost:1234/a%xx',
Expand All @@ -226,7 +227,6 @@ describe('sentryMiddleware', () => {
[SentryCore.SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]: 'GET',
},
name: 'GET a%xx',
op: 'http.server',
},
expect.any(Function), // the `next` function
);
Expand Down
53 changes: 39 additions & 14 deletions packages/browser-utils/src/performance/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,22 @@ import {
URL_FULL,
URL_SCHEME,
} from '@sentry/conventions/attributes';
import { BROWSER_PAINT, UI_LONG_ANIMATION_FRAME, UI_LONG_TASK } from '@sentry/conventions/op';
import {
BROWSER_CACHE,
BROWSER_CONNECT,
BROWSER_DNS,
BROWSER_DOM_CONTENT_LOADED_EVENT,
BROWSER_LOAD_EVENT,
BROWSER_PAINT,
BROWSER_REDIRECT,
BROWSER_REQUEST,
BROWSER_RESPONSE,
BROWSER_TLS_SSL,
BROWSER_UNLOAD_EVENT,
RESOURCE_OTHER,
UI_LONG_ANIMATION_FRAME,
UI_LONG_TASK,
} from '@sentry/conventions/op';
import {
addPerformanceInstrumentationHandler,
type PerformanceLongAnimationFrameTiming,
Expand Down Expand Up @@ -278,14 +293,14 @@ function _addPaintSpan(
* exported only for tests
*/
export function _addNavigationSpans(span: Span, entry: PerformanceNavigationTiming, timeOrigin: number): void {
_addPerformanceNavigationTiming(span, entry, 'unloadEvent', timeOrigin, 'unload_event');
_addPerformanceNavigationTiming(span, entry, 'redirect', timeOrigin, 'redirect');
_addPerformanceNavigationTiming(span, entry, 'domContentLoadedEvent', timeOrigin, 'dom_content_loaded_event');
_addPerformanceNavigationTiming(span, entry, 'loadEvent', timeOrigin, 'load_event');
_addPerformanceNavigationTiming(span, entry, 'connect', timeOrigin, 'connect');
_addPerformanceNavigationTiming(span, entry, 'secureConnection', timeOrigin, 'tls_ssl');
_addPerformanceNavigationTiming(span, entry, 'fetch', timeOrigin, 'cache');
_addPerformanceNavigationTiming(span, entry, 'domainLookup', timeOrigin, 'dns');
_addPerformanceNavigationTiming(span, entry, 'unloadEvent', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'redirect', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'domContentLoadedEvent', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'loadEvent', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'connect', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'secureConnection', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'fetch', timeOrigin);
_addPerformanceNavigationTiming(span, entry, 'domainLookup', timeOrigin);

_addRequest(span, entry, timeOrigin);
}
Expand All @@ -300,6 +315,17 @@ type StartEventName =
| 'domContentLoadedEvent'
| 'loadEvent';

const NAVIGATION_TIMING_SPAN_OPS: Record<StartEventName, string> = {
secureConnection: BROWSER_TLS_SSL,
fetch: BROWSER_CACHE,
domainLookup: BROWSER_DNS,
unloadEvent: BROWSER_UNLOAD_EVENT,
redirect: BROWSER_REDIRECT,
connect: BROWSER_CONNECT,
domContentLoadedEvent: BROWSER_DOM_CONTENT_LOADED_EVENT,
loadEvent: BROWSER_LOAD_EVENT,
};

type EndEventName =
| 'domainLookupStart'
| 'domainLookupEnd'
Expand All @@ -315,7 +341,6 @@ function _addPerformanceNavigationTiming(
entry: PerformanceNavigationTiming,
event: StartEventName,
timeOrigin: number,
name: string = event,
): void {
const eventEnd = _getEndPropertyNameForNavigationTiming(event) satisfies keyof PerformanceNavigationTiming;
const end = entry[eventEnd];
Expand All @@ -324,9 +349,9 @@ function _addPerformanceNavigationTiming(
return;
}
startAndEndSpan(span, timeOrigin + msToSec(start), timeOrigin + msToSec(end), {
op: `browser.${name}`,
name: entry.name,
attributes: {
[SENTRY_OP]: NAVIGATION_TIMING_SPAN_OPS[event],
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',
...(event === 'redirect' && entry.redirectCount != null ? { 'http.redirect_count': entry.redirectCount } : {}),
},
Expand Down Expand Up @@ -354,17 +379,17 @@ function _addRequest(span: Span, entry: PerformanceNavigationTiming, timeOrigin:
// In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect
// these spans when the responseEnd value is available. The backend (Relay) would drop the entire span if it contained faulty spans.
startAndEndSpan(span, requestStartTimestamp, responseEndTimestamp, {
op: 'browser.request',
name: entry.name,
attributes: {
[SENTRY_OP]: BROWSER_REQUEST,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',
},
});

startAndEndSpan(span, responseStartTimestamp, responseEndTimestamp, {
op: 'browser.response',
name: entry.name,
attributes: {
[SENTRY_OP]: BROWSER_RESPONSE,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.metrics',
},
});
Expand All @@ -391,7 +416,7 @@ export function _addResourceSpans(
return;
}

const op = entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other';
const op = entry.initiatorType ? `resource.${entry.initiatorType}` : RESOURCE_OTHER;
if (ignoredResourceSpanOps?.includes(op)) {
return;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/browser/src/integrations/fetchStreamPerformance.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { HTTP_REQUEST_METHOD, URL_FULL } from '@sentry/conventions/attributes';
import { HTTP_REQUEST_METHOD, SENTRY_OP, URL_FULL } from '@sentry/conventions/attributes';
import { HTTP_CLIENT_STREAM } from '@sentry/conventions/op';
import type { IntegrationFn, Span } from '@sentry/core';
import {
addFetchEndInstrumentationHandler,
addFetchInstrumentationHandler,
defineIntegration,
getSanitizedUrlStringFromUrlObject,
parseStringToURLObject,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
stripDataUrlContent,
filterCollectedUrl,
Expand Down Expand Up @@ -85,7 +85,7 @@ export const fetchStreamPerformanceIntegration = defineIntegration(() => {
[URL_FULL]: filterCollectedUrl(stripDataUrlContent(url)),
[HTTP_REQUEST_METHOD]: method,
type: 'fetch',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client.stream',
[SENTRY_OP]: HTTP_CLIENT_STREAM,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser.stream',
},
});
Expand Down
7 changes: 4 additions & 3 deletions packages/browser/src/tracing/browserTracingIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { registerBackgroundTabDetection } from './backgroundtab';
import { linkTraces } from './linkedTraces';
import { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request';
import { SENTRY_SEGMENT_NAME_SOURCE, SENTRY_OP, URL_FULL, URL_PATH } from '@sentry/conventions/attributes';
import { NAVIGATION, NAVIGATION_REDIRECT, PAGELOAD } from '@sentry/conventions/op';

export const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';

Expand Down Expand Up @@ -484,7 +485,7 @@ export const browserTracingIntegration = ((options: Partial<BrowserTracingOption
_createRouteSpan(
client,
{
op: 'navigation.redirect',
op: NAVIGATION_REDIRECT,
...startSpanOptions,
},
false,
Expand Down Expand Up @@ -516,7 +517,7 @@ export const browserTracingIntegration = ((options: Partial<BrowserTracingOption
_createRouteSpan(
client,
{
op: 'navigation',
op: NAVIGATION,
...startSpanOptions,
// Navigation starts a new trace and is NOT parented under any active interaction (e.g. ui.action.click)
parentSpan: null,
Expand Down Expand Up @@ -555,7 +556,7 @@ export const browserTracingIntegration = ((options: Partial<BrowserTracingOption
});

_createRouteSpan(client, {
op: 'pageload',
op: PAGELOAD,
...startSpanOptions,
});
});
Expand Down
13 changes: 10 additions & 3 deletions packages/browser/src/tracing/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
instrumentFetchRequest,
matchesTracePropagationTargets,
parseUrl,
SEMANTIC_ATTRIBUTE_SENTRY_OP,
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
SentryNonRecordingSpan,
setHttpStatus,
Expand All @@ -35,7 +34,15 @@ import {
} from '@sentry/browser-utils';
import type { BrowserClient } from '../client';
import { baggageHeaderHasSentryValues, createHeadersSafely, getFullURL, isPerformanceResourceTiming } from './utils';
import { HTTP_REQUEST_METHOD, SERVER_ADDRESS, URL_FRAGMENT, URL_FULL, URL_QUERY } from '@sentry/conventions/attributes';
import {
HTTP_REQUEST_METHOD,
SENTRY_OP,
SERVER_ADDRESS,
URL_FRAGMENT,
URL_FULL,
URL_QUERY,
} from '@sentry/conventions/attributes';
import { HTTP_CLIENT } from '@sentry/conventions/op';

/** Options for Request Instrumentation */
export interface RequestInstrumentationOptions {
Expand Down Expand Up @@ -372,7 +379,7 @@ function xhrCallback(
[URL_FULL]: filterCollectedUrl(sanitizedFullUrl),
[SERVER_ADDRESS]: parsedUrl?.host,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',
[SENTRY_OP]: HTTP_CLIENT,
[URL_QUERY]: filterCollectedUrlQuery(getUrlQuery(parsedUrl?.search)),
[URL_FRAGMENT]: getUrlFragment(parsedUrl?.hash),
},
Expand Down
5 changes: 3 additions & 2 deletions packages/bun/src/integrations/bunserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from '@sentry/core';
import type { ServeOptions } from 'bun';
import {
SENTRY_OP,
SENTRY_SEGMENT_NAME_SOURCE,
URL_DOMAIN,
URL_FRAGMENT,
Expand All @@ -30,6 +31,7 @@ import {
URL_QUERY,
URL_SCHEME,
} from '@sentry/conventions/attributes';
import { HTTP_SERVER } from '@sentry/conventions/op';

const INTEGRATION_NAME = 'BunServer' as const;

Expand Down Expand Up @@ -246,8 +248,7 @@ function wrapRequestHandler<T extends RouteHandler = RouteHandler>(
() =>
startSpan(
{
attributes,
op: 'http.server',
attributes: { ...attributes, [SENTRY_OP]: HTTP_SERVER },
// With span streaming, span names have to be low cardinality, so we can't fall back to the URL path.
name:
attributes[SENTRY_SEGMENT_NAME_SOURCE] === 'route' || !client || !hasSpanStreamingEnabled(client)
Expand Down
Loading
Loading