Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { sentryCloudflareNitroPlugin } from '@sentry/nuxt/module/plugins';

export default defineNitroPlugin(
sentryCloudflareNitroPlugin({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
tracesSampleRate: 1.0,
tunnel: 'http://localhost:3031/', // proxy server
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
import { expect, test } from '@playwright/test';
import { waitForTransaction } from '@sentry-internal/test-utils';
import { collectStreamedSpans, getSpanOp } from '@sentry-internal/test-utils';

// Streamed child spans arrive across several envelopes, so collect until the request's segment
// span and the expected db spans have all been flushed. The streamed segment name is method-only
// (`GET`), so the segment is selected via `url.path`.
function collectDbSpans(minDbSpans: number) {
return collectStreamedSpans(
'nuxt-4-cloudflare',
spans =>
spans.some(span => span.is_segment && span.attributes['url.path']?.value === '/api/db-mysql') &&
spans.filter(span => getSpanOp(span) === 'db').length >= minDbSpans,
);
}

test('a real mysql query emits a db span with orchestrion-channel attributes', async ({ request }) => {
const transactionPromise = waitForTransaction('nuxt-4-cloudflare', transactionEvent => {
return (
transactionEvent.contexts?.trace?.op === 'http.server' &&
(transactionEvent.spans?.some(span => span.op === 'db') ?? false)
);
});
const spansPromise = collectDbSpans(1);

const res = await request.get('/api/db-mysql');
expect(res.status()).toBe(200);

const transactionEvent = await transactionPromise;
const dbSpans = transactionEvent.spans!.filter(span => span.op === 'db');
const spans = await spansPromise;
const rootSpan = spans.find(span => span.is_segment && span.attributes['url.path']?.value === '/api/db-mysql');
expect(rootSpan).toBeDefined();
expect(getSpanOp(rootSpan!)).toBe('http.server');

const dbSpans = spans.filter(span => getSpanOp(span) === 'db' && span.trace_id === rootSpan!.trace_id);

const firstQuery = dbSpans.find(span => span.description === 'SELECT 1 + 1 AS solution');
const firstQuery = dbSpans.find(span => span.attributes['db.query.text']?.value === 'SELECT 1 + 1 AS solution');
expect(firstQuery).toBeDefined();
expect(firstQuery!.data?.['sentry.origin']).toBe('auto.db.mysql');
expect(firstQuery!.data?.['db.system.name']).toBe('mysql');
expect(firstQuery!.data?.['db.query.text']).toBe('SELECT 1 + 1 AS solution');
expect(firstQuery!.data?.['server.address']).toBe('127.0.0.1');
expect(firstQuery!.data?.['server.port']).toBe(3306);
expect(firstQuery!.data?.['db.user']).toBe('root');
expect(firstQuery!.name).toBe('SELECT');
expect(firstQuery!.attributes).toMatchObject({
'sentry.origin': { type: 'string', value: 'auto.db.mysql' },
'db.system.name': { type: 'string', value: 'mysql' },
'db.query.text': { type: 'string', value: 'SELECT 1 + 1 AS solution' },
'server.address': { type: 'string', value: '127.0.0.1' },
'server.port': { type: 'integer', value: 3306 },
'db.user': { type: 'string', value: 'root' },
});
});

test('a nested query lands on the same transaction (async context restored)', async ({ request }) => {
const transactionPromise = waitForTransaction('nuxt-4-cloudflare', transactionEvent => {
return (
transactionEvent.contexts?.trace?.op === 'http.server' &&
(transactionEvent.spans?.filter(span => span.op === 'db').length ?? 0) >= 2
);
});
test('a nested query lands on the same trace (async context restored)', async ({ request }) => {
const spansPromise = collectDbSpans(2);

const res = await request.get('/api/db-mysql');
expect(res.status()).toBe(200);

const transactionEvent = await transactionPromise;
const descriptions = transactionEvent.spans!.filter(span => span.op === 'db').map(span => span.description);
expect(descriptions).toContain('SELECT 1 + 1 AS solution');
expect(descriptions).toContain('SELECT NOW()');
const spans = await spansPromise;
const rootSpan = spans.find(span => span.is_segment && span.attributes['url.path']?.value === '/api/db-mysql');
expect(rootSpan).toBeDefined();

const queryTexts = spans
.filter(span => getSpanOp(span) === 'db' && span.trace_id === rootSpan!.trace_id)
.map(span => span.attributes['db.query.text']?.value);
expect(queryTexts).toContain('SELECT 1 + 1 AS solution');
expect(queryTexts).toContain('SELECT NOW()');
});
Loading