@@ -16,7 +16,11 @@ import {
16
16
import type { SpanAttributes , TransactionSource } from '@sentry/types' ;
17
17
import { getSanitizedUrlString , parseUrl , stripUrlQueryAndFragment } from '@sentry/utils' ;
18
18
19
- import { SEMANTIC_ATTRIBUTE_SENTRY_OP , SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core' ;
19
+ import {
20
+ SEMANTIC_ATTRIBUTE_SENTRY_OP ,
21
+ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
22
+ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
23
+ } from '@sentry/core' ;
20
24
import { SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION } from '../semanticAttributes' ;
21
25
import type { AbstractSpan } from '../types' ;
22
26
import { getSpanKind } from './getSpanKind' ;
@@ -32,12 +36,12 @@ interface SpanDescription {
32
36
/**
33
37
* Infer the op & description for a set of name, attributes and kind of a span.
34
38
*/
35
- export function inferSpanData ( name : string , attributes : SpanAttributes , kind : SpanKind ) : SpanDescription {
39
+ export function inferSpanData ( originalName : string , attributes : SpanAttributes , kind : SpanKind ) : SpanDescription {
36
40
// if http.method exists, this is an http request span
37
41
// eslint-disable-next-line deprecation/deprecation
38
42
const httpMethod = attributes [ ATTR_HTTP_REQUEST_METHOD ] || attributes [ SEMATTRS_HTTP_METHOD ] ;
39
43
if ( httpMethod ) {
40
- return descriptionForHttpMethod ( { attributes, name, kind } , httpMethod ) ;
44
+ return descriptionForHttpMethod ( { attributes, name : originalName , kind } , httpMethod ) ;
41
45
}
42
46
43
47
// eslint-disable-next-line deprecation/deprecation
@@ -49,17 +53,19 @@ export function inferSpanData(name: string, attributes: SpanAttributes, kind: Sp
49
53
// If db.type exists then this is a database call span
50
54
// If the Redis DB is used as a cache, the span description should not be changed
51
55
if ( dbSystem && ! opIsCache ) {
52
- return descriptionForDbSystem ( { attributes, name } ) ;
56
+ return descriptionForDbSystem ( { attributes, name : originalName } ) ;
53
57
}
54
58
59
+ const customSourceOrRoute = attributes [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] === 'custom' ? 'custom' : 'route' ;
60
+
55
61
// If rpc.service exists then this is a rpc call span.
56
62
// eslint-disable-next-line deprecation/deprecation
57
63
const rpcService = attributes [ SEMATTRS_RPC_SERVICE ] ;
58
64
if ( rpcService ) {
59
65
return {
60
66
op : 'rpc' ,
61
- description : name ,
62
- source : 'route' ,
67
+ description : originalName ,
68
+ source : customSourceOrRoute ,
63
69
} ;
64
70
}
65
71
@@ -69,24 +75,28 @@ export function inferSpanData(name: string, attributes: SpanAttributes, kind: Sp
69
75
if ( messagingSystem ) {
70
76
return {
71
77
op : 'message' ,
72
- description : name ,
73
- source : 'route' ,
78
+ description : originalName ,
79
+ source : customSourceOrRoute ,
74
80
} ;
75
81
}
76
82
77
83
// If faas.trigger exists then this is a function as a service span.
78
84
// eslint-disable-next-line deprecation/deprecation
79
85
const faasTrigger = attributes [ SEMATTRS_FAAS_TRIGGER ] ;
80
86
if ( faasTrigger ) {
81
- return { op : faasTrigger . toString ( ) , description : name , source : 'route' } ;
87
+ return { op : faasTrigger . toString ( ) , description : originalName , source : customSourceOrRoute } ;
82
88
}
83
89
84
- return { op : undefined , description : name , source : 'custom' } ;
90
+ return { op : undefined , description : originalName , source : 'custom' } ;
85
91
}
86
92
87
93
/**
88
94
* Extract better op/description from an otel span.
89
95
*
96
+ * Does not overwrite the span name if the source is already set to custom to ensure
97
+ * that user-updated span names are preserved. In this case, we only adjust the op but
98
+ * leave span description and source unchanged.
99
+ *
90
100
* Based on https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/7422ce2a06337f68a59b552b8c5a2ac125d6bae5/exporter/sentryexporter/sentry_exporter.go#L306
91
101
*/
92
102
export function parseSpanDescription ( span : AbstractSpan ) : SpanDescription {
@@ -98,6 +108,11 @@ export function parseSpanDescription(span: AbstractSpan): SpanDescription {
98
108
}
99
109
100
110
function descriptionForDbSystem ( { attributes, name } : { attributes : Attributes ; name : string } ) : SpanDescription {
111
+ // if we already set the source to custom, we don't overwrite the span description but just adjust the op
112
+ if ( attributes [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] === 'custom' ) {
113
+ return { op : 'db' , description : name , source : 'custom' } ;
114
+ }
115
+
101
116
// Use DB statement (Ex "SELECT * FROM table") if possible as description.
102
117
// eslint-disable-next-line deprecation/deprecation
103
118
const statement = attributes [ SEMATTRS_DB_STATEMENT ] ;
@@ -170,7 +185,10 @@ export function descriptionForHttpMethod(
170
185
const origin = attributes [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] || 'manual' ;
171
186
const isManualSpan = ! `${ origin } ` . startsWith ( 'auto' ) ;
172
187
173
- const useInferredDescription = isClientOrServerKind || ! isManualSpan ;
188
+ // If users (or in very rare occasions we) set the source to custom, we don't overwrite it
189
+ const alreadyHasCustomSource = attributes [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] === 'custom' ;
190
+
191
+ const useInferredDescription = ! alreadyHasCustomSource && ( isClientOrServerKind || ! isManualSpan ) ;
174
192
175
193
return {
176
194
op : opParts . join ( '.' ) ,
0 commit comments