A powerful terminal-based log viewer with an interactive interface. View and filter logs from PM2, Docker containers, files, or stdin with real-time updates and advanced filtering capabilities.
- Multiple Log Sources: Read from PM2 processes, Docker containers, Docker services, files, or stdin
- Interactive TUI: Built with React/Ink for a smooth terminal experience
- Real-time Updates: Follow logs as they're written with automatic updates
- Advanced Filtering: Filter by log level, field values, or custom expressions
- Search: Find specific entries with forward/backward search
- Custom Fields: Add or remove fields from the display
- Sorting: Sort logs by timestamp across multiple sources
- Selection: Mark and navigate between selected log entries
- Inspection: Detailed YAML view of any log entry
npm install -g uncloggr
# or
yarn global add uncloggruncloggr [OPTIONS] [sources...]-a, --all- Include all sources (e.g., stopped Docker containers)-f, --follow- Follow log output (default: true)--since <string>- Show logs since timestamp (e.g., "2013-01-02T13:23:37Z") or relative (e.g., "42m")-n, --tail <string>- Number of lines to show from the end of logs-s, --sort- Sort logs by timestamp (slower but useful for multiple sources)-h, --help- Show help-v, --version- Show version
Sources can be specified with optional type prefixes:
pm2:<pattern>- PM2 process matching patterndocker:<pattern>- Docker container matching patterndocker-service:<pattern>- Docker service matching patternfile:<path>- Log file at pathstdin:-- Read from stdin<pattern>- Auto-detect source type
If no source is specified and stdin is not a TTY, reads from stdin. Otherwise, prompts for source selection.
# View logs from a PM2 process
uncloggr pm2:api-server
# View logs from a Docker container
uncloggr docker:nginx
# View a log file
uncloggr file:/var/log/app.log
# Follow multiple sources with sorting
uncloggr --sort docker:api docker:worker
# Read from stdin
tail -f /var/log/app.log | uncloggr
# Show last 100 lines from all Docker containers
uncloggr --all --tail 100 docker:You would think node index.js | uncloggr would work, and sometimes it does, but unfortunately node.js messes with terminal state when it exits, leaving uncloggr in a broken state. You can work around this by making sure neither of stdin/stdout/stderr is a tty. You can do this using the following:
node index.js </dev/null 2>&1 | uncloggr
This will also make sure stderr is sent to uncloggr. It can also be combined with node --watch. You can add the following to .bashrc to make it easier to type:
upipe() {
"$@" </dev/null 2>&1 | uncloggr
}Now you can type upipe node --watch index.js instead.
If you often run this on remote servers using ssh, you can either install and run it on the remote host, or you can use DOCKER_HOST environment variable and run it locally.
When running it locally, it may take longer to load the log contents, but the user-interface will be less laggy.
DOCKER_HOST=ssh://root@myhost.com uncloggr <args>To avoid typing this long command, you can add the following to your .bashrc (or similar):
u() {
local host="$1"
shift
DOCKER_HOST="ssh://${host}" uncloggr "$@"
}And you can now type u root@myhost.com <args> instead.
When using the docker-service: source, docker service logs is used to read logs. This is sometimes buggy, causing it show incomplete logs. This is also why docker services are not suggested by default unless you specify docker-service:.
jor↓- Move down one linekor↑- Move up one lineCtrl+dorPageDown- Move down half pageCtrl+uorPageUp- Move up half pagehor←- Select previous fieldlor→- Select next fieldg- Go to first lineG- Go to last lineF- Follow mode (jump to end)
1-6- Filter by log level (1=TRACE, 2=DEBUG, 3=INFO, 4=WARN, 5=ERROR, 6=FATAL)+- Filter to entries where selected field equals current value-- Filter out entries where selected field equals current value&- Add custom text filter=- Add custom expression filterBackspace- Remove last filterMeta+Backspace- Clear all filters
/- Search forwardn- Next search resultN- Previous search result
Space- Toggle selection on current linem- Jump to next selected lineM- Jump to previous selected lines- Sort messages by timestamp
*- Add new field to display\- Remove selected field from display
Enter- Toggle detailed inspection viewc- Clear all messagesq- Quit
↑or↓- Scroll inspection pane one lineshift+↑orshift+↓- Next/previous log item when in inspector viewCtrl+dorPageDown- Scroll inspection pane down half pageCtrl+uorPageUp- Scroll inspection pane up half pageEnterorEsc- Exit inspection view
uncloggr works best with JSON-formatted logs, and is expected to be used with pino/bunyan. Each log entry should be a JSON object on a single line. Common fields:
time- Timestamp (ISO 8601 format)level- Numeric log level (10=TRACE, 20=DEBUG, 30=INFO, 40=WARN, 50=ERROR, 60=FATAL)name- Logger name or componentmsg- Log message- Any other custom fields
Non-JSON lines are treated as plain text messages with level 100 (INVALID).
{"time":"2025-10-30T12:34:56.789Z","level":30,"name":"api","msg":"Request received","method":"GET","path":"/users"}# Install dependencies
yarn install
# Build
yarn build
# Watch mode for development
yarn devISC