Skip to content
Open
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
@@ -1,7 +1,6 @@
import * as Sentry from '@sentry/astro';

Sentry.init({
traceLifecycle: 'static',
dsn: import.meta.env.PUBLIC_E2E_TEST_DSN,
environment: 'qa',
tracesSampleRate: 1.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import handler from '@astrojs/cloudflare/entrypoints/server';

export default Sentry.withSentry(
env => ({
traceLifecycle: 'static',
dsn: env.E2E_TEST_DSN,
environment: 'qa',
tracesSampleRate: 1.0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,40 @@
import { expect, test } from '@playwright/test';
import { waitForTransaction } from '@sentry-internal/test-utils';
import { collectStreamedSpansUntilSegment, getSpanOp } from '@sentry-internal/test-utils';

const APP_NAME = 'astro-6-cf-workers';

test('a real mysql query emits a db span with orchestrion-channel attributes', async ({ request }) => {
const transactionPromise = waitForTransaction('astro-6-cf-workers', transactionEvent => {
return (
transactionEvent.contexts?.trace?.op === 'http.server' &&
(transactionEvent.spans?.some(span => span.op === 'db') ?? false)
);
});
const spansPromise = collectStreamedSpansUntilSegment(APP_NAME, 'GET /db-mysql');

const res = await request.get('/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 dbSpans = spans.filter(span => getSpanOp(span) === 'db');

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');
// With span streaming the span name is the low-cardinality query summary; the statement stays in
// `db.query.text`.
expect(firstQuery!.name).toBe('SELECT');
expect(firstQuery!.attributes['sentry.origin']?.value).toBe('auto.db.mysql');
expect(firstQuery!.attributes['db.system.name']?.value).toBe('mysql');
expect(firstQuery!.attributes['db.query.text']?.value).toBe('SELECT 1 + 1 AS solution');
expect(firstQuery!.attributes['server.address']?.value).toBe('127.0.0.1');
expect(firstQuery!.attributes['server.port']?.value).toBe(3306);
expect(firstQuery!.attributes['db.user']?.value).toBe('root');
});

test('a nested query lands on the same transaction (async context restored)', async ({ request }) => {
const transactionPromise = waitForTransaction('astro-6-cf-workers', 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 = collectStreamedSpansUntilSegment(APP_NAME, 'GET /db-mysql');

const res = await request.get('/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 queryTexts = spans
.filter(span => getSpanOp(span) === 'db')
.map(span => span.attributes['db.query.text']?.value);
expect(queryTexts).toContain('SELECT 1 + 1 AS solution');
expect(queryTexts).toContain('SELECT NOW()');
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { expect, test } from '@playwright/test';
import { waitForError, waitForTransaction } from '@sentry-internal/test-utils';
import { getSpanOp, waitForError, waitForStreamedSpan } from '@sentry-internal/test-utils';

test.describe('server-side errors', () => {
test('captures SSR error', async ({ page }) => {
const errorEventPromise = waitForError('astro-6-cf-workers', errorEvent => {
return errorEvent?.exception?.values?.[0]?.value === "Cannot read properties of undefined (reading 'x')";
});

const transactionEventPromise = waitForTransaction('astro-6-cf-workers', transactionEvent => {
return transactionEvent.transaction === 'GET /ssr-error';
const spanPromise = waitForStreamedSpan('astro-6-cf-workers', span => {
return getSpanOp(span) === 'http.server' && span.is_segment && span.name === 'GET /ssr-error';
});

// This page returns an error status code, so we need to catch the navigation error
Expand All @@ -17,19 +17,14 @@ test.describe('server-side errors', () => {
});

const errorEvent = await errorEventPromise;
const transactionEvent = await transactionEventPromise;
const span = await spanPromise;

expect(transactionEvent).toMatchObject({
transaction: 'GET /ssr-error',
spans: [],
});

const traceId = transactionEvent.contexts?.trace?.trace_id;
const spanId = transactionEvent.contexts?.trace?.span_id;
const traceId = span.trace_id;
const spanId = span.span_id;

expect(traceId).toMatch(/[a-f0-9]{32}/);
expect(spanId).toMatch(/[a-f0-9]{16}/);
expect(transactionEvent.contexts?.trace?.parent_span_id).toBeUndefined();
expect(span.parent_span_id).toBeUndefined();

expect(errorEvent).toMatchObject({
contexts: {
Expand Down Expand Up @@ -80,38 +75,28 @@ test.describe('server-side errors', () => {
const errorEventPromise = waitForError('astro-6-cf-workers', errorEvent => {
return errorEvent?.exception?.values?.[0]?.value === 'Endpoint Error';
});
const transactionEventApiPromise = waitForTransaction('astro-6-cf-workers', transactionEvent => {
return transactionEvent.transaction === 'GET /endpoint-error/api';
const apiSpanPromise = waitForStreamedSpan('astro-6-cf-workers', span => {
return getSpanOp(span) === 'http.server' && span.name === 'GET /endpoint-error/api';
});
const transactionEventEndpointPromise = waitForTransaction('astro-6-cf-workers', transactionEvent => {
return transactionEvent.transaction === 'GET /endpoint-error';
const endpointSpanPromise = waitForStreamedSpan('astro-6-cf-workers', span => {
return getSpanOp(span) === 'http.server' && span.is_segment && span.name === 'GET /endpoint-error';
});

await page.goto('/endpoint-error');
await page.getByText('Get Data').click();

const errorEvent = await errorEventPromise;
const transactionEventApi = await transactionEventApiPromise;
const transactionEventEndpoint = await transactionEventEndpointPromise;

expect(transactionEventEndpoint).toMatchObject({
transaction: 'GET /endpoint-error',
spans: [],
});
const apiSpan = await apiSpanPromise;
const endpointSpan = await endpointSpanPromise;

const traceId = transactionEventEndpoint.contexts?.trace?.trace_id;
const endpointSpanId = transactionEventApi.contexts?.trace?.span_id;
const traceId = endpointSpan.trace_id;
const endpointSpanId = apiSpan.span_id;

expect(traceId).toMatch(/[a-f0-9]{32}/);
expect(endpointSpanId).toMatch(/[a-f0-9]{16}/);

expect(transactionEventApi).toMatchObject({
transaction: 'GET /endpoint-error/api',
spans: [],
});

const spanId = transactionEventApi.contexts?.trace?.span_id;
const parentSpanId = transactionEventApi.contexts?.trace?.parent_span_id;
const spanId = apiSpan.span_id;
const parentSpanId = apiSpan.parent_span_id;

expect(spanId).toMatch(/[a-f0-9]{16}/);
// TODO: This is incorrect, for whatever reason, it should be the endpointSpanId ideally
Expand Down
Loading
Loading