Skip to content

Commit ff54c8c

Browse files
committed
Switched tracing from Sentry to OpenTelemetry
- despite Sentry using OTel under the hood, I'm finding it way to hard to get everything working in GCP as expected because we're being forced to do things in the Sentry way so we should just go all-in on doing things with raw OTel and GCP
1 parent 96673bc commit ff54c8c

File tree

4 files changed

+652
-87
lines changed

4 files changed

+652
-87
lines changed

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,17 @@
4444
"dependencies": {
4545
"@fedify/fedify": "1.2.3",
4646
"@google-cloud/opentelemetry-cloud-trace-exporter": "2.4.1",
47+
"@google-cloud/opentelemetry-cloud-trace-propagator": "0.20.0",
4748
"@google-cloud/pubsub": "4.8.0",
4849
"@hono/node-server": "1.13.5",
4950
"@js-temporal/polyfill": "0.4.4",
5051
"@logtape/logtape": "0.7.1",
52+
"@opentelemetry/api": "1.9.0",
53+
"@opentelemetry/auto-instrumentations-node": "0.52.1",
5154
"@opentelemetry/exporter-trace-otlp-proto": "0.54.2",
55+
"@opentelemetry/sdk-node": "0.54.2",
5256
"@opentelemetry/sdk-trace-base": "1.27.0",
57+
"@opentelemetry/sdk-trace-node": "1.27.0",
5358
"@sentry/node": "8.37.1",
5459
"hono": "4.6.9",
5560
"jsonwebtoken": "9.0.2",

src/app.ts

+3-29
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import {
2929
isLogLevel,
3030
withContext,
3131
} from '@logtape/logtape';
32-
import { SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD } from '@sentry/core';
3332
import * as Sentry from '@sentry/node';
3433
import { Hono, type Context as HonoContext, type Next } from 'hono';
3534
import { cors } from 'hono/cors';
@@ -350,34 +349,9 @@ app.use(async (ctx, next) => {
350349
return event;
351350
});
352351

353-
return Sentry.continueTrace(
354-
{
355-
sentryTrace:
356-
ctx.req.header('sentry-trace') ||
357-
(traceId && spanId ? `${traceId}-${spanId}-1` : undefined),
358-
baggage: ctx.req.header('baggage'),
359-
},
360-
() => {
361-
return Sentry.startSpan(
362-
{
363-
op: 'http.server',
364-
name: `${ctx.req.method} ${ctx.req.path}`,
365-
366-
attributes: {
367-
...extra,
368-
[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD]:
369-
ctx.req.method,
370-
'service.name': 'activitypub',
371-
},
372-
},
373-
() => {
374-
return withContext(extra, () => {
375-
return next();
376-
});
377-
},
378-
);
379-
},
380-
);
352+
return withContext(extra, () => {
353+
return next();
354+
});
381355
});
382356
});
383357

src/instrumentation.ts

+66-34
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,84 @@
1+
import { trace } from '@opentelemetry/api';
2+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
3+
import { NodeSDK } from '@opentelemetry/sdk-node';
14
import {
25
BatchSpanProcessor,
36
SimpleSpanProcessor,
47
} from '@opentelemetry/sdk-trace-base';
8+
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
59
import * as Sentry from '@sentry/node';
610

711
if (process.env.SENTRY_DSN) {
8-
const client = Sentry.init({
12+
Sentry.init({
913
dsn: process.env.SENTRY_DSN,
1014
environment: process.env.NODE_ENV || 'unknown',
1115
release: process.env.K_REVISION,
12-
tracesSampleRate: 1.0,
1316
});
17+
}
18+
19+
const sdk = new NodeSDK({
20+
instrumentations: getNodeAutoInstrumentations({
21+
'@opentelemetry/instrumentation-mysql2': {
22+
addSqlCommenterCommentToQueries: true,
23+
},
24+
}),
25+
});
26+
27+
const provider = new NodeTracerProvider();
28+
29+
if (process.env.K_SERVICE) {
30+
const { TraceExporter } = await import(
31+
'@google-cloud/opentelemetry-cloud-trace-exporter'
32+
);
33+
provider.addSpanProcessor(new BatchSpanProcessor(new TraceExporter({})));
34+
35+
const { CloudPropagator } = await import(
36+
'@google-cloud/opentelemetry-cloud-trace-propagator'
37+
);
38+
provider.register({
39+
propagator: new CloudPropagator(),
40+
});
41+
}
42+
43+
if (process.env.NODE_ENV === 'testing') {
44+
const { OTLPTraceExporter } = await import(
45+
'@opentelemetry/exporter-trace-otlp-proto'
46+
);
47+
48+
provider.addSpanProcessor(
49+
new SimpleSpanProcessor(
50+
new OTLPTraceExporter({
51+
url: 'http://jaeger:4318/v1/traces',
52+
}),
53+
),
54+
);
55+
56+
provider.register();
57+
}
58+
59+
export const tracer = trace.getTracer('activitypub');
1460

15-
if (process.env.K_SERVICE) {
16-
const { TraceExporter } = await import(
17-
'@google-cloud/opentelemetry-cloud-trace-exporter'
18-
);
19-
20-
client?.traceProvider?.addSpanProcessor(
21-
new BatchSpanProcessor(new TraceExporter({})),
22-
);
23-
}
24-
25-
if (process.env.NODE_ENV === 'testing') {
26-
const { OTLPTraceExporter } = await import(
27-
'@opentelemetry/exporter-trace-otlp-proto'
28-
);
29-
30-
client?.traceProvider?.addSpanProcessor(
31-
new SimpleSpanProcessor(
32-
new OTLPTraceExporter({
33-
url: 'http://jaeger:4318/v1/traces',
34-
}),
35-
),
36-
);
37-
}
61+
try {
62+
sdk.start();
63+
} catch (e) {
64+
console.error(e);
3865
}
3966

4067
export function spanWrapper<TArgs extends unknown[], TReturn>(
41-
fn: (...args: TArgs) => TReturn,
68+
fn: (...args: TArgs) => TReturn | Promise<TReturn>,
4269
) {
43-
return (...args: TArgs) => {
44-
return Sentry.startSpan(
45-
{
46-
op: 'fn',
47-
name: fn.name,
48-
},
49-
() => fn(...args),
50-
);
70+
return async (...args: TArgs) => {
71+
return tracer.startActiveSpan(fn.name || 'anonymous', async (span) => {
72+
try {
73+
const result = await Promise.resolve(fn(...args));
74+
span.end();
75+
return result;
76+
} catch (error) {
77+
span.recordException(error as Error);
78+
span.setStatus({ code: 2 }); // OpenTelemetry ERROR status
79+
span.end();
80+
throw error;
81+
}
82+
});
5183
};
5284
}

0 commit comments

Comments
 (0)