When production breaks, your options are: ssh + tail + jq (slow, error-prone),
ship logs to a SaaS (expensive, slow to set up), or stand up Loki or Elastic
(ops-heavy overkill). There's no good middle option for
"I have a folder of JSONL files, I want to explore them right now, locally,
with real query power."
Browser opens. You see a timestamp histogram, a facet panel (auto-detected
low-cardinality fields like level, service, host),
a results table, and a SQL editor pre-filled with a sensible default.
| Property | Why it matters |
|---|---|
| Local-first | No SaaS, no account, runs fully offline / air-gapped. |
| File-native | Queries .jsonl, .csv, and .parquet directly. No ingestion. |
| JSON-log-aware | Auto-infers schema, nested fields, timestamps, levels. |
| SQL-powered | Full DuckDB SQL: joins, window functions, aggregations. |
| Real web UI | Browser, not TUI. Shareable URLs, charts, faceted search. |
No existing tool combines all five. DuckDB UI isn't log-shaped. Tailpipe requires ingestion. lnav is terminal-only. Logdy has no SQL.
# Homebrew
brew install alldoq/tap/logq
logq ./var/log
# Docker
docker run --rm -p 7777:7777 -v "$PWD/logs:/data" ghcr.io/alldoq/logq:latest
# From source
git clone https://github.com/alldoq/logq.git
cd logq
cargo build --release
./target/release/logq ./sample-data
All UNION'd by name into one logs view via DuckDB
read_json_auto, read_csv_auto, and
read_parquet. Gzip and zstd handled.
SELECT * FROM logs WHERE service='api' AND request_id IN
(SELECT request_id FROM logs WHERE service='nginx' AND status>=500).
No pipeline.
Toggle button streams newly appended lines over WebSocket, with
optional --remote user@host:/path over SSH.
Switch any GROUP BY result between table, bar, and line views. Column headers open a top-25 value modal.
Click a nested cell to open a pretty-printed JSON modal with the full structure. No truncation.
CSV and Parquet download buttons run a COPY (...) TO
over the current query. Round-trip cleanly into another logq.
Persist named queries to .logq/queries.yml in the
directory. Git-friendly, shareable.
Drop a .logq/schema.yml to coerce columns to
TIMESTAMP, BIGINT, DOUBLE, etc., with optional strptime format.
Versioned /api/v1/*, optional bearer-token auth via
--token or LOGQ_TOKEN. Health endpoint
for monitoring.
logq /dir query "SELECT ..." for one-shot queries.
Output as JSON, NDJSON, CSV, or TSV. No web server needed.
Every query state is encoded in the URL hash. Copy-link button copies to clipboard; teammates open the same view.
Bundles DuckDB and the web UI. No daemons, no dependencies, no system DuckDB needed. About 34 MB.
kubectl logs ... | logq -, or point at an
https:// or s3:// URL. DuckDB httpfs is
loaded on demand.
Plain-text access logs and syslog (RFC3164 + RFC5424) are
detected at scan time and exposed as structured columns:
remote_addr, method, path,
status, host, app.
Click-drag on the histogram to scope every query to a window. Pairs naturally with the level facet for incident triage.
Multi-tab editor with persistent state. The last 100 queries surface in a one-click history panel.
curl -s localhost:7777/api/health
curl -s localhost:7777/api/v1/meta
curl -s -X POST localhost:7777/api/v1/query \
-H 'Content-Type: application/json' \
-d '{"sql":"SELECT level, COUNT(*) FROM logs GROUP BY 1"}'
# Auth (when --token is set)
curl -H "Authorization: Bearer $LOGQ_TOKEN" localhost:7777/api/v1/meta
v0.1.2 covers the v0.1 MVP plus most v0.5/v1.0 items: live tail, remote tail over SSH, schema overrides, CSV/Parquet ingest, charts, exports, Docker image, Homebrew tap, versioned HTTP API. Performance hardening for 100 GB+ datasets and a daemon/alert mode are still ahead.