██╗ ██████╗ ██████╗ ███████╗██╗ ██╗██████╗ ██╗███╗ ██╗██╗ ██╗
██║ ██╔═══██╗██╔════╝ ██╔════╝██║ ██║██╔══██╗██║████╗ ██║██║ ██╔╝
██║ ██║ ██║██║ ███╗███████╗███████║██████╔╝██║██╔██╗ ██║█████╔╝
██║ ██║ ██║██║ ██║╚════██║██╔══██║██╔══██╗██║██║╚██╗██║██╔═██╗
███████╗╚██████╔╝╚██████╔╝███████║██║ ██║██║ ██║██║██║ ╚████║██║ ██╗
╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝
Turn Terminal Log Flood into Signal. Instantly.
A zero-dependency CLI stream filter that deduplicates repetitive polling floods, highlights multi-line errors, and captures incident postmortems in real time.
⚡ Quickstart • 🤖 GitHub Actions CI • 💥 Problem vs. Solution • 📊 Feature Comparison • 📦 Installation • ⚙️ CLI Reference • 🔬 Architecture • 🚀 Benchmarks • 🧪 Test Suite • 🤝 Contributing
💥 The Problem vs. Solution
When developing or debugging backend microservices, Kubernetes pods, and container clusters:
- Polling Floods: Thousands of identical Kubernetes liveness probes (
GET /healthz 200), database heartbeats (SELECT 1), and Prometheus scrapes scroll by every minute. - Lost Errors: When a real deadlock, panic, or unhandled 500 error occurs, it scrolls off your terminal buffer in 300 milliseconds.
- Brittle Grep Pipelines: Chaining
grep -v "health" | grep -v "metrics"is dangerous—it blindly deletes genuine failures occurring on health endpoints and mutilates multi-line tracebacks.
Side-by-Side Terminal Comparison
┌───────────────────────────────────────────────┐ ┌───────────────────────────────────────────────┐
│ BEFORE: Raw Terminal Flood │ │ AFTER: With LogShrink │
├───────────────────────────────────────────────┤ ├───────────────────────────────────────────────┤
│ 19:00:01 [INFO] GET /healthz 200 (took 0.4ms) │ │ 19:00:01 [INFO] GET /healthz 200 (took 0.4ms) │
│ 19:00:02 [INFO] GET /healthz 200 (took 0.3ms) │ │ [-] [x480 suppressed] [INFO] GET /healthz │
│ 19:00:03 [INFO] GET /healthz 200 (took 0.5ms) │ │ (last seen 19:04:11) │
│ 19:00:04 [INFO] GET /healthz 200 (took 0.4ms) │ │ │
│ ... [480 identical lines flooding buffer] ... │ │ ┌── INCIDENT #1: ERROR ────────────────────── │
│ 19:04:12 [ERROR] Database deadlock! │ │ │ 19:04:12 [ERROR] Database deadlock! │
│ Traceback (most recent call last): │ │ │ Traceback (most recent call last): │
│ File "/app/db.py", line 42, in query │ │ │ File "/app/db.py", line 42, in query │
│ raise OperationalError("deadlock") │ │ │ raise OperationalError("deadlock") │
│ 19:04:13 [INFO] GET /healthz 200 (took 0.3ms) │ │ └──────────────────────────────────────────── │
│ 19:04:14 [INFO] GET /healthz 200 (took 0.4ms) │ │ 19:04:13 [INFO] GET /healthz 200 (took 0.3ms) │
│ │ │ │
│ [CRITICAL ERROR SCROLLED OFF BUFFER] │ │ [NOISE COLLAPSED • ERROR BOXED • 0 DRIFT] │
└───────────────────────────────────────────────┘ └───────────────────────────────────────────────┘
LogShrink solves this with zero configuration. It dynamically aggregates repetitive polling noise into live counter badges like [-] [x480 suppressed] while preserving the first occurrence, auto-boxes multi-line stack traces (Python, Go, Java, Rust, Node.js), and exports incident postmortems straight to Markdown or your system clipboard.
📊 Feature Comparison
Why use LogShrink instead of standard Unix utilities or heavyweight observability platforms?
| Capability | LogShrink | grep -v / awk |
lnav |
grc / colortail |
Datadog / ELK |
|---|---|---|---|---|---|
| Dynamic Suppression | ✅ Yes (live counter badge) | ❌ No (blind deletion) | ⚠️ Manual filter query | ❌ No (all lines printed) | ✅ Yes (server aggregation) |
| First Occurrence Preserved | ✅ Yes (full initial context) | ❌ No (deleted entirely) | ⚠️ Hidden | ❌ No | ✅ Indexed |
| Multi-Line Trace Grouping | ✅ Yes (native 5 languages) | ❌ Breaks multi-line context | ⚠️ Requires format setup | ❌ Line-by-line regex only | ⚠️ Requires backend config |
| Zero Configuration | ✅ Yes (works out of box) | ❌ Complex piped regexes | ⚠️ TUI learning curve | ❌ Requires custom configs | ❌ Daemons & clusters |
| Sub-15ms Cold Start | ✅ Yes (< 15 ms) | ✅ Yes (< 5 ms) | ⚠️ ~150–250 ms | ⚠️ ~50 ms | ❌ N/A (Web UI) |
| External Dependencies | ✅ 0 (pure Python stdlib) | ✅ 0 (POSIX tools) | ⚠️ C++ binaries & libs | ⚠️ Python packages | ❌ Heavy agents & JVM |
| Incident Markdown Export | ✅ --export report.md |
❌ Manual piping | ⚠️ Manual file save | ❌ None | ⚠️ Web dashboard |
| Instant Clipboard Copy | ✅ --copy (1-click Slack paste) |
❌ Pipe to pbcopy/xclip |
❌ None | ❌ None | ❌ Manual |
| Unix Stream & Pipe Friendly | ✅ Native (tail -f, pipes) |
✅ Native | ⚠️ Full-screen TUI | ✅ Native | ❌ Network ingestion |
| Adaptive ANSI Highlighting | ✅ Yes (respects NO_COLOR) |
❌ None | ✅ Yes | ✅ Yes | ❌ Web styling only |
⚡ Quickstart & Production Recipes
LogShrink behaves like a standard Unix pipe: pipe any command into logshrink, or pass files directly.
🐳 Docker & Docker Compose
# Follow all services in Docker Compose
docker compose logs -f --tail=100 | logshrink
# Strip Docker container prefixes and follow specific container
docker logs -f my-api-backend | logshrink -p docker
☸️ Kubernetes Pods & Deployments
# Live stream logs across all replicas of a deployment
kubectl logs -f deployment/api-gateway --tail=50 --max-log-requests=10 | logshrink
# Filter production pod down to warnings and fatal incidents only
kubectl logs -f pod/payment-worker-8d76b -n production | logshrink --errors-only
🐧 Systemd Journal & Linux Daemons
# Nginx or Caddy web server
journalctl -u nginx.service -f -n 200 | logshrink -p web
# Follow any system service cleanly
journalctl -u backend.service -f -o cat | logshrink
🚀 Backend Frameworks
# Python: FastAPI / Uvicorn / Flask
uvicorn app.main:app --reload | logshrink
# Python: Django / Gunicorn
gunicorn config.wsgi:application --access-logfile - | logshrink -p web
# Node.js: Express, NestJS, Next.js
npm run dev | logshrink
# Go: Gin, Fiber, Chi
go run ./cmd/server | logshrink
# Rust: Axum, Actix-web, Tokio
cargo run | logshrink
📋 Instant Incident Report for Slack & GitHub
When an unexpected crash occurs, generate an instant postmortem Markdown report and copy it to your clipboard with a single command:
logshrink /var/log/app.log --export incident_report.md --copy
Generated Markdown Output (incident_report.md):
# 🚨 LogShrink Incident & Noise Reduction Report
- **Generated At**: `2026-10-13 19:04:15`
- **Source**: `/var/log/app.log`
- **Total Lines Processed**: `14,820`
- **Noise Suppressed**: `14,350 (96.8%)`
- **Unique Incidents Detected**: `1`
## 📊 Incident Overview
| ID | Level | Occurrences | First Seen | Last Seen | Summary |
|---|---|---|---|---|---|
| #1 | **ERROR** | 1x | `19:04:12` | `19:04:12` | `ERROR: Database deadlock detected!` |
---
## 🔍 Detailed Incident Logs
### Incident #1 — ERROR (1x)
- **First Seen**: `19:04:12`
- **Last Seen**: `19:04:12`
```log
2026-10-13 19:04:12 [ERROR] Database deadlock detected!
Traceback (most recent call last):
File "/app/db.py", line 42, in query
raise OperationalError("deadlock detected")
---
<a id="demo"></a>
## 🖥️ Live Terminal Walkthrough
Test LogShrink immediately with the included synthetic demo stream:
```bash
python -m logshrink demo.log
2026-10-13 19:00:00.123 [INFO] App initialized on port 8080
2026-10-13 19:00:01.001 [INFO] GET /healthz 200 OK (took 0.4ms)
[-] [x5 suppressed] [INFO] GET /healthz 200 OK (last seen 23:18:49)
▲ 2026-10-13 19:00:06.100 [WARN] High memory consumption detected: 82% threshold reached
2026-10-13 19:00:07.001 [INFO] GET /healthz 200 OK (took 0.4ms)
[-] [x2 suppressed] [INFO] GET /healthz 200 OK (last seen 23:18:49)
┌── INCIDENT #1: ERROR ─────────────────────────────────────────────────
│ 2026-10-13 19:00:09.500 [ERROR] Failed to connect to Redis cache cluster at 10.0.0.45:6379
│ Traceback (most recent call last):
│ File "/app/cache/redis.py", line 48, in connect
│ sock.connect((self.host, self.port))
│ File "/usr/local/lib/python3.12/socket.py", line 710, in connect
│ raise ConnectionRefusedError(errno.ECONNREFUSED, 'Connection refused')
│ ConnectionRefusedError: [Errno 111] Connection refused
└───────────────────────────────────────────────────────────────────────
2026-10-13 19:00:10.001 [INFO] Fallback to in-memory cache activated
2026-10-13 19:00:11.001 [INFO] GET /healthz 200 OK (took 0.2ms)
[-] [x3 suppressed] [INFO] GET /healthz 200 OK (last seen 23:18:49)
─── LogShrink Summary ────────────────────────────────────
Total lines processed : 20
Lines passed through : 13
Lines suppressed : 7 (35.0% noise reduced)
Incidents captured : 1
Processing time : 0.00s (7,263 lines/sec)
──────────────────────────────────────────────────────────
🤖 GitHub Actions CI Integration
Deduplicate noisy build outputs and automatically render clean incident postmortems in your GitHub Actions workflow summary in 3 lines of YAML:
- name: Clean & Summarize CI Logs
uses: umutgungorr/logshrink@v1
with:
log-file: ci-test-run.log
🌟 Why Use LogShrink in GitHub Actions?
- No More CI Truncation: GitHub Actions truncates browser log viewers when output exceeds buffer limits. LogShrink suppresses repetitive polling noise (e.g. health checks, heartbeat pings) while preserving every unique error.
- Native Step Summary: Automatically appends a rich Markdown incident card to
$GITHUB_STEP_SUMMARY, so your team sees root-cause stack traces without downloading raw artifacts. - Cross-Platform Runner Support: Runs seamlessly on
ubuntu-latest,macos-latest, andwindows-latest. - Lightning Fast (< 2s): Zero external dependencies means instant setup and execution in your pipeline.
📋 Full Production Workflow Recipe
name: Test Suite & Service Checks
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Run Integration Tests & Save Log
id: run-tests
run: |
pytest -v 2>&1 | tee test-output.log
continue-on-error: true
- name: Process Logs with LogShrink
id: logshrink
uses: umutgungorr/logshrink@v1
with:
log-file: test-output.log
summary: 'true'
export-file: test-incidents.md
- name: Fail CI if Incidents Detected
if: steps.run-tests.outcome == 'failure' || steps.logshrink.outputs.incident-count > 0
run: |
echo "Detected ${{ steps.logshrink.outputs.incident-count }} critical incidents in test run!"
exit 1
⚙️ Action Inputs
| Input | Description | Required | Default |
|---|---|---|---|
log-file |
Path to the log file to clean and analyze | Yes | — |
summary |
Write formatted markdown incident report to $GITHUB_STEP_SUMMARY |
No | 'true' |
export-file |
File path to export markdown incident report file | No | '' |
options |
Additional CLI flags (e.g. --errors-only, --preset docker) |
No | '' |
fail-on-error |
Fail the action step with exit code 1 if any error incidents are detected | No | 'false' |
📤 Action Outputs
| Output | Description |
|---|---|
incident-count |
Total count of detected unique error incidents and stack traces |
reduced-percentage |
Percentage of repetitive polling noise suppressed (e.g. 85.4) |
suppressed-lines |
Total number of noise lines suppressed |
total-lines |
Total number of lines processed |
📦 Installation
LogShrink has zero external dependencies and works out-of-the-box on Linux, macOS, and Windows with any Python 3.9+ runtime.
⚡ Instant execution with uvx (Zero installation required)
# Run directly from repository
uvx --from git+https://github.com/umutgungorr/logshrink.git logshrink --help
# Pipe anywhere
docker compose logs -f | uvx --from git+https://github.com/umutgungorr/logshrink.git logshrink
🔒 Isolated install via pipx (Recommended for CLI tools)
pipx install git+https://github.com/umutgungorr/logshrink.git
🐍 Standard install via pip
# From GitHub repository
pip install git+https://github.com/umutgungorr/logshrink.git
# Or standard PyPI install (once published)
pip install logshrink
🛠️ Build from source
git clone https://github.com/umutgungorr/logshrink.git
cd logshrink
pip install -e .
⚙️ CLI Reference
usage: logshrink [-h] [-f] [-t THRESHOLD] [-w WINDOW]
[-p {auto,docker,json,web,raw}] [-e]
[--export PATH] [--copy] [-i REGEX]
[--no-color] [--no-stats] [-v]
[FILE ...]
Options & Flags
| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
FILE ... |
— | path |
stdin |
Path to log file(s). Reads continuous stream from standard input if omitted or -. |
--follow |
-f |
bool |
False |
Follow appended file operations in real time (equivalent to tail -f). |
--threshold |
-t |
int |
2 |
Minimum consecutive/pattern occurrences required before collapsing repetitions. |
--window |
-w |
float |
5.0 |
Sliding time-window debounce threshold (in seconds) for recurring patterns. |
--preset |
-p |
choice |
auto |
Log format parser: auto, docker, json, web, raw. |
--errors-only |
-e |
bool |
False |
Discard all routine noise; only output errors, warnings, and stack traces. |
--export |
— | path |
None |
Export all detected error incidents to a formatted Markdown report file. |
--copy |
— | bool |
False |
Copy detected incidents report directly to system clipboard upon completion. |
--ignore |
-i |
regex |
[] |
Regex pattern to discard matching lines completely (repeatable). |
--no-color |
— | bool |
False |
Disable ANSI colors and boxes (also respects standard NO_COLOR=1). |
--no-stats |
— | bool |
False |
Suppress the final noise reduction summary card upon completion. |
--version |
-v |
bool |
— | Show program version and exit. |
--help |
-h |
bool |
— | Show help message and command-line usage. |
Presets
auto(default): Dynamically detects JSON lines, Docker compose container prefixes, and standard ISO/Syslog timestamped logs.docker: Strips container prefixes (e.g.api-server_1 |) and container engine run timestamps.json: Unpacks structured JSON fields (level,msg,message,status,path) into compact human signatures.web: Tailored for HTTP access logs (Nginx, Apache, Caddy, Uvicorn), extracting method, route, and status code.raw: Performs strict line-by-line deduplication without fuzzy masking.
🔬 How It Works: Pipeline Architecture
LogShrink processes streaming log events through a high-performance 5-stage pipeline designed for $O(1)$ constant memory consumption:
┌────────────────────────────────────────────────────────┐
│ Incoming Stream (stdin / tail -f) │
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 1. Ingestion & Preset Tokenizer │
│ • Strips container tags (`backend_1 |`) │
│ • Extracts structured JSON fields (`msg`, `level`) │
│ • Normalizes Web access patterns (`GET /healthz`) │
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 2. Dynamic Pattern Normalizer │
│ • Masks ephemeral timestamps (`<TIMESTAMP>`) │
│ • Masks UUIDs, IPv4/IPv6, hex addresses (`0x7f...`) │
│ • Masks durations (`0.4ms`), ports (`:8080`), sizes │
│ • Computes canonical pattern fingerprint │
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 3. Multi-Pattern Sliding-Window Aggregator │
│ • Maintains separate debouncing state per pattern │
│ • Tracks repetition counts within time window │
│ • Suppresses lines meeting threshold (default: >=2) │
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 4. Incident Boundary Detector │
│ • Detects multi-line traces (Python, Go, Java, │
│ Rust, Node.js async traces) │
│ • Captures HTTP 5xx server exceptions │
│ • Filters false positives (`0 errors`, `err: nil`) │
└───────────────────────────┬────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ 5. Terminal & Incident Exporter │
│ • High-contrast ANSI bounding boxes for incidents │
│ • Live suppression counter badges │
│ • Markdown postmortem report generator │
│ • Direct system clipboard integration │
└────────────────────────────────────────────────────────┘
- Ingestion & Preset Tokenizer: Fast pre-filtering that strips environment artifacts (such as Docker Compose container names or syslog headers) while preserving the underlying message.
- Dynamic Pattern Normalizer: Converts transient variable data into stable tokens without requiring complex regexes from the user. Timestamps, request IDs, IP addresses, memory pointers, and microsecond latencies are unified into a canonical signature.
- Multi-Pattern Sliding-Window Aggregator: Avoids buffer explosions by keeping rolling pattern hashes. If multiple periodic events interleave (e.g., metric scrape A followed by heartbeat B), both are independently tracked and suppressed without losing count.
- Incident Boundary Detector: Inspects lines for error severity tokens and multi-line exception starters across 5 major programming languages. Blocks false positives such as
0 errors foundorerr: nil. - Terminal & Incident Exporter: Highlights true errors inside ANSI border boxes, renders compact badges for collapsed noise, and produces markdown exports for incident postmortems.
🚀 Benchmarks & Performance
Benchmarked against a 100,000-line synthetic log stream (containing interleaved healthchecks, metrics, warnings, and stack traces):
| Benchmark Metric | LogShrink | Standard grep -v Pipeline |
|---|---|---|
| Cold Start Time | < 15 ms (POSIX) / < 50 ms (Win) | ~ 5 ms |
| Stream Throughput | 10,000+ lines/sec | ~ 80,000 lines/sec |
| Memory Consumption (Heap) | < 10 MB (constant $O(1)$) | ~ 10 MB |
| Multi-Line Incident Grouping | Automatic (5 languages) | ❌ Not supported |
| Noise Reduction Ratio | 94% – 99% | Manual regex dependent |
| Crash Context Preservation | 100% (No data loss) | ❌ Breaks multi-line context |
🧪 Comprehensive Test Suite
LogShrink has 100% passing tests with 84% branch coverage:
# Run complete pytest test suite
pytest
# Run tests with detailed line coverage report
pytest --cov=src/logshrink --cov-report=term-missing
The 59-test suite covers:
- ✅ Multi-language stack trace boundaries (Python, Go, Java, Rust, Node.js)
- ✅ Ephemeral masking for UUIDs, IPv4/IPv6, ephemeral ports, hex pointers, durations, and sizes
- ✅ Interleaved recurring pattern collapsing and debouncing
- ✅ False-positive phrase suppression (
err: nil,0 errors,status=ok error=none) - ✅ Web access HTTP 5xx error and 4xx warning boundary isolation
- ✅ Docker JSON file driver log payload extraction
- ✅ Real-time follow mode (
-f) and file rotation handling - ✅ Clean broken pipe handling (
SIGPIPE) in CLI pipelines - ✅ System clipboard (
pbcopy,wl-copy,xclip,clip.exe) and Markdown export formatters
⚡ Part of the Developer Diagnostics Suite
LogShrink is part of the zero-dependency Developer Diagnostics Suite by @umutgungorr:
- 🌲 PortTree: Dev socket tree scanner, Docker proxy unmasker, and process-tree killer.
- ⚡ LogShrink: Zero-config CLI stream filter that collapses noisy polling logs and auto-boxes stack traces.
- 🩺 RepoPulse: Git forensic health, architectural hotspot churn, and bus-factor risk engine.
🤝 Contributing
Contributions, issues, and feature requests are welcome!
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Run formatting and tests (
ruff check . && pytest) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please refer to CONTRIBUTING.md and CODE_OF_CONDUCT.md for detailed guidelines.
📄 License
Distributed under the MIT License. See LICENSE for more information.
Copyright © 2026 Umut Güngör.
Metadata
Release files for logshrink 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| logshrink-1.0.0.tar.gz | 47.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| logshrink-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 78.8 kB
Release files / logshrink-1.0.0.tar.gz
| Download URL | logshrink-1.0.0.tar.gz |
|---|---|
| Size | 47.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
958d41f5705e33c6b1a47a307c73ef6ba330ac314d1db5daf0a00b71acdd0e56
|
|
BLAKE2b-256 checksum How to use checksums |
20d0150d431902f7917f06aad425e62ffd26e4ac32fc2644d6c56afe20aeb583
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / logshrink-1.0.0-py3-none-any.whl
| Download URL | logshrink-1.0.0-py3-none-any.whl |
|---|---|
| Size | 31.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5f2555411588e5015a1dbe40767848ae7ca22fa4e9a638382187051b1566afad
|
|
BLAKE2b-256 checksum How to use checksums |
c118656a65efb4675047a855c0ed83ca3ec591104b70801d0c428a74754d9b97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.4 {"installer":{"name":"uv","version":"0.12.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|