From ae3456bd5b2659899743e88d4f349f979f0a2a2f Mon Sep 17 00:00:00 2001 From: Edward Zhang Date: Wed, 14 Oct 2026 00:55:16 -0400 Subject: [PATCH 1/3] feat(service): otel setup + builtin tracing --- package.json | 3 ++- src/app.ts | 1 + src/services/observability.ts | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/services/observability.ts diff --git a/package.json b/package.json index 64c5d38..f6031d1 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "main": "src/app.ts", "scripts": { - "start": "tsx src/app.ts", + "start": "tsx --env-file=.env src/app.ts", "test": "vitest run test", "stress-test": "vitest run test/search-stress.test.ts", "docs": "typedoc --entryPointStrategy expand ./src --exclude \"**/legacy/**\"" @@ -14,6 +14,7 @@ "license": "ISC", "dependencies": { "@datastructures-js/priority-queue": "^6.3.3", + "@hyperdx/node-opentelemetry": "^0.11.0", "axios": "^1.7.2", "dotenv": "^16.4.5", "express": "^4.19.2", diff --git a/src/app.ts b/src/app.ts index 7690451..fb26aed 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,6 @@ import express from "express"; +import "@/services/observability"; import mbus from "./routes/api" const app = express(); diff --git a/src/services/observability.ts b/src/services/observability.ts new file mode 100644 index 0000000..8089d1f --- /dev/null +++ b/src/services/observability.ts @@ -0,0 +1,29 @@ +import * as HyperDX from '@hyperdx/node-opentelemetry'; +import opentelemetry, { Tracer, Meter } from '@opentelemetry/api'; +import * as z from 'zod'; + +// dotenv is NOT used because the otlp endpoint var needs to already be set to work properly +const config = z.object({ + OTEL_KEY: z.string().optional(), + OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(), + SERVICE_NAME: z.string().default('local/mbus-backend-dev'), +}).parse(process.env); + +export let tracer: Tracer | null = null; +export let meter: Meter | null = null; + +if (config.OTEL_KEY && config.OTEL_EXPORTER_OTLP_ENDPOINT) { + // must be before any meters are created + HyperDX.init({ + apiKey: config.OTEL_KEY, + service: config.SERVICE_NAME, + }); + + tracer = opentelemetry.trace.getTracer('mbus-backend-dev', '0.1.0'); + meter = opentelemetry.metrics.getMeter('mbus-backend-dev', '0.1.0'); + + console.log('otel initialized as ' + config.SERVICE_NAME); +} else { + console.log('otel is off, make sure key and endpoint are set'); +} + From 715ac732fda83a13f7c6b058d3b8778506b08dfa Mon Sep 17 00:00:00 2001 From: Edward Zhang Date: Mon, 19 Oct 2026 15:34:10 -0400 Subject: [PATCH 2/3] chore: add pull request template --- .github/pull_request_template.md | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..3b03a07 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,74 @@ + + +## Description +(1-2 sentences: what changed and why — e.g., "Added Firebase push notifications for real-time bus arrivals") + +## Type of Change +- [ ] New feature (`feat`) +- [ ] Bug fix (`fix`) +- [ ] Refactor / code improvement +- [ ] Dependency / build update +- [ ] Documentation +- [ ] Other (explain) + +## Changed Files +(Please list *all* files you changed, each with a description of what you changed and why.) +*Tip: see a list of everything you changed on the "Files changed" tab* + +Example: +* `map_screen.dart` + * Added "New" button to top toolbar +* `bluebus_api.dart` + * Added try/catch statements to `fetchRoutes()` for better reliability + +## Related Issues +Closes #XX, Prereq of #XX, etc. + +## Does your code rely on another PR +(attach PR number here) + +## Testing Done +**Flutter:** +- [ ] Tested on: + - [ ] iOS Simulator + - [ ] Android Emulator + - [ ] Physical device +**Vitest:** +- [ ] existing test(s) with coverage: (which tests?) +- [ ] new tests added: (describe) + +## Screenshots / Demo (if UI or notification change) + + +## Checklist +- [ ] Commit messages follow Conventional Commits +- [ ] PR title follows `(scope): short description` +- [ ] PR target branch is not `main` and is our current working update branch (e.g. `maizebus2.1`, `dev`) +- [ ] No `print()` / `debugPrint()` / `console.log()` left in production code +- [ ] Secrets / keys not committed From 95e32a1250d26c8af5d04c36bbb4b1b356a811af Mon Sep 17 00:00:00 2001 From: Edward Zhang Date: Wed, 21 Oct 2026 00:18:16 -0400 Subject: [PATCH 3/3] fix(otel): make it emit runtime and host metrics --- package.json | 3 ++- src/app.ts | 1 - src/services/observability.ts | 31 ++++++++++++++----------------- src/services/reminder.ts | 2 -- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index f6031d1..2c75559 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "main": "src/app.ts", "scripts": { - "start": "tsx --env-file=.env src/app.ts", + "start": "tsx --env-file=.env --experimental-loader=@opentelemetry/instrumentation/hook.mjs --import src/services/observability.ts src/app.ts", "test": "vitest run test", "stress-test": "vitest run test/search-stress.test.ts", "docs": "typedoc --entryPointStrategy expand ./src --exclude \"**/legacy/**\"" @@ -15,6 +15,7 @@ "dependencies": { "@datastructures-js/priority-queue": "^6.3.3", "@hyperdx/node-opentelemetry": "^0.11.0", + "@opentelemetry/host-metrics": "^0.40.0", "axios": "^1.7.2", "dotenv": "^16.4.5", "express": "^4.19.2", diff --git a/src/app.ts b/src/app.ts index fb26aed..7690451 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,5 @@ import express from "express"; -import "@/services/observability"; import mbus from "./routes/api" const app = express(); diff --git a/src/services/observability.ts b/src/services/observability.ts index 8089d1f..32c7e17 100644 --- a/src/services/observability.ts +++ b/src/services/observability.ts @@ -1,28 +1,25 @@ import * as HyperDX from '@hyperdx/node-opentelemetry'; -import opentelemetry, { Tracer, Meter } from '@opentelemetry/api'; -import * as z from 'zod'; +import { HostMetrics } from '@opentelemetry/host-metrics'; +import { metrics } from '@opentelemetry/api' // dotenv is NOT used because the otlp endpoint var needs to already be set to work properly -const config = z.object({ - OTEL_KEY: z.string().optional(), - OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(), - SERVICE_NAME: z.string().default('local/mbus-backend-dev'), -}).parse(process.env); +const otelKey = process.env.OTEL_KEY; +const otelExporterOtlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT; +const serviceName = process.env.SERVICE_NAME ?? 'local/mbus-backend-dev'; -export let tracer: Tracer | null = null; -export let meter: Meter | null = null; - -if (config.OTEL_KEY && config.OTEL_EXPORTER_OTLP_ENDPOINT) { +if (otelKey && otelExporterOtlpEndpoint) { // must be before any meters are created - HyperDX.init({ - apiKey: config.OTEL_KEY, - service: config.SERVICE_NAME, + HyperDX.initSDK({ + apiKey: otelKey, + service: serviceName, + experimentalExceptionCapture: true, }); - tracer = opentelemetry.trace.getTracer('mbus-backend-dev', '0.1.0'); - meter = opentelemetry.metrics.getMeter('mbus-backend-dev', '0.1.0'); + new HostMetrics({ + meterProvider: metrics.getMeterProvider(), + }).start(); - console.log('otel initialized as ' + config.SERVICE_NAME); + console.log('otel initialized as ' + serviceName); } else { console.log('otel is off, make sure key and endpoint are set'); } diff --git a/src/services/reminder.ts b/src/services/reminder.ts index a274244..581bcbb 100644 --- a/src/services/reminder.ts +++ b/src/services/reminder.ts @@ -5,8 +5,6 @@ import { applicationDefault, initializeApp } from "firebase-admin/app"; import * as state from "@/state/transitState"; import { BaseEvent, DelayEvent, eventsEqual, toKey, Key, RegistrationToken, ThresholdEvent, fromKey, delayEvent, thresholdEvent } from "./reminderTypes"; -export * from "./reminderTypes"; - dotenv.config() // Initialize Firebase