Skip to content

Commit 82e6810

Browse files
committed
feat: OTEL
1 parent 1ed3d1b commit 82e6810

File tree

10 files changed

+979
-489
lines changed

10 files changed

+979
-489
lines changed

apps/basket/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
"@databuddy/shared": "workspace:*",
1919
"@databuddy/validation": "workspace:*",
2020
"@elysiajs/cors": "^1.3.3",
21+
"@elysiajs/opentelemetry": "^1.4.6",
2122
"@elysiajs/server-timing": "^1.3.0",
2223
"@maxmind/geoip2-node": "^6.1.0",
24+
"@opentelemetry/exporter-trace-otlp-proto": "^0.208.0",
25+
"@opentelemetry/resources": "^2.2.0",
26+
"@opentelemetry/sdk-trace-node": "^2.2.0",
27+
"@opentelemetry/semantic-conventions": "^1.38.0",
2328
"@types/ua-parser-js": "^0.7.39",
2429
"async-mutex": "^0.5.0",
2530
"autumn-js": "catalog:",

apps/basket/src/hooks/auth.ts

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import { and, db, eq, member, websites } from "@databuddy/db";
99
import { cacheable } from "@databuddy/redis";
10+
import { record, setAttributes } from "@elysiajs/opentelemetry";
1011
import { logger } from "../lib/logger";
1112

1213
type Website = typeof websites.$inferSelect;
@@ -354,17 +355,39 @@ const getWebsiteByIdWithOwnerCached = cacheable(
354355
}
355356
);
356357

357-
export async function getWebsiteByIdV2(
358+
export function getWebsiteByIdV2(
358359
id: string
359360
): Promise<WebsiteWithOwner | null> {
360-
console.time("getWebsiteByIdV2");
361-
try {
362-
const result = await getWebsiteByIdWithOwnerCached(id);
363-
console.timeEnd("getWebsiteByIdV2");
364-
return result;
365-
} catch (error) {
366-
logger.error({ error, websiteId: id }, "Failed to get website by ID V2");
367-
console.timeEnd("getWebsiteByIdV2");
368-
return null;
369-
}
361+
return record("getWebsiteByIdV2", async () => {
362+
console.time("getWebsiteByIdV2");
363+
setAttributes({
364+
"website.id": id,
365+
});
366+
367+
try {
368+
const result = await getWebsiteByIdWithOwnerCached(id);
369+
console.timeEnd("getWebsiteByIdV2");
370+
371+
if (result) {
372+
setAttributes({
373+
"website.found": true,
374+
"website.status": result.status,
375+
"website.has_owner": Boolean(result.ownerId),
376+
});
377+
} else {
378+
setAttributes({
379+
"website.found": false,
380+
});
381+
}
382+
383+
return result;
384+
} catch (error) {
385+
logger.error({ error, websiteId: id }, "Failed to get website by ID V2");
386+
setAttributes({
387+
"website.lookup_failed": true,
388+
});
389+
console.timeEnd("getWebsiteByIdV2");
390+
return null;
391+
}
392+
});
370393
}

apps/basket/src/index.ts

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
// import './polyfills/compression'
1+
import "./polyfills/compression";
22

3+
import { opentelemetry } from "@elysiajs/opentelemetry";
4+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
5+
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
36
import { Elysia } from "elysia";
47
import { logger } from "./lib/logger";
5-
// import stripeRouter from './routes/stripe';
68
import { getProducerStats } from "./lib/producer";
79
import basketRouter from "./routes/basket";
810
import emailRouter from "./routes/email";
9-
import "./polyfills/compression";
1011

1112
function getKafkaHealth() {
1213
const stats = getProducerStats();
@@ -34,16 +35,31 @@ function getKafkaHealth() {
3435
lastErrorTime: stats.lastErrorTime,
3536
};
3637
}
37-
// import { checkBotId } from "botid/server";
3838

3939
const app = new Elysia()
40-
.onError(({ error, code }) => {
40+
.use(
41+
opentelemetry({
42+
serviceName: "basket",
43+
spanProcessors: [
44+
new BatchSpanProcessor(
45+
new OTLPTraceExporter({
46+
url: "https://api.axiom.co/v1/traces",
47+
headers: {
48+
Authorization: `Bearer ${process.env.AXIOM_TOKEN}`,
49+
"X-Axiom-Dataset": process.env.AXIOM_DATASET ?? "basket",
50+
},
51+
})
52+
),
53+
],
54+
})
55+
)
56+
.onError(function handleError({ error, code }) {
4157
if (code === "NOT_FOUND") {
4258
return new Response(null, { status: 404 });
4359
}
4460
logger.error({ error }, "Error in basket service");
4561
})
46-
.onBeforeHandle(({ request, set }) => {
62+
.onBeforeHandle(function handleCors({ request, set }) {
4763
const origin = request.headers.get("origin");
4864
if (origin) {
4965
set.headers ??= {};
@@ -58,17 +74,18 @@ const app = new Elysia()
5874
.options("*", () => new Response(null, { status: 204 }))
5975
.use(basketRouter)
6076
.use(emailRouter)
61-
.get("/health", () => ({
62-
status: "ok",
63-
version: "1.0.0",
64-
producer_stats: getProducerStats(),
65-
kafka: getKafkaHealth(),
66-
}));
77+
.get("/health", function healthCheck() {
78+
return {
79+
status: "ok",
80+
version: "1.0.0",
81+
producer_stats: getProducerStats(),
82+
kafka: getKafkaHealth(),
83+
};
84+
});
6785

6886
const port = process.env.PORT || 4000;
6987

7088
console.log(`Starting basket service on port ${port}`);
71-
console.log(`Basket service running on http://localhost:${port}`);
7289

7390
export default {
7491
fetch: app.fetch,

0 commit comments

Comments
 (0)