|
1 | | -# LogPilot 🧭 |
| 1 | +# LogPilot 🪵 |
2 | 2 |
|
3 | 3 | [](https://github.com/clarabennett2626/logpilot/actions/workflows/ci.yml) |
4 | 4 | [](https://github.com/clarabennett2626/logpilot/releases/latest) |
5 | 5 | [](https://goreportcard.com/report/github.com/clarabennett2626/logpilot) |
| 6 | +[](https://pkg.go.dev/github.com/clarabennett2626/logpilot) |
6 | 7 | [](LICENSE) |
7 | 8 |
|
8 | | -**Multi-source structured log viewer for the terminal.** |
| 9 | +**A multi-source structured log viewer for the terminal.** Tail files, pipe from Docker/kubectl, mix JSON and logfmt and plain text — all in one interactive TUI. |
9 | 10 |
|
10 | | -Stream, search, and correlate logs from files, Kubernetes, Docker, SSH, and more — all in one TUI. |
| 11 | +<p align="center"> |
| 12 | + <img src="docs/demos/demo-json.gif" alt="LogPilot demo — JSON logs" width="720"> |
| 13 | +</p> |
11 | 14 |
|
12 | | - |
| 15 | +## Why LogPilot? |
| 16 | + |
| 17 | +- **Structured-first.** LogPilot *parses* your logs — JSON fields, logfmt pairs, timestamps, levels — not just regex-highlights keywords. That means real filtering, not cosmetic coloring. |
| 18 | +- **Format-agnostic.** Auto-detects JSON, logfmt, and plain text. Tail a JSON API log and a plain syslog side by side in one view. No config files, no format declarations. |
| 19 | +- **Interactive, not passive.** Live-scrolling TUI with search, vim keybindings, and color-coded levels. Not a pager you pipe through — a tool you work *in*. |
| 20 | +- **Lightweight and modern.** Single binary, no runtime dependencies. Built with Go and [Bubble Tea](https://github.com/charmbracelet/bubbletea) — starts instantly, stays under 20 MB RSS. |
13 | 21 |
|
14 | 22 | ## Features |
15 | 23 |
|
16 | | -### ✅ Implemented |
17 | | -- 🔍 **Format auto-detection** — Automatically identifies JSON, logfmt, and plain text log formats |
18 | | -- 🎨 **Color-coded rendering** — Log levels rendered with distinct colors (DEBUG=gray, INFO=blue, WARN=yellow, ERROR=red, FATAL=red bold) |
19 | | -- ⏰ **Flexible timestamps** — Configurable display: relative ("2m ago"), ISO 8601, or local time |
20 | | -- 🌗 **Theme support** — Dark and light terminal themes |
21 | | -- 📂 **File reader** — Read and tail local log files with rotation handling and glob patterns |
22 | | -- 📥 **Stdin/pipe support** — Composable with any command: `kubectl logs -f | logpilot` |
23 | | -- ⚡ **Backpressure handling** — Configurable strategies (block or drop-oldest) for high-throughput streams |
24 | | -- 🔄 **Log rotation** — Detects file truncation and replacement, reopens automatically |
25 | | -- 📊 **Multi-file tailing** — Monitor multiple log files simultaneously with glob patterns |
26 | | - |
27 | | -### 🚧 Coming Soon |
28 | | -- ☸️ **Kubernetes source** — Stream logs directly from pods |
29 | | -- 🐳 **Docker source** — Tail container logs |
30 | | -- 🔗 **SSH remote** — Read logs from remote servers |
31 | | -- 🔎 **Field-based filtering** — Queries like `level=error service=auth latency>500ms` |
32 | | -- 📈 **Timeline visualization** — ASCII sparklines for error rates |
33 | | -- 🔗 **Trace correlation** — Follow request IDs across sources |
34 | | -- ⌨️ **Vim keybindings** — Navigate logs like code |
| 24 | +### Implemented |
35 | 25 |
|
36 | | -## Installation |
| 26 | +- 🔍 **Auto-format detection** — JSON, logfmt, plain text, no config needed |
| 27 | +- 🎨 **Color-coded log levels** — DEBUG (gray), INFO (blue), WARN (yellow), ERROR (red), FATAL (red bold) |
| 28 | +- 📂 **Multi-source input** — files, stdin/pipes, glob patterns (`*.log`) |
| 29 | +- 🔄 **Live tailing** — follows files with rotation handling (rename, truncate) |
| 30 | +- ⏱️ **Flexible timestamps** — relative (`2s ago`), ISO 8601, local time |
| 31 | +- 🌗 **Dark & light themes** — auto-detects terminal background |
| 32 | +- ⌨️ **Vim-style navigation** — `j/k`, `G`, `gg`, `/` search, `n/N` |
| 33 | +- 🚦 **Backpressure handling** — configurable: block or drop-oldest when buffer is full |
37 | 34 |
|
38 | | -### From Release (recommended) |
| 35 | +### Roadmap |
39 | 36 |
|
40 | | -Download the latest binary for your platform from [Releases](https://github.com/clarabennett2626/logpilot/releases/latest). |
| 37 | +- ☸️ Kubernetes pod log source |
| 38 | +- 🐳 Docker container log source |
| 39 | +- 🔐 SSH remote log source |
| 40 | +- 🏷️ Field-based filtering (`level:error service:auth`) |
| 41 | +- 🔗 Trace correlation (group by trace ID) |
| 42 | +- 📊 Timeline visualization |
| 43 | + |
| 44 | +## Quick Start |
41 | 45 |
|
42 | 46 | ```bash |
43 | | -# Linux (amd64) |
44 | | -curl -L https://github.com/clarabennett2626/logpilot/releases/latest/download/logpilot_0.1.0_linux_amd64.tar.gz | tar xz |
45 | | -sudo mv logpilot /usr/local/bin/ |
| 47 | +# View a log file |
| 48 | +logpilot app.log |
46 | 49 |
|
47 | | -# macOS (Apple Silicon) |
48 | | -curl -L https://github.com/clarabennett2626/logpilot/releases/latest/download/logpilot_0.1.0_darwin_arm64.tar.gz | tar xz |
49 | | -sudo mv logpilot /usr/local/bin/ |
50 | | -``` |
| 50 | +# Tail with live follow |
| 51 | +logpilot -f /var/log/app/*.log |
51 | 52 |
|
52 | | -### From Source |
| 53 | +# Pipe from Docker |
| 54 | +docker logs -f my-container 2>&1 | logpilot - |
53 | 55 |
|
54 | | -```bash |
55 | | -go install github.com/clarabennett2626/logpilot/cmd/logpilot@latest |
| 56 | +# Pipe from kubectl |
| 57 | +kubectl logs -f deploy/api-server | logpilot - |
| 58 | + |
| 59 | +# Mix multiple sources with glob |
| 60 | +logpilot services/*.log /var/log/syslog |
56 | 61 | ``` |
57 | 62 |
|
58 | | -### Verify Installation |
| 63 | +## Installation |
| 64 | + |
| 65 | +### Go install (requires Go 1.22+) |
59 | 66 |
|
60 | 67 | ```bash |
61 | | -logpilot --version |
62 | | -# logpilot 0.1.0 (abc1234) built 2026-02-17T... |
| 68 | +go install github.com/clarabennett2626/logpilot@latest |
63 | 69 | ``` |
64 | 70 |
|
65 | | -## Quick Start |
| 71 | +### Binary download |
| 72 | + |
| 73 | +Grab a prebuilt binary from [Releases](https://github.com/clarabennett2626/logpilot/releases/latest): |
66 | 74 |
|
67 | 75 | ```bash |
68 | | -# View a local log file |
69 | | -logpilot app.log |
| 76 | +# Linux (amd64) |
| 77 | +curl -LO https://github.com/clarabennett2626/logpilot/releases/download/v0.1.0/logpilot_linux_amd64.tar.gz |
| 78 | +tar xzf logpilot_linux_amd64.tar.gz |
| 79 | +sudo mv logpilot /usr/local/bin/ |
70 | 80 |
|
71 | | -# Tail a log file (follows new lines) |
72 | | -logpilot -f /var/log/app.log |
| 81 | +# macOS (Apple Silicon) |
| 82 | +curl -LO https://github.com/clarabennett2626/logpilot/releases/download/v0.1.0/logpilot_darwin_arm64.tar.gz |
| 83 | +tar xzf logpilot_darwin_arm64.tar.gz |
| 84 | +sudo mv logpilot /usr/local/bin/ |
73 | 85 |
|
74 | | -# Pipe from another command |
75 | | -kubectl logs -f my-pod | logpilot |
| 86 | +# Windows (amd64) |
| 87 | +# Download logpilot_windows_amd64.zip from the releases page and add to PATH |
| 88 | +``` |
76 | 89 |
|
77 | | -# Streaming demo |
78 | | - |
79 | | -docker logs -f my-container | logpilot |
80 | | -cat /var/log/syslog | logpilot |
| 90 | +### From source |
81 | 91 |
|
82 | | -# Multiple files with glob |
83 | | -logpilot /var/log/*.log |
| 92 | +```bash |
| 93 | +git clone https://github.com/clarabennett2626/logpilot.git |
| 94 | +cd logpilot |
| 95 | +go build -o logpilot ./cmd/logpilot |
84 | 96 | ``` |
85 | 97 |
|
86 | | -## Supported Log Formats |
| 98 | +## Supported Formats |
87 | 99 |
|
88 | | -LogPilot auto-detects the format from the first few lines: |
| 100 | +LogPilot auto-detects the format of each log line independently — you can mix formats in the same stream. |
89 | 101 |
|
90 | 102 | ### JSON |
91 | 103 |
|
92 | | - |
93 | | - |
94 | 104 | ```json |
95 | | -{"timestamp":"2026-02-17T20:30:00Z","level":"error","message":"connection timeout","service":"api","latency_ms":1523} |
| 105 | +{"timestamp":"2026-02-19T12:00:01Z","level":"info","msg":"request handled","method":"GET","path":"/api/users","duration_ms":42} |
| 106 | +{"timestamp":"2026-02-19T12:00:02Z","level":"error","msg":"connection refused","host":"db-primary","port":5432} |
96 | 107 | ``` |
97 | 108 |
|
98 | | -### Logfmt |
| 109 | +<details><summary>See demo</summary> |
| 110 | +<img src="docs/demos/demo-json.gif" alt="JSON log demo" width="640"> |
| 111 | +</details> |
99 | 112 |
|
100 | | - |
| 113 | +### logfmt |
101 | 114 |
|
102 | 115 | ``` |
103 | | -ts=2026-02-17T20:30:00Z level=error msg="connection timeout" service=api latency_ms=1523 |
| 116 | +ts=2026-02-19T12:00:01Z level=info msg="request handled" method=GET path=/api/users duration_ms=42 |
| 117 | +ts=2026-02-19T12:00:02Z level=warn msg="slow query" query="SELECT *" duration_ms=1250 |
104 | 118 | ``` |
105 | 119 |
|
106 | | -### Plain Text |
| 120 | +<details><summary>See demo</summary> |
| 121 | +<img src="docs/demos/demo-logfmt.gif" alt="logfmt log demo" width="640"> |
| 122 | +</details> |
107 | 123 |
|
108 | | - |
| 124 | +### Plain text |
109 | 125 |
|
110 | 126 | ``` |
111 | | -2026-02-17 20:30:00 ERROR connection timeout |
112 | | -Feb 17 20:30:00 myhost app[1234]: connection timeout |
| 127 | +Feb 19 12:00:01 myhost sshd[1234]: Accepted publickey for deploy |
| 128 | +Feb 19 12:00:02 myhost nginx: 192.168.1.1 - GET /health 200 |
| 129 | +``` |
| 130 | + |
| 131 | +<details><summary>See demo</summary> |
| 132 | +<img src="docs/demos/demo-plain.gif" alt="Plain text log demo" width="640"> |
| 133 | +</details> |
| 134 | + |
| 135 | +### Piped input |
| 136 | + |
| 137 | +```bash |
| 138 | +kubectl logs -f deploy/api | logpilot - |
113 | 139 | ``` |
114 | 140 |
|
| 141 | +<details><summary>See demo</summary> |
| 142 | +<img src="docs/demos/demo-pipe.gif" alt="Pipe demo" width="640"> |
| 143 | +</details> |
| 144 | + |
| 145 | +## Keybindings |
| 146 | + |
| 147 | +| Key | Action | |
| 148 | +|---|---| |
| 149 | +| `j` / `↓` | Scroll down | |
| 150 | +| `k` / `↑` | Scroll up | |
| 151 | +| `G` | Jump to bottom (latest) | |
| 152 | +| `g g` | Jump to top | |
| 153 | +| `f` / `Page Down` | Page down | |
| 154 | +| `b` / `Page Up` | Page up | |
| 155 | +| `/` | Start search | |
| 156 | +| `n` | Next search match | |
| 157 | +| `N` | Previous search match | |
| 158 | +| `t` | Toggle timestamp format | |
| 159 | +| `w` | Toggle line wrap | |
| 160 | +| `Tab` | Cycle theme | |
| 161 | +| `q` / `Ctrl+C` | Quit | |
| 162 | + |
| 163 | +## Comparison |
| 164 | + |
| 165 | +| | LogPilot | lnav | hl | tailspin | lazyjournal | |
| 166 | +|---|:---:|:---:|:---:|:---:|:---:| |
| 167 | +| **Interactive TUI** | ✅ | ✅ | ❌ | ❌ | ✅ | |
| 168 | +| **Structured parsing** | ✅ | ✅ | ❌ | ❌ | Partial | |
| 169 | +| **Multi-source** | ✅ | ✅ | ✅ | ✅ | ✅ | |
| 170 | +| **Format-agnostic** | ✅ | Partial¹ | ✅ | ✅ | ❌² | |
| 171 | +| **Language** | Go | C++ | Rust | Rust | Go | |
| 172 | +| **Focus** | Structured log TUI | Log file navigator | Log processor/pager | Highlight & tail | journald/docker/k8s | |
| 173 | + |
| 174 | +¹ lnav supports many formats but requires format definitions for custom structured logs. |
| 175 | +² lazyjournal focuses on journald, Docker, and Kubernetes sources rather than arbitrary log files. |
| 176 | + |
| 177 | +**Honest take:** lnav is the most mature and feature-rich tool here. tailspin and hl are excellent if you want fast, zero-config highlighting for piped output. lazyjournal is great if your logs come from systemd/Docker/k8s. LogPilot occupies the space between — an interactive TUI that understands structured fields across arbitrary log sources. |
| 178 | + |
115 | 179 | ## Architecture |
116 | 180 |
|
117 | 181 | ``` |
118 | | -cmd/logpilot/ → CLI entry point |
119 | | -internal/ |
120 | | - parser/ → Format detection & parsing (JSON, logfmt, plain) |
121 | | - source/ → Log sources (file, stdin; k8s, docker coming soon) |
122 | | - tui/ → Terminal UI rendering (Bubble Tea + Lipgloss) |
123 | | - config/ → Configuration |
124 | | - filter/ → Query engine (coming soon) |
125 | | - merge/ → Multi-source merge (coming soon) |
| 182 | +logpilot/ |
| 183 | +├── cmd/logpilot/ # CLI entrypoint |
| 184 | +├── internal/ |
| 185 | +│ ├── app/ # Bubble Tea application model |
| 186 | +│ ├── parser/ # Format detection + parsing (JSON, logfmt, plain) |
| 187 | +│ ├── source/ # Input sources (file, stdin, glob) |
| 188 | +│ ├── tail/ # File tailing with rotation handling |
| 189 | +│ ├── theme/ # Dark/light theme definitions |
| 190 | +│ ├── buffer/ # Ring buffer with backpressure |
| 191 | +│ └── ui/ # Lipgloss view components |
| 192 | +├── docs/demos/ # GIF demos |
| 193 | +└── go.mod |
126 | 194 | ``` |
127 | 195 |
|
128 | 196 | ## Development |
129 | 197 |
|
130 | 198 | ```bash |
131 | 199 | # Build |
132 | | -go build -o logpilot ./cmd/logpilot/ |
| 200 | +go build ./cmd/logpilot |
| 201 | + |
| 202 | +# Run tests |
| 203 | +go test ./... |
133 | 204 |
|
134 | | -# Test |
135 | | -go test ./... -v -race |
| 205 | +# Run tests with race detector |
| 206 | +go test -race ./... |
136 | 207 |
|
137 | | -# Benchmark |
| 208 | +# Benchmarks |
138 | 209 | go test -bench=. ./internal/parser/ |
139 | 210 |
|
140 | 211 | # Lint |
141 | | -go vet ./... |
| 212 | +golangci-lint run |
142 | 213 | ``` |
143 | 214 |
|
144 | | -## CI/CD |
| 215 | +## Contributing |
145 | 216 |
|
146 | | -- **CI**: Tests run on Go 1.22, 1.23, and 1.24 for every PR and push to main |
147 | | -- **Release**: GoReleaser builds binaries for linux/darwin/windows × amd64/arm64 on version tags |
| 217 | +Contributions are welcome! Whether it's a bug report, feature request, or pull request — all appreciated. |
148 | 218 |
|
149 | | -## Keybindings |
| 219 | +1. Fork the repo |
| 220 | +2. Create a feature branch (`git checkout -b feat/my-feature`) |
| 221 | +3. Commit with clear messages |
| 222 | +4. Open a PR against `main` |
150 | 223 |
|
151 | | -| Key | Action | |
152 | | -|-----|--------| |
153 | | -| `j`/`k` | Scroll down/up | |
154 | | -| `G` | Jump to bottom | |
155 | | -| `gg` | Jump to top | |
156 | | -| `/` | Search | |
157 | | -| `n`/`N` | Next/previous match | |
158 | | -| `q` | Quit | |
| 224 | +Please open an issue first for large changes so we can discuss the approach. |
| 225 | + |
| 226 | +## Acknowledgments |
| 227 | + |
| 228 | +Built on the shoulders of the [Charm](https://charm.sh/) ecosystem: |
| 229 | + |
| 230 | +- [Bubble Tea](https://github.com/charmbracelet/bubbletea) — TUI framework |
| 231 | +- [Lipgloss](https://github.com/charmbracelet/lipgloss) — Styling |
| 232 | +- [Bubbles](https://github.com/charmbracelet/bubbles) — TUI components |
159 | 233 |
|
160 | 234 | ## License |
161 | 235 |
|
162 | | -MIT |
| 236 | +[MIT](LICENSE) |
0 commit comments