Skip to content

Commit 6e4b593

Browse files
authored
feat(node): Add prismaInstrumentation option to Prisma integration as escape hatch for all Prisma versions (getsentry#15127)
1 parent 2796917 commit 6e4b593

File tree

2 files changed

+110
-45
lines changed

2 files changed

+110
-45
lines changed

docs/migration/v8-to-v9.md

+29-6
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,35 @@ Older Typescript versions _may_ still work, but we will not test them anymore an
107107

108108
- The `childProcessIntegration`'s (previously `processThreadBreadcrumbIntegration`) `name` value has been changed from `"ProcessAndThreadBreadcrumbs"` to `"ChildProcess"`. This is relevant if you were filtering integrations by name.
109109

110-
- The Prisma integration no longer supports Prisma v5. As per Prisma v6, the `previewFeatures = ["tracing"]` client generator option in your Prisma Schema is no longer required to use tracing with the Prisma integration.
111-
112-
For performance instrumentation using Prisma v5:
113-
114-
1. Install the `@prisma/instrumentation` package on version 5
115-
1. Pass a `new PrismaInstrumentation()` instance as exported from `@prisma/instrumentation` to the the `Sentry.init()`'s `openTelemetryInstrumentations` option.
110+
- The Prisma integration no longer supports Prisma v5 and supports Prisma v6 by default. As per Prisma v6, the `previewFeatures = ["tracing"]` client generator option in your Prisma Schema is no longer required to use tracing with the Prisma integration.
111+
112+
For performance instrumentation using other/older Prisma versions:
113+
114+
1. Install the `@prisma/instrumentation` package with the desired version.
115+
1. Pass a `new PrismaInstrumentation()` instance as exported from `@prisma/instrumentation` to the `prismaInstrumentation` option of this integration:
116+
117+
```js
118+
import { PrismaInstrumentation } from '@prisma/instrumentation';
119+
Sentry.init({
120+
integrations: [
121+
prismaIntegration({
122+
// Override the default instrumentation that Sentry uses
123+
prismaInstrumentation: new PrismaInstrumentation(),
124+
}),
125+
],
126+
});
127+
```
128+
129+
The passed instrumentation instance will override the default instrumentation instance the integration would use, while the `prismaIntegration` will still ensure data compatibility for the various Prisma versions.
130+
131+
1. Depending on your Prisma version (prior to Prisma version 6), add `previewFeatures = ["tracing"]` to the client generator block of your Prisma schema:
132+
133+
```
134+
generator client {
135+
provider = "prisma-client-js"
136+
previewFeatures = ["tracing"]
137+
}
138+
```
116139

117140
### `@sentry/browser`
118141

Original file line numberDiff line numberDiff line change
@@ -1,55 +1,97 @@
1+
import type { Instrumentation } from '@opentelemetry/instrumentation';
12
// When importing CJS modules into an ESM module, we cannot import the named exports directly.
23
import * as prismaInstrumentation from '@prisma/instrumentation';
34
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core';
4-
import type { IntegrationFn } from '@sentry/core';
55
import { generateInstrumentOnce } from '../../otel/instrument';
66

77
const INTEGRATION_NAME = 'Prisma';
88

9-
export const instrumentPrisma = generateInstrumentOnce(INTEGRATION_NAME, () => {
10-
const EsmInteropPrismaInstrumentation: typeof prismaInstrumentation.PrismaInstrumentation =
11-
// @ts-expect-error We need to do the following for interop reasons
12-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
13-
prismaInstrumentation.default?.PrismaInstrumentation || prismaInstrumentation.PrismaInstrumentation;
9+
export const instrumentPrisma = generateInstrumentOnce<{ prismaInstrumentation?: Instrumentation }>(
10+
INTEGRATION_NAME,
11+
options => {
12+
// Use a passed instrumentation instance to support older Prisma versions
13+
if (options?.prismaInstrumentation) {
14+
return options.prismaInstrumentation;
15+
}
1416

15-
return new EsmInteropPrismaInstrumentation({});
16-
});
17+
const EsmInteropPrismaInstrumentation: typeof prismaInstrumentation.PrismaInstrumentation =
18+
// @ts-expect-error We need to do the following for interop reasons
19+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
20+
prismaInstrumentation.default?.PrismaInstrumentation || prismaInstrumentation.PrismaInstrumentation;
1721

18-
const _prismaIntegration = (() => {
19-
return {
20-
name: INTEGRATION_NAME,
21-
setupOnce() {
22-
instrumentPrisma();
23-
},
24-
25-
setup(client) {
26-
client.on('spanStart', span => {
27-
const spanJSON = spanToJSON(span);
28-
if (spanJSON.description?.startsWith('prisma:')) {
29-
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma');
30-
}
31-
32-
// Make sure we use the query text as the span name, for ex. SELECT * FROM "User" WHERE "id" = $1
33-
if (spanJSON.description === 'prisma:engine:db_query' && spanJSON.data?.['db.query.text']) {
34-
span.updateName(spanJSON.data['db.query.text'] as string);
35-
}
36-
});
37-
},
38-
};
39-
}) satisfies IntegrationFn;
22+
return new EsmInteropPrismaInstrumentation({});
23+
},
24+
);
4025

4126
/**
4227
* Adds Sentry tracing instrumentation for the [prisma](https://www.npmjs.com/package/prisma) library.
43-
*
4428
* For more information, see the [`prismaIntegration` documentation](https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/).
4529
*
46-
* @example
47-
* ```javascript
48-
* const Sentry = require('@sentry/node');
30+
* NOTE: By default, this integration works with Prisma version 6.
31+
* To get performance instrumentation for other Prisma versions,
32+
* 1. Install the `@prisma/instrumentation` package with the desired version.
33+
* 1. Pass a `new PrismaInstrumentation()` instance as exported from `@prisma/instrumentation` to the `prismaInstrumentation` option of this integration:
34+
*
35+
* ```js
36+
* import { PrismaInstrumentation } from '@prisma/instrumentation'
4937
*
50-
* Sentry.init({
51-
* integrations: [Sentry.prismaIntegration()],
52-
* });
53-
* ```
38+
* Sentry.init({
39+
* integrations: [
40+
* prismaIntegration({
41+
* // Override the default instrumentation that Sentry uses
42+
* prismaInstrumentation: new PrismaInstrumentation()
43+
* })
44+
* ]
45+
* })
46+
* ```
47+
*
48+
* The passed instrumentation instance will override the default instrumentation instance the integration would use, while the `prismaIntegration` will still ensure data compatibility for the various Prisma versions.
49+
* 1. Depending on your Prisma version (prior to version 6), add `previewFeatures = ["tracing"]` to the client generator block of your Prisma schema:
50+
*
51+
* ```
52+
* generator client {
53+
* provider = "prisma-client-js"
54+
* previewFeatures = ["tracing"]
55+
* }
56+
* ```
5457
*/
55-
export const prismaIntegration = defineIntegration(_prismaIntegration);
58+
export const prismaIntegration = defineIntegration(
59+
({
60+
prismaInstrumentation,
61+
}: {
62+
/**
63+
* Overrides the instrumentation used by the Sentry SDK with the passed in instrumentation instance.
64+
*
65+
* NOTE: By default, the Sentry SDK uses the Prisma v6 instrumentation. Use this option if you need performance instrumentation different Prisma versions.
66+
*
67+
* For more information refer to the documentation of `prismaIntegration()` or see https://docs.sentry.io/platforms/javascript/guides/node/configuration/integrations/prisma/
68+
*/
69+
prismaInstrumentation?: Instrumentation;
70+
} = {}) => {
71+
return {
72+
name: INTEGRATION_NAME,
73+
setupOnce() {
74+
instrumentPrisma({ prismaInstrumentation });
75+
},
76+
setup(client) {
77+
client.on('spanStart', span => {
78+
const spanJSON = spanToJSON(span);
79+
if (spanJSON.description?.startsWith('prisma:')) {
80+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma');
81+
}
82+
83+
// Make sure we use the query text as the span name, for ex. SELECT * FROM "User" WHERE "id" = $1
84+
if (spanJSON.description === 'prisma:engine:db_query' && spanJSON.data['db.query.text']) {
85+
span.updateName(spanJSON.data['db.query.text'] as string);
86+
}
87+
88+
// In Prisma v5.22+, the `db.system` attribute is automatically set
89+
// On older versions, this is missing, so we add it here
90+
if (spanJSON.description === 'prisma:engine:db_query' && !spanJSON.data['db.system']) {
91+
span.setAttribute('db.system', 'prisma');
92+
}
93+
});
94+
},
95+
};
96+
},
97+
);

0 commit comments

Comments
 (0)