A fast, cross-platform replacement for Tail that can follow multiple log files simultaneously, annotate each line with timestamps, and color output by source file.
- Follow multiple files: Behaves like
tail -fbut for multiple files at once - File rotation detection: Automatically detects when files are truncated or replaced
- Timestamp injection: Prefixes each line with ISO-8601 timestamp and source file name
- Color-coded output: Each file gets a deterministic color for easy identification
- Regex filtering: Filter lines by pattern with
--grep - JSON support: Pretty-print structured JSON logs
- Time filtering: Start from a specific time with
--since - Cross-platform: Works on Linux, macOS, and Windows
# Clone the repository
git clone https://github.com/myferr/foxtail
cd foxtail
# Install Crystal (if not already installed)
# Visit: https://crystal-lang.org/install/
# Build the binary
shards build
# (Optional) Install system-wide
sudo cp bin/foxtail /usr/local/bin/foxtail [options] <file...>| Flag | Description |
|---|---|
-n, --lines=N |
Output last N lines |
-f, --follow |
Follow file(s) (default) |
--no-follow |
Don't follow, just read once |
--grep <regex> |
Filter lines by regex pattern |
--ignore-case |
Case-insensitive grep |
--json |
Enable JSON pretty-printing |
--no-color |
Disable ANSI colors |
--since <duration> |
Start from last N seconds/m/h/d |
-h, --help |
Show help message |
-v, --version |
Show version |
foxtail /var/log/app.logOutput: Just the colored line content without timestamp or filename.
foxtail /var/log/app.log /var/log/error.logfoxtail /var/log/*.logfoxtail --grep "error" /var/log/app.logfoxtail --grep "error" --ignore-case /var/log/app.logfoxtail --json /var/log/app.logInput:
{"level":"error","msg":"db failed","requestId":"abc"}Output:
2026-01-05T15:02:11.432Z [app.log] ERROR db failed requestId=abc
foxtail --since 5m /var/log/app.logfoxtail --no-color /var/log/app.log | grep "error"foxtail --no-follow /var/log/app.logfoxtail --json --grep "error" --since 1h /var/log/*.logJust shows colored content (clean output, similar to tail -f):
Server started on port 8080
Connection established
Request received: GET /api/users
Each line is prefixed with timestamp and filename:
<timestamp> [filename] <content>
Example:
2026-01-05T15:02:11.432Z [api.log] Server started on port 8080
2026-01-05T15:02:12.123Z [db.log] Connection established
2026-01-05T15:02:15.456Z [api.log] Request received: GET /api/users
When using --json, foxtail attempts to parse each line as JSON and formats it nicely:
- Extracts
levelorseverityfield (uppercased) - Extracts
msgormessagefield - Displays other fields as
key=valuepairs
Example:
Input:
{"level":"info","msg":"Request completed","requestId":"xyz","duration":"23ms"}Output:
2026-01-05T15:02:11.432Z [app.log] INFO Request completed requestId=xyz duration=23ms
Non-JSON lines are displayed as-is.
foxtail automatically detects when log files are:
- Truncated (log rotation)
- Replaced (deleted and recreated)
In both cases, it continues following the file from the beginning.
- Low CPU usage: Efficient polling with configurable intervals
- Minimal overhead: Only reads new data, doesn't re-read entire files
- Scalable: Can monitor dozens of files simultaneously
0: Success1: Error (invalid arguments, file not found, etc.)
SIGINT(Ctrl+C): Clean shutdownSIGTERM: Clean shutdown
- Crystal 1.13.0 or later
- No external dependencies
MIT