Skip to content

Commit 458dca4

Browse files
authored
feat(node): Add openTelemetrySpanProcessors option (#14852)
Since `provider.addSpanProcessor()` is deprecated, we need a new way to add additional span processors. Fixes #14826
1 parent 9030f37 commit 458dca4

File tree

14 files changed

+420
-5
lines changed

14 files changed

+420
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "node-otel",
3+
"version": "1.0.0",
4+
"private": true,
5+
"scripts": {
6+
"build": "tsc",
7+
"start": "node dist/app.js",
8+
"test": "playwright test",
9+
"clean": "npx rimraf node_modules pnpm-lock.yaml",
10+
"test:build": "pnpm install && pnpm build",
11+
"test:assert": "pnpm test"
12+
},
13+
"dependencies": {
14+
"@opentelemetry/sdk-node": "0.52.1",
15+
"@opentelemetry/exporter-trace-otlp-http": "0.52.1",
16+
"@sentry/core": "latest || *",
17+
"@sentry/node": "latest || *",
18+
"@sentry/opentelemetry": "latest || *",
19+
"@types/express": "4.17.17",
20+
"@types/node": "^18.19.1",
21+
"express": "4.19.2",
22+
"typescript": "~5.0.0"
23+
},
24+
"devDependencies": {
25+
"@playwright/test": "^1.44.1",
26+
"@sentry-internal/test-utils": "link:../../../test-utils"
27+
},
28+
"volta": {
29+
"extends": "../../package.json"
30+
}
31+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig(
4+
{
5+
startCommand: `pnpm start`,
6+
},
7+
{
8+
webServer: [
9+
{
10+
command: `node ./start-event-proxy.mjs`,
11+
port: 3031,
12+
stdout: 'pipe',
13+
stderr: 'pipe',
14+
},
15+
{
16+
command: `node ./start-otel-proxy.mjs`,
17+
port: 3032,
18+
stdout: 'pipe',
19+
stderr: 'pipe',
20+
},
21+
{
22+
command: 'pnpm start',
23+
port: 3030,
24+
stdout: 'pipe',
25+
stderr: 'pipe',
26+
env: {
27+
PORT: 3030,
28+
},
29+
},
30+
],
31+
},
32+
);
33+
34+
export default config;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import './instrument';
2+
3+
// Other imports below
4+
import * as Sentry from '@sentry/node';
5+
import express from 'express';
6+
7+
const app = express();
8+
const port = 3030;
9+
10+
app.get('/test-success', function (req, res) {
11+
res.send({ version: 'v1' });
12+
});
13+
14+
app.get('/test-param/:param', function (req, res) {
15+
res.send({ paramWas: req.params.param });
16+
});
17+
18+
app.get('/test-transaction', function (req, res) {
19+
Sentry.withActiveSpan(null, async () => {
20+
Sentry.startSpan({ name: 'test-transaction', op: 'e2e-test' }, () => {
21+
Sentry.startSpan({ name: 'test-span' }, () => undefined);
22+
});
23+
24+
await Sentry.flush();
25+
26+
res.send({});
27+
});
28+
});
29+
30+
app.get('/test-error', async function (req, res) {
31+
const exceptionId = Sentry.captureException(new Error('This is an error'));
32+
33+
await Sentry.flush(2000);
34+
35+
res.send({ exceptionId });
36+
});
37+
38+
app.get('/test-exception/:id', function (req, _res) {
39+
throw new Error(`This is an exception with id ${req.params.id}`);
40+
});
41+
42+
Sentry.setupExpressErrorHandler(app);
43+
44+
app.use(function onError(err: unknown, req: any, res: any, next: any) {
45+
// The error id is attached to `res.sentry` to be returned
46+
// and optionally displayed to the user for support.
47+
res.statusCode = 500;
48+
res.end(res.sentry + '\n');
49+
});
50+
51+
app.listen(port, () => {
52+
console.log(`Example app listening on port ${port}`);
53+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const opentelemetry = require('@opentelemetry/sdk-node');
2+
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
3+
const Sentry = require('@sentry/node');
4+
5+
const sentryClient = Sentry.init({
6+
environment: 'qa', // dynamic sampling bias to keep transactions
7+
dsn:
8+
process.env.E2E_TEST_DSN ||
9+
'https://3b6c388182fb435097f41d181be2b2ba@o4504321058471936.ingest.sentry.io/4504321066008576',
10+
debug: !!process.env.DEBUG,
11+
tunnel: `http://localhost:3031/`, // proxy server
12+
tracesSampleRate: 1,
13+
14+
// Additional OTEL options
15+
openTelemetrySpanProcessors: [
16+
new opentelemetry.node.BatchSpanProcessor(
17+
new OTLPTraceExporter({
18+
url: 'http://localhost:3032/',
19+
}),
20+
),
21+
],
22+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { startEventProxyServer } from '@sentry-internal/test-utils';
2+
3+
startEventProxyServer({
4+
port: 3031,
5+
proxyServerName: 'node-otel',
6+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { startProxyServer } from '@sentry-internal/test-utils';
2+
3+
startProxyServer({
4+
port: 3032,
5+
proxyServerName: 'node-otel-otel',
6+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError } from '@sentry-internal/test-utils';
3+
4+
test('Sends correct error event', async ({ baseURL }) => {
5+
const errorEventPromise = waitForError('node-otel', event => {
6+
return !event.type && event.exception?.values?.[0]?.value === 'This is an exception with id 123';
7+
});
8+
9+
await fetch(`${baseURL}/test-exception/123`);
10+
11+
const errorEvent = await errorEventPromise;
12+
13+
expect(errorEvent.exception?.values).toHaveLength(1);
14+
expect(errorEvent.exception?.values?.[0]?.value).toBe('This is an exception with id 123');
15+
16+
expect(errorEvent.request).toEqual({
17+
method: 'GET',
18+
cookies: {},
19+
headers: expect.any(Object),
20+
url: 'http://localhost:3030/test-exception/123',
21+
});
22+
23+
expect(errorEvent.transaction).toEqual('GET /test-exception/:id');
24+
25+
expect(errorEvent.contexts?.trace).toEqual({
26+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
27+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
28+
});
29+
});

0 commit comments

Comments
 (0)