A Node-native log investigator for the terminal. It eats messy, half-structured
app output, the stuff console.log and framework loggers actually emit, and
turns it into something readable: stack traces folded into single events,
noisy repeats collapsed, levels colorized. Plus an AI digest of what went wrong.
- reads logs from a file or stdin
- detects
json,logfmt,common, andsyslogformats automatically - normalizes raw framework-style logs through config-driven regex patterns
- folds stack traces into single events instead of shredding them line by line
- collapses consecutive duplicate entries into
(×N)badges - renders readable terminal output with timestamps, levels, and extra fields
- generates AI summaries of failures through
--summarizewhen provider keys are configured
The terminal log space is crowded but lopsided. lnav (~10k stars, C++) owns
interactive investigation. hl (~3k stars, Rust) owns fast JSON/logfmt
reformatting. Both are excellent and you will not out-perform them on raw speed.
The gaps they leave:
- Unstructured app output.
hlonly speaks JSON and logfmt. The messy reality, raw stdout, ad-hoc logger lines, and multi-line Node/Java/Python stack traces, is unserved. That's logclaw's primary target. - No AI, anywhere. None of the incumbents summarize or triage. logclaw's
--summarizeis the headline, not a bolt-on. - No Node-native option. Every serious tool is Rust/C++/Go. "Runs in the
runtime my app already uses,
npm i -g, just works" is an open lane.
logclaw does not try to win on throughput against a multithreaded Rust tool. It wins on handling the mess and on the AI investigator.
- Node 22+
npm install -g logclawBoth logclaw and lclaw are available after install.
logclaw /var/log/app.log
lclaw /var/log/app.log --level warnRead from stdin:
cat /var/log/nginx/access.log | logclaw
kubectl logs my-pod | logclaw --level error
docker logs my-container | logclaw --summarizeLive tail:
logclaw /var/log/app.log -f
logclaw /var/log/app.log -f --level warnCompressed files:
logclaw /var/log/app.log.gz
logclaw archive/app-2026-05-21.log.gz --level errorClone and run from source:
git clone https://github.com/psandis/logclaw.git
cd logclaw
npm install
npm run dev -- samples/json.log
npm run dev -- samples/spring-boot.log
npm test
npm run build| Command | Purpose | Result |
|---|---|---|
lclaw app.log |
parse a log file | readable terminal output with grouping and repeat collapsing |
lclaw app.log --level warn |
filter by minimum level | only warn, error, and fatal entries shown |
lclaw app.log -f |
live tail a file | new lines rendered as they arrive |
lclaw app.log.gz |
read a compressed file | transparent gzip decompression |
cat app.log | lclaw |
read from stdin | same render pipeline without a file path |
kubectl logs my-pod | lclaw --level error |
triage pod logs | errors only, stack traces grouped |
lclaw app.log --summarize |
AI triage | short plain-text root-cause summary |
lclaw app.log --summarize --errors-only |
AI triage on failures only | tighter digest focused on error events |
lclaw app.log --ai-detect |
infer unknown format with AI | pattern applied for the session |
npm test |
run automated tests (dev) | Vitest suite result |
npm run typecheck |
verify TypeScript correctness (dev) | compile check without emit |
Fixtures live in samples/. Use them to verify each supported format family:
| File | Format | What it proves |
|---|---|---|
json.log |
JSON | structured parsing, repeat collapsing, stack-trace grouping |
logfmt.log |
logfmt | key/value parsing, extras rendering, repeat collapsing |
apache.log |
Apache access + error | common-log detection plus regex-driven raw parsing |
nginx.log |
nginx access + error | common-log detection plus regex-driven raw parsing |
syslog.log |
RFC3164 syslog | syslog detection plus regex-driven raw parsing |
spring-boot.log |
Spring Boot | regex-driven raw parsing and Java stack-trace grouping |
laravel.log |
Laravel | regex-driven raw parsing |
python.log |
Python logging | regex-driven raw parsing and traceback grouping |
mixed.log |
mixed formats | fallback behavior when one file mixes multiple styles |
Run them from the cloned repo:
npm run dev -- samples/json.log
npm run dev -- samples/logfmt.log
npm run dev -- samples/apache.log
npm run dev -- samples/syslog.log| Script | What it does |
|---|---|
npm run dev -- <file> |
run from source through tsx (no build needed) |
npm run build |
compile TypeScript to dist/ |
npm test |
run the Vitest suite |
npm run typecheck |
TypeScript compile check without emitting |
logclaw [file] [options]
lclaw [file] [options]
-l, --level <level> minimum level to show (trace|debug|info|warn|error|fatal)
--format <fmt> force format instead of auto-detect (json|logfmt|common|syslog)
-f, --follow watch the file for new lines and render them as they arrive
--no-color disable ANSI colors
--no-group disable multiline / stack-trace grouping
--no-collapse disable consecutive-repeat collapsing
--no-trace hide grouped stack traces
--summarize print an AI digest of what went wrong
--errors-only with --summarize, only feed error/fatal entries
--ai-detect use AI to infer format when auto-detection returns unknown
Set LOGCLAW_DEBUG=1 to print the detected format + confidence to stderr.
Watch a file and render new lines as they arrive:
lclaw /var/log/app.log -f
lclaw /var/log/app.log -f --level warn
kubectl logs -f my-pod > /tmp/pod.log && lclaw /tmp/pod.log -f--follow requires a file path. Stack-trace grouping and repeat collapsing work the same as in batch mode, carrying state across watch callbacks.
Pass a .gz file directly — logclaw decompresses it transparently:
lclaw /var/log/nginx/access.log.gz
lclaw archive/app-2026-05-21.log.gz --level error
cat backup.log.gz | lclawBoth file and stdin paths are supported. Detection is by .gz extension or gzip magic bytes.
When auto-detection returns unknown and you have a provider key configured, --ai-detect sends a sample of lines to the model and applies the inferred pattern for the session:
lclaw custom-app.log --ai-detect
LOGCLAW_DEBUG=1 lclaw custom-app.log --ai-detect
lclaw custom-app.log --ai-detect --summarizeRequires OPENAI_API_KEY or ANTHROPIC_API_KEY in your environment or .env file. The inferred pattern is session-only and does not modify data/defaults.jsonc.
Default behavior is defined in data/defaults.jsonc.
It defines:
- detection thresholds
- structured field aliases
- regex-driven raw log patterns
- level normalization aliases
- renderer defaults
The runtime loads this file once at startup and threads it through detection, parsing, level normalization, and rendering.
What the config file controls:
| Section | Purpose |
|---|---|
detection |
sample size and confidence threshold for format detection |
parsers.fieldMappings |
which keys count as level, message, and timestamp in structured logs |
rawPatterns |
ordered regex profiles for raw framework and server log formats |
levelAliases |
mapping from raw level words to canonical logclaw levels |
render.timestampSlice |
which part of the timestamp string is shown in terminal output |
render.levelColors |
per-level terminal color selection |
Editing the config file changes behavior without touching parser or renderer code.
Create a local .env from .env.example to enable --summarize.
Supported variables:
| Variable | What it does |
|---|---|
LOGCLAW_AI_PROVIDER |
optional override: openai or anthropic |
OPENAI_API_KEY |
enables OpenAI-backed summaries |
OPENAI_MODEL |
OpenAI model id, defaults to gpt-4.1-mini |
ANTHROPIC_API_KEY |
enables Anthropic-backed summaries |
CLAUDE_API_KEY |
alias for ANTHROPIC_API_KEY |
ANTHROPIC_MODEL |
Anthropic model id, defaults to claude-sonnet-4-20250514 |
CLAUDE_MODEL |
alias for ANTHROPIC_MODEL |
Example:
cp .env.example .env
node dist/index.js samples/spring-boot.log --summarizeAI usage examples:
lclaw samples/spring-boot.log --summarize
lclaw samples/spring-boot.log --summarize --errors-only
cat samples/json.log | lclaw --summarize
LOGCLAW_AI_PROVIDER=anthropic lclaw samples/laravel.log --summarizeWhat --summarize produces:
- a short plain-text triage summary
- the most likely root cause
- which entries to inspect first
- better signal when combined with
--errors-only
Example AI summary output:
The checkout flow is failing because the application tries to read `total` from an undefined cart object during request handling. The primary failure is the `TypeError` in `computeCart`, which then surfaces as an unhandled rejection in `/checkout`. Start with the error event at 09:14:06.440 and the attached stack trace, especially `/app/src/cart.js:42` and `/app/src/routes/checkout.js:17`. The repeated healthcheck lines are unrelated noise.
logclaw/
├── data/
│ └── defaults.jsonc
├── .env.example
├── .gitignore
├── samples/
│ ├── apache.log
│ ├── json.log
│ ├── laravel.log
│ ├── logfmt.log
│ ├── mixed.log
│ ├── nginx.log
│ ├── python.log
│ ├── spring-boot.log
│ └── syslog.log
├── src/
│ ├── ai/
│ ├── parser/
│ ├── render/
│ ├── transform/
│ └── index.ts
├── tests/
│ ├── collapse.test.ts
│ ├── detect.test.ts
│ ├── fixtures.test.ts
│ ├── formats.test.ts
│ └── multiline.test.ts
├── package.json
├── tsconfig.json
└── vitest.config.ts
Other OpenClaw projects:
- dustclaw - disk space analyzer and cleanup CLI
- dietclaw - codebase health and dependency bloat monitor
- feedclaw - RSS/Atom reader and AI digest builder
- wirewatch - network traffic monitoring with AI-assisted anomaly detection
- driftclaw - version drift inspection across environments
- speak2text - speech-to-text CLI
- text2speak - text-to-speech CLI
- asciiclaw - image to ASCII art terminal converter
- unasciiclaw - ASCII art to image converter
- mymailclaw - email scanner, categorizer, and cleaner CLI
source lines
│
▼
detect format src/parser/detect.ts ← samples first ~50 lines, scores each format
│
▼
parse per line src/parser/formats.ts ← json / logfmt / raw fallback
│
▼
group multiline src/transform/multiline.ts ← folds stack traces into one entry
│
▼
collapse repeats src/transform/collapse.ts ← "(×N)" instead of N identical lines
│
▼
render / summarize src/render/pretty.ts , src/ai/summarize.ts
json and logfmt have dedicated parsers. common, syslog, and framework-style raw logs are normalized through config-driven regex patterns plus multiline grouping.
samples/json.log is the quick demo fixture used in the README flow:
09:14:01.221 INFO server listening port=3000
09:14:02.882 INFO healthcheck ok (×3)
09:14:05.101 WARN slow query ms=812 query=SELECT * FROM orders
09:14:06.440 ERROR unhandled rejection in /checkout
TypeError: Cannot read properties of undefined (reading 'total')
at computeCart (/app/src/cart.js:42:18)
at /app/src/routes/checkout.js:17:23
at processTicksAndRejections (node:internal/process/task_queues:95:5)
09:14:07.000 INFO healthcheck ok
-
-f, --followlive tail mode. - Compressed input (
.gz) — transparent decompression for files and stdin. -
--ai-detectformat inference when auto-detection returnsunknown. - Optional: route
src/ai/summarize.tsthrough psclawmcp instead of direct provider calls. - Dedicated
common(Apache/nginx) andsyslogparsers (detection exists, parsers fall back to raw for now). - Register logclaw as a tool in
psclawmcp.
- npm name to confirm. Backup naming if taken:
logsclaw/clawlog. - ESM,
"type": "module", NodeNext resolution, relative imports use.js.
See MIT