diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/scenario.js b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/scenario.js index 7f291290bea2..82fbc044b973 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/scenario.js @@ -1,6 +1,3 @@ -const { randomBytes } = require('crypto'); -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -const { PrismaClient } = require('@prisma/client'); const Sentry = require('@sentry/node'); const { loggingTransport } = require('@sentry-internal/node-integration-tests'); @@ -12,6 +9,9 @@ Sentry.init({ integrations: [Sentry.prismaIntegration()], }); +const { randomBytes } = require('crypto'); +const { PrismaClient } = require('@prisma/client'); + // Stop the process from exiting before the transaction is sent setInterval(() => {}, 1000); @@ -49,5 +49,4 @@ async function run() { ); } -// eslint-disable-next-line @typescript-eslint/no-floating-promises run(); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts index 32bcdf168555..3c96c6d80779 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts @@ -7,100 +7,104 @@ conditionalTest({ min: 16 })('Prisma ORM Tests', () => { transaction: 'Test Transaction', spans: expect.arrayContaining([ expect.objectContaining({ - data: expect.objectContaining({ + data: { method: 'create', model: 'User', name: 'User.create', 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:client:operation', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:client:serialize', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:client:connect', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:engine', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'db.type': 'postgres', 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:engine:connection', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'db.statement': expect.stringContaining( 'INSERT INTO "public"."User" ("createdAt","email","name") VALUES ($1,$2,$3) RETURNING "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" /* traceparent', ), 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), - description: 'prisma:engine:db_query', + 'sentry.origin': 'auto.db.otel.prisma', + 'db.system': 'prisma', + 'sentry.op': 'db', + }, + description: expect.stringContaining( + 'INSERT INTO "public"."User" ("createdAt","email","name") VALUES ($1,$2,$3) RETURNING "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" /* traceparent', + ), status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:engine:serialize', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:engine:response_json_serialization', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { method: 'findMany', model: 'User', name: 'User.findMany', 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:client:operation', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:client:serialize', status: 'ok', }), expect.objectContaining({ - data: expect.objectContaining({ + data: { 'otel.kind': 'INTERNAL', - 'sentry.origin': 'manual', - }), + 'sentry.origin': 'auto.db.otel.prisma', + }, description: 'prisma:engine', status: 'ok', }), diff --git a/packages/node/src/integrations/tracing/prisma.ts b/packages/node/src/integrations/tracing/prisma.ts index 13e51065dce8..7652ea793530 100644 --- a/packages/node/src/integrations/tracing/prisma.ts +++ b/packages/node/src/integrations/tracing/prisma.ts @@ -1,6 +1,6 @@ // When importing CJS modules into an ESM module, we cannot import the named exports directly. import * as prismaInstrumentation from '@prisma/instrumentation'; -import { defineIntegration } from '@sentry/core'; +import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration, spanToJSON } from '@sentry/core'; import { addOpenTelemetryInstrumentation } from '@sentry/opentelemetry'; import type { IntegrationFn } from '@sentry/types'; @@ -13,6 +13,19 @@ const _prismaIntegration = (() => { new prismaInstrumentation.PrismaInstrumentation({}), ); }, + + setup(client) { + client.on('spanStart', span => { + const spanJSON = spanToJSON(span); + if (spanJSON.description?.startsWith('prisma:')) { + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma'); + } + + if (spanJSON.description === 'prisma:engine:db_query') { + span.setAttribute('db.system', 'prisma'); + } + }); + }, }; }) satisfies IntegrationFn;