Back to Blog

Keeping an Eye on the Master Key: Building or-observer

#golang #svelte #duckdb #llm #observability #openrouter #devops

In my previous post, I described OpenRouter as the master key to a massive building filled with hundreds of Large Language Model doors. Whether it’s an automation script, a CLI tool like my ai assistant, or a weekend project, I route nearly all of my LLM traffic through it. But there’s a catch: when you have one master key opening hundreds of different doors, you eventually need to install some security cameras in the hallway.

You need to know who is calling what, how long it takes, and—most importantly for an IT Operator—how much it costs.

That’s why, shortly after building my own SDK, I built or-observer — a self-hosted LLM observability platform tailored specifically for OpenRouter.

Why Build Another Observability Tool?

There are plenty of massive, enterprise-grade cloud observability platforms out there. But as an IT Operator and DevOps engineer, I look at software through a strictly operational lens. I wanted something practical, secure, and lean for personal and small-scale use (< 1K requests/day).

I wanted:

  • Absolute Privacy: It’s self-hosted. My API traffic metadata doesn’t need to live on someone else’s server.
  • Granular Cost Tracking: I need to know exactly which model or user is burning through my credits.
  • Speed & Simplicity: No bulky Postgres databases or complex infrastructure to manage. Just a fast, embedded database.
  • Zero-Cloud Overhead: A lightweight container I can spin up with a single docker-compose up.

Key Features Under the Hood

or-observer is designed to be a frictionless dashboard for your LLM usage.

  • Real-time Webhook Ingestion: OpenRouter can broadcast standard OTLP (OpenTelemetry) JSON events. The backend listens for these webhooks and ingests the traces in real-time.
  • Fast Analytics via DuckDB: I used embedded DuckDB with the DuckLake extension. It provides blazing-fast columnar storage in a single file, perfect for analytical queries like calculating P95 latencies and hourly cost rollups.
  • Cost Breakdowns: Detailed analytics tabs let you slice and dice your usage by user or model, so you know exactly where your money is going.
  • Svelte 5 Dashboard: The frontend is a modern SvelteKit application using Svelte 5 (Runes), TanStack Query v6, and LayerChart v2 for visualization. It supports SSR, dark mode out of the box, and features a clean, responsive UI.

The Tech Stack: Go + DuckDB + Svelte 5

The architecture is deliberately simple but highly effective:

  1. Go 1.26+ Backend: Go is perfect for writing a robust, highly concurrent webhook receiver. Having just built the openrouter-go SDK, I naturally used it here to deserialize the OTLP payload and handle all the API endpoints and background aggregation tasks.
  2. DuckDB (Embedded): Using duckdb-go/v2, the app runs a single-writer embedded database. The lake.traces table stores the raw spans, while a background Go worker periodically rolls them up into lake.metrics_hourly for instant dashboard loading. No separate database server required.
  3. SvelteKit Frontend: Svelte 5 makes state management a breeze. Combined with Tailwind CSS and shadcn-svelte, building the trace explorer—complete with pagination, filtering, and a detailed trace modal—was an incredibly smooth experience.

API Endpoints Overview

To keep the frontend snappy, the backend exposes distinct data endpoints, each tailored for a specific dashboard view:

EndpointMethodBest for
/api/tracesGETPaginated, high-fidelity log exploration for debugging specific requests
/api/metricsGETAggregated latency (P50/P90/P99) and token velocity over time
/api/costsGETGrouped rollups (by user, model, or API key) for financial oversight

Oversight Without the Bloat

As a “non-classical developer” whose day job is rooted in IT Operations, I tend to avoid unnecessary complexity. When you run systems, you need oversight. You need to know when things break, when latency spikes, and when costs drift out of bounds. But you shouldn’t have to deploy a Kubernetes cluster to get it.

or-observer is my answer to the LLM observability problem. It gives me the dashboard I need for my OpenRouter master key, without the bloated infrastructure of a SaaS product.

If you’re routing your LLM traffic through OpenRouter and want a lightweight, self-hosted way to keep an eye on things, check out the repository on GitHub.