No description
Find a file
Hans Hübner 0445904b3b Surface buried error details on continuation lines
Recursively scan records for values held under generic error-shape keys
(error/err/exception/cause/fault) and render each as a compact "name: message"
summary, so a real upstream cause shows even when the top-level message is
generic. Heuristic-only; not tied to any producer's payload layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 06:48:05 +02:00
.gitignore Add logtail: a JSON log formatter for pipes and tail -f 2026-06-10 06:34:52 +02:00
CLAUDE.md Add README and CLAUDE.md 2026-06-10 06:39:48 +02:00
go.mod Add logtail: a JSON log formatter for pipes and tail -f 2026-06-10 06:34:52 +02:00
main.go Surface buried error details on continuation lines 2026-06-10 06:48:05 +02:00
README.md Add README and CLAUDE.md 2026-06-10 06:39:48 +02:00

logtail

A small, fast formatter for JSON logs. It reads from a pipe or follows a file like tail -f, pulls the timestamp, level and message out of each JSON record using heuristics, and prints them as clean, color-coded lines.

It is a single dependency-free Go binary, so it cross-compiles to any platform and drops in anywhere with no runtime requirements.

Features

  • Pipe or follow. Reads JSON log lines from stdin, or follows a file (tail -f style) when given a path.
  • Rotation & truncation aware. When following a file it detects log rotation (a new file at the same path) and in-place truncation, and keeps going — using only portable, poll-based checks.
  • Prefix detection. Many log shippers prepend things like a timestamp and a stream id before the JSON (2026-06-10T04:20:40.796000+00:00 splitter/… {…}). logtail detects that prefix, folds a timestamp into the record, and keeps the rest available.
  • Heuristic field extraction. Finds the timestamp (timestamp, time, ts, @timestamp, …), level (level, severity, lvl, …) and message (message, msg, text, …) across common key names.
  • Timestamp normalization. Reformats timestamps — ISO 8601 variants or Unix epoch (s/ms/µs/ns) — to one canonical layout. Values it can't parse are left untouched.
  • Never drops a line. Any line that isn't valid trailing JSON is passed through verbatim, so nothing silently disappears.

Install

With the Go toolchain:

go install .          # from a clone; installs to $(go env GOPATH)/bin

Or build and place the binary on your PATH:

go build -o logtail .
install -m 755 logtail /usr/local/bin/logtail

Cross-compile for another machine (static, no dependencies — just copy the file over):

GOOS=linux  GOARCH=amd64 go build -o logtail-linux-amd64 .
GOOS=linux  GOARCH=arm64 go build -o logtail-linux-arm64 .

Usage

# follow a file (tail -f style, survives rotation/truncation)
logtail /var/log/app.log

# read from a pipe
my-service | logtail
kubectl logs -f pod | logtail

Options

Flag Description
-from-start Read the file from the beginning instead of following from the end
-x, -extra Also print the remaining JSON fields (dimmed)
-local Render normalized timestamps in local time instead of UTC
-no-color Disable ANSI colors (also auto-disabled when output is not a TTY)

Example

Input:

2026-06-10T04:20:40.796000+00:00 splitter/splitter/3bed8ce3 {"accountId":"e8d3…","level":"info","message":"splitter: shard parsed","records":10000,"timestamp":"2026-06-10T04:20:40.795Z"}
this is a plain log line with no JSON

Output:

2026-06-10 04:20:40.795 INFO  splitter: shard parsed
this is a plain log line with no JSON

Add -x to append the remaining fields (accountId=… records=10000 …) dimmed after the message.