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 @@ -2,7 +2,6 @@ import * as Sentry from '@sentry/node';
import { loggingTransport } from '@sentry-internal/node-integration-tests';

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
Expand All @@ -12,11 +11,11 @@ Sentry.init({
Sentry.httpIntegration({
onSpanCreated: (span, req, res) => {
span.setAttribute('onSpanCreated', 'yes');
Sentry.setExtra('onSpanCreatedCalled', {
reqUrl: req.url,
reqMethod: req.method,
resUrl: res.req.url,
resMethod: res.req.method,
span.setAttributes({
'onSpanCreated.reqUrl': req.url,
'onSpanCreated.reqMethod': req.method,
'onSpanCreated.resUrl': res.req.url,
'onSpanCreated.resMethod': res.req.method,
});
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const { loggingTransport } = require('@sentry-internal/node-integration-tests');
const Sentry = require('@sentry/node');

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
Expand All @@ -11,6 +10,9 @@ Sentry.init({
integrations: [
Sentry.httpIntegration({
ignoreIncomingRequests: (url, request) => {
if (request.url === '/flush') {
return true;
}
if (url.includes('/liveness')) {
return true;
}
Expand All @@ -32,6 +34,11 @@ const app = express();

app.use(cors());

app.get('/flush', async (_req, res) => {
await Sentry.flush();
res.send({ response: 'flushed' });
});

app.get('/test', (_req, res) => {
res.send({ response: 'response 1' });
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const Sentry = require('@sentry/node');
const url = process.env.SERVER_URL;

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
Expand Down Expand Up @@ -40,6 +39,7 @@ app.use(cors());
app.get('/testUrl', (_req, response) => {
makeHttpRequest(`${url}/blockUrl`).then(() => {
makeHttpRequest(`${url}/pass`).then(() => {
Sentry.captureMessage('outgoing requests completed');

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is needed because this test requires an event to check breadcrumbs on (before this was checked on the transaction)

response.send({ response: 'done' });
});
});
Expand All @@ -48,6 +48,7 @@ app.get('/testUrl', (_req, response) => {
app.get('/testRequest', (_req, response) => {
makeHttpRequest(`${url}/blockRequest`).then(() => {
makeHttpRequest(`${url}/pass`).then(() => {
Sentry.captureMessage('outgoing requests completed');
response.send({ response: 'done' });
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ const { loggingTransport } = require('@sentry-internal/node-integration-tests');
const Sentry = require('@sentry/node');

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
transport: loggingTransport,
// Test default for ignoreStaticAssets: true
integrations: [Sentry.httpIntegration()],
integrations: [
Sentry.httpIntegration({
ignoreIncomingRequests: (_url, request) => request.url === '/flush',
}),
],
});

const express = require('express');
Expand All @@ -19,6 +22,11 @@ const app = express();

app.use(cors());

app.get('/flush', async (_req, res) => {
await Sentry.flush();
res.send({ response: 'flushed' });
});

app.get('/test', (_req, res) => {
res.send({ response: 'ok' });
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const Sentry = require('@sentry/node');
const url = process.env.SERVER_URL;

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const { loggingTransport } = require('@sentry-internal/node-integration-tests');
const Sentry = require('@sentry/node');

Sentry.init({
traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTTP_SERVER } from '@sentry/conventions/op';
import { HTTP_CLIENT, HTTP_SERVER } from '@sentry/conventions/op';
import { createTestServer } from '@sentry-internal/test-utils';
import { HTTP_RESPONSE_STATUS_CODE, SENTRY_OP, URL_FULL, URL_PATH } from '@sentry/conventions/attributes';
import { afterAll, describe, expect, test } from 'vitest';
Expand Down Expand Up @@ -27,28 +27,25 @@ describe('httpIntegration', () => {
test('allows to configure onSpanCreated', async () => {
const runner = createRunner()
.expect({
transaction: {
contexts: {
trace: {
span: {
items: expect.arrayContaining([
expect.objectContaining({
is_segment: true,
span_id: expect.stringMatching(/[a-f\d]{16}/),
trace_id: expect.stringMatching(/[a-f\d]{32}/),
data: {
'url.full': expect.stringMatching(/\/test$/),
'http.response.status_code': 200,
onSpanCreated: 'yes',
},
op: 'http.server',
status: 'ok',
},
},
extra: expect.objectContaining({
onSpanCreatedCalled: {
reqUrl: expect.stringMatching(/\/test$/),
reqMethod: 'GET',
resUrl: expect.stringMatching(/\/test$/),
resMethod: 'GET',
},
}),
attributes: expect.objectContaining({
[URL_FULL]: { type: 'string', value: expect.stringMatching(/\/test$/) },
[HTTP_RESPONSE_STATUS_CODE]: { type: 'integer', value: 200 },
[SENTRY_OP]: { type: 'string', value: HTTP_SERVER },
onSpanCreated: { type: 'string', value: 'yes' },
'onSpanCreated.reqUrl': { type: 'string', value: expect.stringMatching(/\/test$/) },
'onSpanCreated.reqMethod': { type: 'string', value: 'GET' },
'onSpanCreated.resUrl': { type: 'string', value: expect.stringMatching(/\/test$/) },
'onSpanCreated.resMethod': { type: 'string', value: 'GET' },
}),
}),
]),
},
})
.start();
Expand All @@ -67,15 +64,15 @@ describe('httpIntegration', () => {
const runner = createRunner(__dirname, 'server-outgoingHooks.js')
.withEnv({ SERVER_URL })
.expect({
transaction: event => {
const clientSpans = event.spans?.filter(span => span.op === 'http.client');
span: container => {
const clientSpans = container.items.filter(span => span.attributes[SENTRY_OP]?.value === HTTP_CLIENT);
expect(clientSpans).toHaveLength(1);

// All three hooks run before the span ends, so every attribute has to survive to the envelope.
const data = clientSpans![0]?.data;
expect(data?.['outgoingRequestHook']).toBe('GET');
expect(data?.['outgoingResponseHook']).toBe(200);
expect(data?.['outgoingRequestApplyCustomAttributes']).toBe('GET 200');
const attributes = clientSpans[0]?.attributes;
expect(attributes?.['outgoingRequestHook']).toEqual({ type: 'string', value: 'GET' });
expect(attributes?.['outgoingResponseHook']).toEqual({ type: 'integer', value: 200 });
expect(attributes?.['outgoingRequestApplyCustomAttributes']).toEqual({ type: 'string', value: 'GET 200' });
},
})
.start();
Expand Down Expand Up @@ -455,52 +452,58 @@ describe('httpIntegration', () => {
test('via the url param', async () => {
const runner = createRunner(__dirname, 'server-ignoreIncomingRequests.js')
.expect({
transaction: {
contexts: {
trace: {
span: {
items: expect.arrayContaining([
expect.objectContaining({
name: 'GET /test',
is_segment: true,
span_id: expect.stringMatching(/[a-f\d]{16}/),
trace_id: expect.stringMatching(/[a-f\d]{32}/),
data: {
'url.full': expect.stringMatching(/\/test$/),
'http.response.status_code': 200,
},
op: 'http.server',
status: 'ok',
},
},
transaction: 'GET /test',
Comment thread
nicohrubec marked this conversation as resolved.
attributes: expect.objectContaining({
[URL_FULL]: { type: 'string', value: expect.stringMatching(/\/test$/) },
[HTTP_RESPONSE_STATUS_CODE]: { type: 'integer', value: 200 },
[SENTRY_OP]: { type: 'string', value: HTTP_SERVER },
}),
}),
]),
},
})
.start();

runner.makeRequest('get', '/liveness'); // should be ignored
runner.makeRequest('get', '/test');
await runner.makeRequest('get', '/liveness'); // should be ignored
// Flush so any span from the ignored request fails the expectation before /test runs.
await runner.makeRequest('get', '/flush');
await runner.makeRequest('get', '/test');
await runner.completed();
});

test('via the request param', async () => {
const runner = createRunner(__dirname, 'server-ignoreIncomingRequests.js')
.expect({
transaction: {
contexts: {
trace: {
span: {
items: expect.arrayContaining([
expect.objectContaining({
name: 'GET /test',
is_segment: true,
span_id: expect.stringMatching(/[a-f\d]{16}/),
trace_id: expect.stringMatching(/[a-f\d]{32}/),
data: {
'url.full': expect.stringMatching(/\/test$/),
'http.response.status_code': 200,
},
op: 'http.server',
status: 'ok',
},
},
transaction: 'GET /test',
attributes: expect.objectContaining({
[URL_FULL]: { type: 'string', value: expect.stringMatching(/\/test$/) },
[HTTP_RESPONSE_STATUS_CODE]: { type: 'integer', value: 200 },
[SENTRY_OP]: { type: 'string', value: HTTP_SERVER },
}),
}),
]),
},
})
.start();

runner.makeRequest('post', '/readiness'); // should be ignored
runner.makeRequest('get', '/test');
await runner.makeRequest('post', '/readiness'); // should be ignored
// Flush so any span from the ignored request fails the expectation before /test runs.
await runner.makeRequest('get', '/flush');
await runner.makeRequest('get', '/test');
await runner.completed();
});
});
Expand All @@ -515,18 +518,22 @@ describe('httpIntegration', () => {
const runner = createRunner(__dirname, 'server-ignoreOutgoingRequests.js')
.withEnv({ SERVER_URL })
.expect({
transaction: event => {
expect(event.transaction).toBe('GET /testUrl');

const requestSpans = event.spans?.filter(span => span.op === 'http.client');
expect(requestSpans).toHaveLength(1);
expect(requestSpans![0]?.description).toBe(`GET ${SERVER_URL}/pass`);

event: event => {
const breadcrumbs = event.breadcrumbs?.filter(b => b.category === 'http');
expect(breadcrumbs).toHaveLength(1);
expect(breadcrumbs![0]?.data?.url).toEqual(`${SERVER_URL}/pass`);
},
})
.expect({
span: container => {
expect(container.items.find(span => span.is_segment)?.name).toBe('GET /testUrl');

const requestSpans = container.items.filter(span => span.attributes[SENTRY_OP]?.value === HTTP_CLIENT);
expect(requestSpans).toHaveLength(1);
expect(requestSpans[0]?.name).toBe('GET localhost');
expect(requestSpans[0]?.attributes[URL_FULL]).toEqual({ type: 'string', value: `${SERVER_URL}/pass` });
},
})
.start();
runner.makeRequest('get', '/testUrl');
await runner.completed();
Expand All @@ -542,18 +549,22 @@ describe('httpIntegration', () => {
const runner = createRunner(__dirname, 'server-ignoreOutgoingRequests.js')
.withEnv({ SERVER_URL })
.expect({
transaction: event => {
expect(event.transaction).toBe('GET /testRequest');

const requestSpans = event.spans?.filter(span => span.op === 'http.client');
expect(requestSpans).toHaveLength(1);
expect(requestSpans![0]?.description).toBe(`GET ${SERVER_URL}/pass`);

event: event => {
const breadcrumbs = event.breadcrumbs?.filter(b => b.category === 'http');
expect(breadcrumbs).toHaveLength(1);
expect(breadcrumbs![0]?.data?.url).toEqual(`${SERVER_URL}/pass`);
},
})
.expect({
span: container => {
expect(container.items.find(span => span.is_segment)?.name).toBe('GET /testRequest');

const requestSpans = container.items.filter(span => span.attributes[SENTRY_OP]?.value === HTTP_CLIENT);
expect(requestSpans).toHaveLength(1);
expect(requestSpans[0]?.name).toBe('GET localhost');
expect(requestSpans[0]?.attributes[URL_FULL]).toEqual({ type: 'string', value: `${SERVER_URL}/pass` });
},
})
.start();
runner.makeRequest('get', '/testRequest');

Expand All @@ -565,11 +576,12 @@ describe('httpIntegration', () => {
test('ignores static asset requests by default', async () => {
const runner = createRunner(__dirname, 'server-ignoreStaticAssets.js')
.expect({
transaction: event => {
expect(event.transaction).toBe('GET /test');
expect(event.contexts?.trace?.data?.['url.full']).toMatch(/\/test$/);
expect(event.contexts?.trace?.op).toBe('http.server');
expect(event.contexts?.trace?.status).toBe('ok');
span: container => {
const segment = container.items.find(span => span.is_segment);
expect(segment?.name).toBe('GET /test');
expect(segment?.attributes[URL_FULL]?.value).toMatch(/\/test$/);
expect(segment?.attributes[SENTRY_OP]).toEqual({ type: 'string', value: HTTP_SERVER });
expect(segment?.status).toBe('ok');
},
})
.start();
Expand All @@ -579,6 +591,9 @@ describe('httpIntegration', () => {
await runner.makeRequest('get', '/robots.txt');
await runner.makeRequest('get', '/assets/app.js');

// Flush so any static-asset span fails the expectation before /test runs.
await runner.makeRequest('get', '/flush');

// This one should be traced
await runner.makeRequest('get', '/test');

Expand All @@ -588,11 +603,12 @@ describe('httpIntegration', () => {
test('traces static asset requests when ignoreStaticAssets is false', async () => {
const runner = createRunner(__dirname, 'server-traceStaticAssets.js')
.expect({
transaction: event => {
expect(event.transaction).toBe('GET /favicon.ico');
expect(event.contexts?.trace?.data?.['url.full']).toMatch(/\/favicon.ico$/);
expect(event.contexts?.trace?.op).toBe('http.server');
expect(event.contexts?.trace?.status).toBe('ok');
Comment thread
cursor[bot] marked this conversation as resolved.
span: container => {
const segment = container.items.find(span => span.is_segment);
expect(segment?.name).toBe('GET /favicon.ico');
expect(segment?.attributes[URL_FULL]?.value).toMatch(/\/favicon.ico$/);
expect(segment?.attributes[SENTRY_OP]).toEqual({ type: 'string', value: HTTP_SERVER });
expect(segment?.status).toBe('ok');
},
})
.start();
Expand Down
Loading