1
- import type { Hub } from '@sentry/core' ;
2
- import { trace } from '@sentry/core' ;
3
- import type { EventProcessor , Integration } from '@sentry/types' ;
4
- import { logger } from '@sentry/utils' ;
1
+ import { getCurrentHub , trace } from '@sentry/core' ;
2
+ import type { Integration } from '@sentry/types' ;
3
+ import { addNonEnumerableProperty , logger } from '@sentry/utils' ;
5
4
6
5
import { shouldDisableAutoInstrumentation } from './utils/node-utils' ;
7
6
@@ -36,6 +35,7 @@ type PrismaMiddleware<T = unknown> = (
36
35
) => Promise < T > ;
37
36
38
37
interface PrismaClient {
38
+ _sentryInstrumented ?: boolean ;
39
39
$use : ( cb : PrismaMiddleware ) => void ;
40
40
}
41
41
@@ -55,17 +55,30 @@ export class Prisma implements Integration {
55
55
*/
56
56
public name : string = Prisma . id ;
57
57
58
- /**
59
- * Prisma ORM Client Instance
60
- */
61
- private readonly _client ?: PrismaClient ;
62
-
63
58
/**
64
59
* @inheritDoc
65
60
*/
66
61
public constructor ( options : { client ?: unknown } = { } ) {
67
- if ( isValidPrismaClient ( options . client ) ) {
68
- this . _client = options . client ;
62
+ // We instrument the PrismaClient inside the constructor and not inside `setupOnce` because in some cases of server-side
63
+ // bundling (Next.js) multiple Prisma clients can be instantiated, even though users don't intend to. When instrumenting
64
+ // in setupOnce we can only ever instrument one client.
65
+ // https://github.com/getsentry/sentry-javascript/issues/7216#issuecomment-1602375012
66
+ // In the future we might explore providing a dedicated PrismaClient middleware instead of this hack.
67
+ if ( isValidPrismaClient ( options . client ) && ! options . client . _sentryInstrumented ) {
68
+ addNonEnumerableProperty ( options . client as any , '_sentryInstrumented' , true ) ;
69
+
70
+ options . client . $use ( ( params , next : ( params : PrismaMiddlewareParams ) => Promise < unknown > ) => {
71
+ if ( shouldDisableAutoInstrumentation ( getCurrentHub ) ) {
72
+ return next ( params ) ;
73
+ }
74
+
75
+ const action = params . action ;
76
+ const model = params . model ;
77
+ return trace (
78
+ { name : model ? `${ model } ${ action } ` : action , op : 'db.sql.prisma' , data : { 'db.system' : 'prisma' } } ,
79
+ ( ) => next ( params ) ,
80
+ ) ;
81
+ } ) ;
69
82
} else {
70
83
__DEBUG_BUILD__ &&
71
84
logger . warn (
@@ -77,24 +90,7 @@ export class Prisma implements Integration {
77
90
/**
78
91
* @inheritDoc
79
92
*/
80
- public setupOnce ( _ : ( callback : EventProcessor ) => void , getCurrentHub : ( ) => Hub ) : void {
81
- if ( ! this . _client ) {
82
- __DEBUG_BUILD__ && logger . error ( 'PrismaIntegration is missing a Prisma Client Instance' ) ;
83
- return ;
84
- }
85
-
86
- if ( shouldDisableAutoInstrumentation ( getCurrentHub ) ) {
87
- __DEBUG_BUILD__ && logger . log ( 'Prisma Integration is skipped because of instrumenter configuration.' ) ;
88
- return ;
89
- }
90
-
91
- this . _client . $use ( ( params , next : ( params : PrismaMiddlewareParams ) => Promise < unknown > ) => {
92
- const action = params . action ;
93
- const model = params . model ;
94
- return trace (
95
- { name : model ? `${ model } ${ action } ` : action , op : 'db.sql.prisma' , data : { 'db.system' : 'prisma' } } ,
96
- ( ) => next ( params ) ,
97
- ) ;
98
- } ) ;
93
+ public setupOnce ( ) : void {
94
+ // Noop - here for backwards compatibility
99
95
}
100
96
}
0 commit comments