1
1
import { WINDOW , captureException } from '@sentry/browser' ;
2
- import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , spanToJSON } from '@sentry/core' ;
3
- import type { Transaction , TransactionContext , TransactionSource } from '@sentry/types' ;
2
+ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN , SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , spanToJSON } from '@sentry/core' ;
3
+ import type { SpanAttributes , Transaction , TransactionContext , TransactionSource } from '@sentry/types' ;
4
4
5
5
import { getActiveTransaction } from './tracing' ;
6
6
@@ -50,6 +50,8 @@ interface VueRouter {
50
50
* * `routeLabel`: Set this to `route` to opt-out of using `route.name` for transaction names.
51
51
*
52
52
* @param router The Vue Router instance that is used
53
+ *
54
+ * @deprecated Use `browserTracingIntegration()` from `@sentry/vue` instead - this includes the vue router instrumentation.
53
55
*/
54
56
export function vueRouterInstrumentation (
55
57
router : VueRouter ,
@@ -60,10 +62,6 @@ export function vueRouterInstrumentation(
60
62
startTransactionOnPageLoad : boolean = true ,
61
63
startTransactionOnLocationChange : boolean = true ,
62
64
) => {
63
- const tags = {
64
- 'routing.instrumentation' : 'vue-router' ,
65
- } ;
66
-
67
65
// We have to start the pageload transaction as early as possible (before the router's `beforeEach` hook
68
66
// is called) to not miss child spans of the pageload.
69
67
// We check that window & window.location exists in order to not run this code in SSR environments.
@@ -72,76 +70,105 @@ export function vueRouterInstrumentation(
72
70
name : WINDOW . location . pathname ,
73
71
op : 'pageload' ,
74
72
origin : 'auto.pageload.vue' ,
75
- tags ,
76
- data : {
73
+ attributes : {
74
+ 'routing.instrumentation' : 'vue-router' ,
77
75
[ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : 'url' ,
78
76
} ,
79
77
} ) ;
80
78
}
81
79
82
- router . onError ( error => captureException ( error , { mechanism : { handled : false } } ) ) ;
83
-
84
- router . beforeEach ( ( to , from , next ) => {
85
- // According to docs we could use `from === VueRouter.START_LOCATION` but I couldnt get it working for Vue 2
86
- // https://router.vuejs.org/api/#router-start-location
87
- // https://next.router.vuejs.org/api/#start-location
88
-
89
- // from.name:
90
- // - Vue 2: null
91
- // - Vue 3: undefined
92
- // hence only '==' instead of '===', because `undefined == null` evaluates to `true`
93
- const isPageLoadNavigation = from . name == null && from . matched . length === 0 ;
94
-
95
- const data : Record < string , unknown > = {
96
- params : to . params ,
97
- query : to . query ,
98
- } ;
99
-
100
- // Determine a name for the routing transaction and where that name came from
101
- let transactionName : string = to . path ;
102
- let transactionSource : TransactionSource = 'url' ;
103
- if ( to . name && options . routeLabel !== 'path' ) {
104
- transactionName = to . name . toString ( ) ;
105
- transactionSource = 'custom' ;
106
- } else if ( to . matched [ 0 ] && to . matched [ 0 ] . path ) {
107
- transactionName = to . matched [ 0 ] . path ;
108
- transactionSource = 'route' ;
80
+ instrumentVueRouter (
81
+ router ,
82
+ {
83
+ routeLabel : options . routeLabel || 'name' ,
84
+ instrumentNavigation : startTransactionOnLocationChange ,
85
+ instrumentPageLoad : startTransactionOnPageLoad ,
86
+ } ,
87
+ startTransaction ,
88
+ ) ;
89
+ } ;
90
+ }
91
+
92
+ /**
93
+ * Instrument the Vue router to create navigation spans.
94
+ */
95
+ export function instrumentVueRouter (
96
+ router : VueRouter ,
97
+ options : {
98
+ routeLabel : 'name' | 'path' ;
99
+ instrumentPageLoad : boolean ;
100
+ instrumentNavigation : boolean ;
101
+ } ,
102
+ startNavigationSpanFn : ( context : TransactionContext ) => void ,
103
+ ) : void {
104
+ router . onError ( error => captureException ( error , { mechanism : { handled : false } } ) ) ;
105
+
106
+ router . beforeEach ( ( to , from , next ) => {
107
+ // According to docs we could use `from === VueRouter.START_LOCATION` but I couldnt get it working for Vue 2
108
+ // https://router.vuejs.org/api/#router-start-location
109
+ // https://next.router.vuejs.org/api/#start-location
110
+
111
+ // from.name:
112
+ // - Vue 2: null
113
+ // - Vue 3: undefined
114
+ // hence only '==' instead of '===', because `undefined == null` evaluates to `true`
115
+ const isPageLoadNavigation = from . name == null && from . matched . length === 0 ;
116
+
117
+ const attributes : SpanAttributes = {
118
+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.navigation.vue' ,
119
+ 'routing.instrumentation' : 'vue-router' ,
120
+ } ;
121
+
122
+ for ( const key of Object . keys ( to . params ) ) {
123
+ attributes [ `params.${ key } ` ] = to . params [ key ] ;
124
+ }
125
+ for ( const key of Object . keys ( to . query ) ) {
126
+ const value = to . query [ key ] ;
127
+ if ( value ) {
128
+ attributes [ `query.${ key } ` ] = value ;
109
129
}
130
+ }
110
131
111
- if ( startTransactionOnPageLoad && isPageLoadNavigation ) {
112
- // eslint-disable-next-line deprecation/deprecation
113
- const pageloadTransaction = getActiveTransaction ( ) ;
114
- if ( pageloadTransaction ) {
115
- const attributes = spanToJSON ( pageloadTransaction ) . data || { } ;
116
- if ( attributes [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] !== 'custom' ) {
117
- pageloadTransaction . updateName ( transactionName ) ;
118
- pageloadTransaction . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , transactionSource ) ;
119
- }
120
- // TODO: We need to flatten these to make them attributes
121
- // eslint-disable-next-line deprecation/deprecation
122
- pageloadTransaction . setData ( 'params' , data . params ) ;
123
- // eslint-disable-next-line deprecation/deprecation
124
- pageloadTransaction . setData ( 'query' , data . query ) ;
132
+ // Determine a name for the routing transaction and where that name came from
133
+ let transactionName : string = to . path ;
134
+ let transactionSource : TransactionSource = 'url' ;
135
+ if ( to . name && options . routeLabel !== 'path' ) {
136
+ transactionName = to . name . toString ( ) ;
137
+ transactionSource = 'custom' ;
138
+ } else if ( to . matched [ 0 ] && to . matched [ 0 ] . path ) {
139
+ transactionName = to . matched [ 0 ] . path ;
140
+ transactionSource = 'route' ;
141
+ }
142
+
143
+ if ( options . instrumentPageLoad && isPageLoadNavigation ) {
144
+ // eslint-disable-next-line deprecation/deprecation
145
+ const pageloadTransaction = getActiveTransaction ( ) ;
146
+ if ( pageloadTransaction ) {
147
+ const existingAttributes = spanToJSON ( pageloadTransaction ) . data || { } ;
148
+ if ( existingAttributes [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] !== 'custom' ) {
149
+ pageloadTransaction . updateName ( transactionName ) ;
150
+ pageloadTransaction . setAttribute ( SEMANTIC_ATTRIBUTE_SENTRY_SOURCE , transactionSource ) ;
125
151
}
152
+ // Set router attributes on the existing pageload transaction
153
+ // This will the origin, and add params & query attributes
154
+ pageloadTransaction . setAttributes ( attributes ) ;
126
155
}
156
+ }
127
157
128
- if ( startTransactionOnLocationChange && ! isPageLoadNavigation ) {
129
- data [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] = transactionSource ;
130
- startTransaction ( {
131
- name : transactionName ,
132
- op : 'navigation' ,
133
- origin : 'auto.navigation.vue' ,
134
- tags,
135
- data,
136
- } ) ;
137
- }
158
+ if ( options . instrumentNavigation && ! isPageLoadNavigation ) {
159
+ attributes [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] = transactionSource ;
160
+ startNavigationSpanFn ( {
161
+ name : transactionName ,
162
+ op : 'navigation' ,
163
+ attributes,
164
+ } ) ;
165
+ }
138
166
139
- // Vue Router 4 no longer exposes the `next` function, so we need to
140
- // check if it's available before calling it.
141
- // `next` needs to be called in Vue Router 3 so that the hook is resolved.
142
- if ( next ) {
143
- next ( ) ;
144
- }
145
- } ) ;
146
- } ;
167
+ // Vue Router 4 no longer exposes the `next` function, so we need to
168
+ // check if it's available before calling it.
169
+ // `next` needs to be called in Vue Router 3 so that the hook is resolved.
170
+ if ( next ) {
171
+ next ( ) ;
172
+ }
173
+ } ) ;
147
174
}
0 commit comments