@brechtknecht/turbolog
v0.1.0
Published
Developer-first runtime observability toolkit with a Turbo-inspired TUI and local MCP server. Everything in the runtime is a stream.
Maintainers
Readme
turbolog
Developer-first runtime observability with a Turbo-inspired TUI and a local MCP server. Everything in your runtime — logs, HTTP, SQL, jobs, cache, events — is a stream you can view, filter, search, inspect and control in real time.
turbolog embeds into your app as a tiny SDK. It records events into an in-memory store and serves them over a local socket. Two clients attach to that socket:
- the TUI (
npx turbolog) — a live terminal UI - the MCP server (
turbolog-mcp) — exposes the runtime to AI agents/editors
your app ──createLogger()──▶ turbolog runtime ──local socket──┬──▶ TUI
└──▶ MCP server ──▶ Claude / Cursor / VS CodeLocal-first. Zero-config. Development-only by default (off when NODE_ENV=production unless TURBOLOG=1).
Install
npm install @brechtknecht/turbolog # in your projectThe package is scoped, but the CLI commands stay turbolog (TUI) and
turbolog-mcp (MCP server). (For local development of turbolog itself:
npm install && npm run build.)
1. Embed it in your app
import { createLogger } from "@brechtknecht/turbolog";
const log = createLogger(); // also starts a local socket server
log.info("Application started", { pid: process.pid });
const db = log.channel("db"); // channels appear as their own streams
db.info("Connected");
db.warn("Slow query", { duration: 320, table: "users" });
log.channel("auth").warn("Invalid password", { user: "alice" });Structured/typed streams (used by framework integrations) go through emit:
log.emit({
stream: "http",
message: "GET /users 200",
meta: { method: "GET", route: "/users", status: 200, tenant: "acme" },
duration: 42,
requestId: "req-91",
traceId: "trace-abc",
});log.error(new Error("boom")) captures the stack automatically.
2. Attach the TUI
From the same project directory (so it discovers the socket):
npx turbolog turbolog ● connected
┌ STREAMS ────┬ OUTPUT · http /level:error ───────────────────────┐
│▸≡ All 153│ 12:41:02 ERROR [http] GET /health 500 412ms │
│ ⛁ db 7│ 12:41:02 WARN [sql] SELECT * FROM users 118ms │
│ ↔ http 49│ 12:41:03 INFO [http] GET /orders 200 route=/ord… │
│ ⛁ sql 49│ ... │
└─────────────┴────────────────────────────────────────────────────┘
↑↓ move · → output · e toggle · c clear · / search · r rec · ? help · q quitKeys: ↑↓/jk move · tab switch pane · →/enter output / inspect ·
/ search · e enable/disable stream · c clear · r record · x export ·
i inspect · ? help · q quit.
3. Attach the MCP server
Point any MCP client (Claude Desktop, Cursor, VS Code) at turbolog-mcp, with
cwd set to your project (so it finds the same socket). See
examples/mcp.json:
{
"mcpServers": {
"turbolog": {
"command": "npx",
"args": ["-y", "turbolog-mcp"],
"cwd": "/absolute/path/to/your/project"
}
}
}Your app must be running. Then ask things like "Summarize the last 100 errors", "Show all failed HTTP requests", "Find slow SQL queries".
Tools: list_streams, read_stream, tail_stream, enable_stream,
disable_stream, clear_stream, search_logs, inspect_event,
list_requests, inspect_request, list_errors, record_session,
stop_recording, export_session, execute_command.
Resources: turbolog://streams, turbolog://errors, turbolog://history.
Search query language
Used by both the TUI / search and the search_logs MCP tool. Space-separated
tokens are ANDed together.
| Example | Matches |
|---|---|
| payment | free text in message or metadata |
| level:error | exact level |
| level:>=warn | level at or above warn |
| channel=db | events on channel db |
| stream=http | events on stream http |
| duration>100 | numeric compare (> < >= <= =), unit suffixes ok (100ms) |
| tenant=foo table=users | metadata equality |
| trace=abc123 / request=42 | correlation ids |
Runtime controls (no restart)
Enable · Disable / Pause · Resume · Mute · Clear · Record · Search — per stream, live, from the TUI or via MCP.
Session recording
r in the TUI (or record_session / stop_recording via MCP) captures events;
x / export_session writes .turbolog/session-<ts>.json for bug reports and replay.
Try the demo
npm run build
node examples/demo-app.mjs # generates logs/http/sql/cache/queue streams
npx turbolog # in another terminal, same directoryConfiguration
| Env | Effect |
|---|---|
| TURBOLOG=1 / TURBOLOG=0 | force on / off (overrides NODE_ENV) |
| TURBOLOG_SOCKET=<path> | explicit socket path (client + server must agree) |
| TURBOLOG_DEBUG=1 | log server startup errors |
Socket path resolution: explicit option → TURBOLOG_SOCKET → .turbolog/socket
discovery file → deterministic default derived from the project directory. This
is why the app, TUI and MCP server agree with zero configuration when run from
the same directory.
API
const log = createLogger({ enabled?, serve?, socketPath?, cwd? });
log.info/warn/error/debug/trace(message, meta?)
log.channel(name) // → scoped logger, shows as its own stream
log.emit({ stream, message, meta, level?, duration?, traceId?, requestId? })
log.store // underlying Store (read/subscribe in-process)
await log.serve() // start socket server (idempotent) → socket path
log.close() // stop servingProgrammatic clients: TurbologClient (socket client used by TUI + MCP),
TurbologServer, Store, search, compileQuery.
Status
MVP. Implemented: core SDK, streams + channels, in-memory store, socket server/client, query language, TUI (sidebar, output, search, inspector, controls, recording), and a working local MCP server (tools + resources).
Not yet: framework integration packages (@turbolog/express, /next,
/react), plugin system, split/timeline views, OpenTelemetry bridge.
MIT.
