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' ;
54
65import { shouldDisableAutoInstrumentation } from './utils/node-utils' ;
76
@@ -36,6 +35,7 @@ type PrismaMiddleware<T = unknown> = (
3635) => Promise < T > ;
3736
3837interface PrismaClient {
38+ _sentryInstrumented ?: boolean ;
3939 $use : ( cb : PrismaMiddleware ) => void ;
4040}
4141
@@ -55,17 +55,30 @@ export class Prisma implements Integration {
5555 */
5656 public name : string = Prisma . id ;
5757
58- /**
59- * Prisma ORM Client Instance
60- */
61- private readonly _client ?: PrismaClient ;
62-
6358 /**
6459 * @inheritDoc
6560 */
6661 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+ } ) ;
6982 } else {
7083 __DEBUG_BUILD__ &&
7184 logger . warn (
@@ -77,24 +90,7 @@ export class Prisma implements Integration {
7790 /**
7891 * @inheritDoc
7992 */
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
9995 }
10096}
0 commit comments