1717 * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/15ef7506553f631ea4181391e0c5725a56f0d082/packages/instrumentation-koa
1818 * - Upstream version: @opentelemetry/instrumentation-koa@0.66.0
1919 * - Minor TypeScript strictness adjustments for this repository's compiler settings
20+ * - Span creation migrated to the @sentry/core API; op/origin/name and transaction name folded into
21+ * span creation (previously set via a Sentry requestHook)
2022 */
21- /* eslint-disable */
2223
2324import * as api from '@opentelemetry/api' ;
25+ import { isWrapped , InstrumentationBase , InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation' ;
26+
27+ import { KoaLayerType , type KoaInstrumentationConfig } from './types' ;
2428import {
25- isWrapped ,
26- InstrumentationBase ,
27- InstrumentationNodeModuleDefinition ,
28- safeExecuteInTheMiddle ,
29- } from '@opentelemetry/instrumentation' ;
30-
31- import { KoaLayerType , KoaInstrumentationConfig } from './types ' ;
32- import { SDK_VERSION } from '@sentry/core ' ;
29+ debug ,
30+ getDefaultIsolationScope ,
31+ getIsolationScope ,
32+ SDK_VERSION ,
33+ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ,
34+ startSpan ,
35+ } from '@sentry/core ' ;
36+ import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions ' ;
3337import { getMiddlewareMetadata , isLayerIgnored } from './utils' ;
3438import { setHttpServerSpanRouteAttribute } from '../../../../utils/setHttpServerSpanRouteAttribute' ;
35- import { Next , kLayerPatched , KoaContext , KoaMiddleware , KoaPatchedMiddleware } from './internal-types' ;
39+ import { DEBUG_BUILD } from '../../../../debug-build' ;
40+ import { AttributeNames } from './enums/AttributeNames' ;
41+ import {
42+ kLayerPatched ,
43+ type Next ,
44+ type KoaContext ,
45+ type KoaMiddleware ,
46+ type KoaPatchedMiddleware ,
47+ } from './internal-types' ;
3648
3749const PACKAGE_NAME = '@sentry/instrumentation-koa' ;
3850
51+ interface KoaModuleExports {
52+ prototype : { use : KoaMiddleware } ;
53+ }
54+
55+ type KoaModule = KoaModuleExports & { [ Symbol . toStringTag ] ?: string ; default ?: KoaModuleExports } ;
56+
3957/** Koa instrumentation for OpenTelemetry */
4058export class KoaInstrumentation extends InstrumentationBase < KoaInstrumentationConfig > {
4159 constructor ( config : KoaInstrumentationConfig = { } ) {
@@ -46,11 +64,8 @@ export class KoaInstrumentation extends InstrumentationBase<KoaInstrumentationCo
4664 return new InstrumentationNodeModuleDefinition (
4765 'koa' ,
4866 [ '>=2.0.0 <4' ] ,
49- ( module : any ) => {
50- const moduleExports : any =
51- module [ Symbol . toStringTag ] === 'Module'
52- ? module . default // ESM
53- : module ; // CommonJS
67+ ( module : KoaModule ) => {
68+ const moduleExports = module [ Symbol . toStringTag ] === 'Module' ? module . default : module ;
5469 if ( moduleExports == null ) {
5570 return moduleExports ;
5671 }
@@ -60,12 +75,9 @@ export class KoaInstrumentation extends InstrumentationBase<KoaInstrumentationCo
6075 this . _wrap ( moduleExports . prototype , 'use' , this . _getKoaUsePatch . bind ( this ) ) ;
6176 return module ;
6277 } ,
63- ( module : any ) => {
64- const moduleExports : any =
65- module [ Symbol . toStringTag ] === 'Module'
66- ? module . default // ESM
67- : module ; // CommonJS
68- if ( isWrapped ( moduleExports . prototype . use ) ) {
78+ ( module : KoaModule ) => {
79+ const moduleExports = module [ Symbol . toStringTag ] === 'Module' ? module . default : module ;
80+ if ( moduleExports && isWrapped ( moduleExports . prototype . use ) ) {
6981 this . _unwrap ( moduleExports . prototype , 'use' ) ;
7082 }
7183 } ,
@@ -77,15 +89,13 @@ export class KoaInstrumentation extends InstrumentationBase<KoaInstrumentationCo
7789 * middleware layer which is introduced
7890 * @param {KoaMiddleware } middleware - the original middleware function
7991 */
80- private _getKoaUsePatch ( original : ( middleware : KoaMiddleware ) => any ) {
81- const plugin = this ;
82- return function use ( this : any , middlewareFunction : KoaMiddleware ) {
83- let patchedFunction : KoaMiddleware ;
84- if ( middlewareFunction . router ) {
85- patchedFunction = plugin . _patchRouterDispatch ( middlewareFunction ) ;
86- } else {
87- patchedFunction = plugin . _patchLayer ( middlewareFunction , false ) ;
88- }
92+ private _getKoaUsePatch ( original : ( middleware : KoaMiddleware ) => unknown ) {
93+ const patchRouterDispatch = this . _patchRouterDispatch . bind ( this ) ;
94+ const patchLayer = this . _patchLayer . bind ( this ) ;
95+ return function use ( this : unknown , middlewareFunction : KoaMiddleware ) {
96+ const patchedFunction = middlewareFunction . router
97+ ? patchRouterDispatch ( middlewareFunction )
98+ : patchLayer ( middlewareFunction , false ) ;
8999 return original . apply ( this , [ patchedFunction ] ) ;
90100 } ;
91101 }
@@ -107,9 +117,9 @@ export class KoaInstrumentation extends InstrumentationBase<KoaInstrumentationCo
107117 const path = pathLayer . path ;
108118 // Type cast needed: router.stack comes from @types /koa@2.x but we use @types/koa@3.x
109119 // See internal-types.ts for full explanation
110- const pathStack = pathLayer . stack as any ;
120+ const pathStack = pathLayer . stack as KoaMiddleware [ ] ;
111121 for ( let j = 0 ; j < pathStack . length ; j ++ ) {
112- const routedMiddleware : KoaMiddleware = pathStack [ j ] ;
122+ const routedMiddleware = pathStack [ j ] as KoaMiddleware ;
113123 pathStack [ j ] = this . _patchLayer ( routedMiddleware , true , path ) ;
114124 }
115125 }
@@ -146,49 +156,40 @@ export class KoaInstrumentation extends InstrumentationBase<KoaInstrumentationCo
146156 middlewareLayer [ kLayerPatched ] = true ;
147157
148158 api . diag . debug ( 'patching Koa middleware layer' ) ;
149- return async ( context : KoaContext , next : Next ) => {
159+ return ( context : KoaContext , next : Next ) => {
150160 const parent = api . trace . getSpan ( api . context . active ( ) ) ;
151161 if ( parent === undefined ) {
152162 return middlewareLayer ( context , next ) ;
153163 }
154164 const metadata = getMiddlewareMetadata ( context , middlewareLayer , isRouter , layerPath ) ;
155- const span = this . tracer . startSpan ( metadata . name , {
156- attributes : metadata . attributes ,
157- } ) ;
158165
159166 if ( context . _matchedRoute ) {
160167 setHttpServerSpanRouteAttribute ( context . _matchedRoute . toString ( ) ) ;
161168 }
162169
163- const { requestHook } = this . getConfig ( ) ;
164- if ( requestHook ) {
165- safeExecuteInTheMiddle (
166- ( ) =>
167- requestHook ( span , {
168- context,
169- middlewareLayer,
170- layerType,
171- } ) ,
172- e => {
173- if ( e ) {
174- api . diag . error ( 'koa instrumentation: request hook failed' , e ) ;
175- }
176- } ,
177- true ,
178- ) ;
179- }
170+ const koaName = metadata . attributes [ AttributeNames . KOA_NAME ] ;
171+ const name = typeof koaName === 'string' ? koaName || '< unknown >' : metadata . name ;
180172
181- const newContext = api . trace . setSpan ( api . context . active ( ) , span ) ;
182- return api . context . with ( newContext , async ( ) => {
183- try {
184- return await middlewareLayer ( context , next ) ;
185- } catch ( err : any ) {
186- span . recordException ( err ) ;
187- throw err ;
188- } finally {
189- span . end ( ) ;
190- }
191- } ) ;
173+ return startSpan (
174+ {
175+ name,
176+ op : `${ layerType } .koa` ,
177+ attributes : {
178+ ...metadata . attributes ,
179+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.http.otel.koa' ,
180+ } ,
181+ } ,
182+ ( ) => {
183+ const route = metadata . attributes [ ATTR_HTTP_ROUTE ] ;
184+ if ( getIsolationScope ( ) === getDefaultIsolationScope ( ) ) {
185+ DEBUG_BUILD && debug . warn ( 'Isolation scope is default isolation scope - skipping setting transactionName' ) ;
186+ } else if ( route ) {
187+ const method = ( context . request as { method ?: string } | undefined ) ?. method ?. toUpperCase ( ) || 'GET' ;
188+ getIsolationScope ( ) . setTransactionName ( `${ method } ${ route } ` ) ;
189+ }
190+ return middlewareLayer ( context , next ) ;
191+ } ,
192+ ) ;
192193 } ;
193194 }
194195}
0 commit comments