Skip to content

Commit 3a2a050

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 - also introduces `development` NODE_ENV so we can disable traces in tests
1 parent d4ea5b0 commit 3a2a050

File tree

5 files changed

+654
-89
lines changed

5 files changed

+654
-89
lines changed

docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ services:
1010
- MYSQL_HOST=mysql
1111
- MYSQL_PORT=3306
1212
- MYSQL_DATABASE=activitypub
13-
- NODE_ENV=testing
13+
- NODE_ENV=development
1414
- ALLOW_PRIVATE_ADDRESS=true
1515
- SKIP_SIGNATURE_VERIFICATION=true
1616
command: yarn build:watch

package.json

+5
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,17 @@
4545
"dependencies": {
4646
"@fedify/fedify": "1.2.4",
4747
"@google-cloud/opentelemetry-cloud-trace-exporter": "2.4.1",
48+
"@google-cloud/opentelemetry-cloud-trace-propagator": "0.20.0",
4849
"@google-cloud/pubsub": "4.8.0",
4950
"@hono/node-server": "1.13.5",
5051
"@js-temporal/polyfill": "0.4.4",
5152
"@logtape/logtape": "0.7.1",
53+
"@opentelemetry/api": "1.9.0",
54+
"@opentelemetry/auto-instrumentations-node": "0.52.1",
5255
"@opentelemetry/exporter-trace-otlp-proto": "0.54.2",
56+
"@opentelemetry/sdk-node": "0.54.2",
5357
"@opentelemetry/sdk-trace-base": "1.27.0",
58+
"@opentelemetry/sdk-trace-node": "1.27.0",
5459
"@sentry/node": "8.37.1",
5560
"hono": "4.6.9",
5661
"jsonwebtoken": "9.0.2",

src/app.ts

+5-31
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';
@@ -158,10 +157,10 @@ export const fedify = createFederation<ContextData>({
158157
kv: fedifyKv,
159158
skipSignatureVerification:
160159
process.env.SKIP_SIGNATURE_VERIFICATION === 'true' &&
161-
process.env.NODE_ENV === 'testing',
160+
['development', 'testing'].includes(process.env.NODE_ENV || ''),
162161
allowPrivateAddress:
163162
process.env.ALLOW_PRIVATE_ADDRESS === 'true' &&
164-
process.env.NODE_ENV === 'testing',
163+
['development', 'testing'].includes(process.env.NODE_ENV || ''),
165164
});
166165

167166
export const db = await KnexKvStore.create(client, 'key_value');
@@ -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

+65-33
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 === 'development') {
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
) {
4370
return (...args: TArgs) => {
44-
return Sentry.startSpan(
45-
{
46-
op: 'fn',
47-
name: fn.name,
48-
},
49-
() => fn(...args),
50-
);
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)