Hugh KaznowskiandClaude Sonnet 5 9f84be26ef Fix sum()/avg() merging sparse across staggered raw timestamps (ticket 042)
merge_series_exact required an exact-millisecond timestamp match to combine
sub-series, so sum(requests) by (path)-style queries over raw occurrence
counts produced one point per underlying (label, timestamp) pair instead of
a meaningful combined total, since real occurrence timestamps across
different label groups essentially never coincide. Added a regression test
confirming the sparse behavior, then replaced the merge with
merge_series_windowed: a single-sub-series group is passed through
unchanged (preserving existing single-label-group resolution exactly), and
groups with multiple sub-series are bucketed into fixed 1s windows before
summing/averaging, mirroring the fixed-width bucketing rate() already uses.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XFUNZwCvz3kcod3352ZR2o
2026-09-05 22:27:59 +01:00
2026-09-05 21:41:11 +01:00

ottyl

Observability for any command's terminal output — no logging backend, no agents, no config to ship.

your_app --verbose | ottyl

Pipe a program's stdout into ottyl and turn it into a searchable log timeline, ad-hoc metrics extracted from the log lines themselves, and Grafana-style dashboards — served from a single local binary, for the lifetime of that process:

  • Search: A syntax-aware filter bar over your logs — regex matches and metric comparisons like latency_ms[value]<200, with relative (5h, -3m) and absolute datetimes.
  • Log timeline: A bucketed bar chart of message volume over time, Kibana-style. Drag across it to set the active time range.
  • Metrics from logs: Declare a metric by matching a regex against your log lines and extracting a value. It applies retroactively to everything already ingested, and to everything that follows.
  • Dashboards: Bar, line, and pie chart panels driven by PromQL-style queries over your declared metrics.
  • Mixed sources: Poll an existing Prometheus/OpenMetrics endpoint alongside log ingestion, in the same dashboard.
  • Profiles: Parsing rules and dashboards are saved per app, so they're there again next time that app runs through ottyl.

Use cases

  • Debugging a noisy CLI or long-running script, instead of scrolling a terminal buffer.
  • Getting metrics and charts out of a program that only ever prints text.
  • Local dashboards without standing up a metrics stack.
  • Combining scraped Prometheus metrics with log-derived ones during a debugging session.

Get started

Requires Rust and Node.js. The webapp is built and embedded into the binary, so the result is a single self-contained executable.

git clone <this-repo>
cd ottyl
make build
your_app --verbose | ottyl

Or point it at a log file instead of stdin, and mix in a Prometheus/OpenMetrics endpoint:

ottyl --file /var/log/your_app.log --metrics-url http://localhost:9090/metrics

ottyl prints the URL of the local web server it starts (an OS-assigned free port by default; pin one with --port). See ottyl --help for the rest, including where settings and profiles live (--settings-path).

Full documentation — filtering syntax, parameters, metrics, dashboards — is built into the app itself, under the nav menu's docs section.

Development

make dev    # frontend dev server with hot reload, proxying to a separately running `cargo run` backend
make test   # backend + frontend tests
make lint   # clippy + oxlint
S
Description
Observability dashboard from terminal output
Readme
1.2 MiB
0.1.0 release
Latest
2026-09-05 20:44:51 +00:00
Languages
Rust 70.4%
TypeScript 27.7%
CSS 1.8%
Makefile 0.1%