Pipe your JSON log output into peacock and get colorized, readable, interactively filterable log streams in the terminal.
go run . | peacock
kubectl logs -f my-pod | peacock
peacock -f app.log- Zero-config JSON formatting — Automatically highlights levels (
ERROR,WARN,INFO,DEBUG), timestamps, callers, andkey=valuecontext while passing non-JSON lines through untouched. - Scroll up to auto-pause — Use your mouse wheel,
Up, orPageUpto inspect log history while new entries continue buffering in the background. PressSpaceto resume live tailing. - Live stacked filtering — Press
/to filter logs on the fly, stack multiple filters to drill into noisy streams, and hitBackspaceto pop the last filter. - Built for fast streams — Decoupled 30fps batched rendering ingests 70,000+ JSON lines/sec in a real terminal without freezing your UI.
Homebrew (macOS & Linux):
brew install dubeyKartikay/peacock/peacockTroubleshooting Homebrew tap trust
If Homebrew reports an untrusted tap, trust the formula and retry:
brew tap dubeyKartikay/peacock
brew trust --formula dubeykartikay/peacock/peacock
brew install peacockOne-liner (macOS & Linux) — installs the latest release to ~/.local/bin:
curl -fsSL https://raw.githubusercontent.com/dubeyKartikay/peacock/main/install.sh | bashWith Go:
go install github.com/dubeyKartikay/peacock/cmd/peacock@latestManual binary install (Linux, macOS, Windows)
Pre-built binaries are available on the releases page.
# Extract the archive (replace filename with your platform's download)
tar -xzf peacock_Linux_x86_64.tar.gz
# Copy the binary to a directory on your PATH (e.g. /usr/local/bin)
sudo cp peacock /usr/local/bin/
# Verify the install
peacock --help# Read a file
peacock app.log
# Tail a file (follow mode)
peacock -f app.log
# Tail the last 50 lines of a file
peacock -f -n 50 app.log
# Pipe stdin
your-app | peacock| Flag | Default | Description |
|---|---|---|
-f, --follow |
false |
Follow appended lines (like tail -f) |
-n, --lines |
10 |
Number of lines to read from end of file on startup |
--config |
Platform default | Path to a custom config file |
| Key | Action |
|---|---|
Space |
Pause / resume live tail |
/ |
Enter filter mode (press Enter to apply) |
Esc |
Cancel filter entry and keep active filters |
Backspace |
Remove last active filter |
| Mouse wheel | Scroll logs; scrolling up pauses live output |
Up |
Scroll up one line and pause live output |
g |
Jump to top and pause live output |
G |
Jump to bottom |
PageUp / Ctrl+B |
Scroll up one page and pause live output |
PageDown / Ctrl+F |
Scroll down one page |
Ctrl+C |
Quit |
Scrolling down or pressing G keeps the view paused. Press Space to resume
live output. New logs continue to arrive in the bounded queue while paused.
peacock parses each line as JSON and renders it with structured formatting and color:
- Level: color-coded:
ERROR/FATALin red,WARNin yellow,INFOin green,DEBUGin cyan - Timestamp: dimmed, pulled from
timeortimestampfields - Message: bright white, pulled from
msgormessagefields - Caller: pulled from
callerorfilefields - Context: all remaining fields rendered as dimmed
key=valuepairs
Non-JSON lines are printed as-is without any transformation.
The config file location depends on your platform:
| Platform | Path |
|---|---|
| Linux | $XDG_CONFIG_HOME/peacock/config.yaml (falls back to ~/.config/peacock/config.yaml) |
| macOS | ~/Library/Application Support/peacock/config.yaml |
| Windows | %AppData%\peacock\config.yaml |
The directory and file are created automatically on first run if they don't exist.
buffer:
max_entries: 5000 # Max log entries to keep in memory
input:
batch_max_entries: 256
batch_interval: 33ms
filter_prompt: "/ " # Prompt shown in filter mode
filter_placeholder: "filter logs"
filter_char_limit: 256
scanner_initial_buffer_bytes: 65536 # 64KB
scanner_max_buffer_bytes: 1048576 # 1MB
source:
file_tail_lines: 10 # Lines to read from end of file (-n default)
file_poll: true # Use polling instead of inotify
file_reopen: false # Reopen file if rotated/replaced
theme:
level_error: "9" # Color for ERROR/FATAL (256-color ANSI)
level_warn: "11" # Color for WARN
level_info: "10" # Color for INFO
level_debug: "14" # Color for DEBUG
level_other: "7" # Color for unrecognized levels
level_bold: true
timestamp_fg: "7"
timestamp_faint: true
message_fg: "15"
caller_fg: "4"
context_fg: "5"
raw_fg: "7"
panel_border: "8"
status_fg: "7"
filter_fg: "15"
filter_bg: "8"Theme colors accept either a 256-color ANSI code (e.g. "9") or a hex color string (e.g. "#ff5f5f").
Config values are resolved in this order (highest to lowest):
- Environment variables: overrides everything
config.yaml: your config file- Defaults: built-in fallback values
Any config key can be set via an environment variable using the PEACOCK_ prefix. Nested keys are joined with _:
PEACOCK_BUFFER_MAX_ENTRIES=10000 # buffer.max_entries
PEACOCK_INPUT_BATCH_INTERVAL=50ms
PEACOCK_THEME_LEVEL_ERROR="#ff0000" # theme.level_error
PEACOCK_SOURCE_FILE_POLL=false # source.file_pollgo test ./...
go test ./testdata/stress-test/...
go test -race ./...The VHS UI suite generates deterministic logs and checks static files, stdin pipes, and followed files against recorded terminal snapshots:
brew install vhs ffmpeg
make test-ui
python3 scripts/test-ui-vhs.py run --rate 2000Recordings, screenshots, generated tapes, and the JSON/Markdown reports are written to
results/vhs-ui/. Static file mode renders and exits at EOF; the live modes
exercise filtering, arriving logs, pause/resume, history navigation, and quitting.
Bubble Tea commands read up to input.batch_max_entries available entries at a
time. Pending entries are flushed into the view by tea.Tick after
input.batch_interval (33 ms by default, roughly 30 frames per second). Empty
reads retry after the same interval. Filter changes, pause/resume, resizing, and
input completion flush immediately;
ordinary typing and downward navigation keep pending input queued until the tick.
Upward navigation pauses on the currently displayed logs. History
and pending entries stay bounded by buffer.max_entries, including while paused.
Both batch settings must be positive; the interval accepts durations such as
16ms or 50ms.
Ctrl+C quits immediately without flushing pending entries or rebuilding the view.
To compare two built binaries on macOS or Linux:
make build
python3 scripts/benchmark-throughput.py /path/to/baseline/peacock ./target/peacock --lines 5000 --runs 3The benchmark pipes a finite, deterministic JSON stream into each viewer in a
70×240 pseudo-terminal and waits until its final entry appears in terminal output.
It reports JSON results and median throughput, including process startup and
rendering. This measures burst ingestion with rolling history, rather than a
sustained generator rate. Use --rows, --cols, and --timeout to vary the setup.
The following items are planned but not yet implemented.
- Logfmt support: v0 only parses JSON; logfmt auto-detection is deferred
- Multi-file multiplexing: tail multiple files simultaneously with per-source tagging
- Complex log rotation handling: re-attaching to rotated/moved files without restarting
- In-message syntax highlighting: highlight IPs, UUIDs, durations, and other patterns inside log messages
- Stack trace parsing: multi-line stack traces currently print as raw strings
- Custom JSON key mapping: CLI flags or config to define which keys map to level/message/timestamp/caller







