BinlogViz is a local CLI for MySQL ROW binlog analysis. It is built for DBAs and operators who need to quickly answer practical questions from real binlog files: which tables are absorbing the most writes, which transactions are unusually large, where spikes happened, and how workload changed over a time window.
The Cobra command layer streams normalized binlog events into the analyzer, then delegates stable machine and human presentation to report, compare, and trend modules.
| Module | Responsibility | Documentation |
|---|---|---|
cmd/binlogviz |
CLI commands and end-to-end orchestration | README |
internal/binlog |
Binlog parsing, probing, and normalization | README |
internal/analyzer |
Streaming aggregation and diagnostics | README |
internal/model |
Shared analysis and evidence types | README |
internal/report |
Analyze text, JSON, Markdown, and HTML renderers | README |
internal/i18n |
Embedded English and Simplified Chinese presentation messages | README |
internal/compare |
Two-report comparison and rendering | README |
internal/trend |
Ordered multi-snapshot trend analysis and rendering | README |
internal/snapshot |
Named analyze snapshot persistence | README |
internal/workflow |
Multi-step investigation plans and manifests | README |
BinlogViz is a fast ROW-binlog summary: hot tables, write shapes, and before/after compare. A 510 MB file is typically a few seconds.
It is not a full STATEMENT/MIXED analyzer — those files come back empty or undercounted (only ROW images are counted). Printed positions are file evidence; use them as mysqlbinlog --start-position only when the reported span covers the transaction events, not an XID-only interval.
curl -fsSLO https://raw.githubusercontent.com/Fanduzi/BinlogVisualizer/main/cmd/binlogviz/testdata/minimal.binlog
binlogviz analyze minimal.binlogThe same 1500-byte fixture lives at cmd/binlogviz/testdata/minimal.binlog in the repo. Each GitHub Release tar.gz also includes that file as testdata/minimal.binlog, a discovery-layout copy at testdata/sample-binlog/mysql-bin.000001, and an incident.yaml whose from_dir points at that directory. After extract, ./binlogviz analyze testdata/minimal.binlog and ./binlogviz workflow run incident.yaml do not need a clone.
binlogviz analyze mysql-bin.000123analyze exits 0 when at least one event was counted, 1 when the file could not be analyzed (corrupt, truncated, or no Format Description), and 2 when a complete binlog parsed but counted zero events (empty --start/--end window, or Format Description / rotate only). Exit 2 writes nothing to stdout and one Error: line to stderr.
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin.binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--start "2026-03-15T10:00:00Z" \
--end "2026-03-15T10:30:00Z"--start/--end also accept YYYY-MM-DD HH:MM:SS in the local timezone of the machine running binlogviz. Prefer RFC3339 with an explicit offset across machines.
Positions are exact event boundaries on one explicit file and use a half-open [start, stop) range. Time flags may be supplied too; the predicates intersect.
binlogviz analyze mysql-bin.000015 --start-position 1651 --stop-position 4096
binlogviz analyze mysql-bin.000015 --include-gtids '24bc7850-2c16-11e6-a073-0242ac110002:7-12'
binlogviz analyze mariadb-bin.000015 --include-gtids '0-7-1857,0-7-1859' --exclude-gtids '0-7-1859'binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--include-schema orders \
--include-table payments--include-table / --exclude-table accept TABLE or SCHEMA.TABLE.
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. --format json > analyze.jsonbinlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--start "2026-03-15T10:00:00Z" \
--end "2026-03-15T10:30:00Z" \
--workload-id orders-production \
--format json \
--snapshot-name incident_current
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--start "2026-03-08T10:00:00Z" \
--end "2026-03-08T10:30:00Z" \
--workload-id orders-production \
--format json \
--snapshot-name incident_baseline
binlogviz snapshot list
binlogviz snapshot list --format json
binlogviz snapshot show incident_current
binlogviz snapshot show incident_current --format json
binlogviz snapshot rename incident_current incident_current_renamed
binlogviz snapshot delete incident_current_renamed
binlogviz compare \
--current-snapshot incident_current \
--baseline-snapshot incident_baseline \
--format html > compare.htmlWhen --snapshot-name is set, analyze --format json still writes the JSON report to stdout and also saves the same payload under ~/.binlogviz/snapshots/<name>.json. The save confirmation is printed to stderr.
snapshot list now prints a human-readable table with name, label, created_at, input_mode, and window. snapshot list --format json and snapshot show --format json still provide stable machine-readable output for scripts and external tooling. snapshot rename keeps the stored snapshot identity in sync with the renamed file, and snapshot delete removes one saved snapshot without touching the rest of the store.
compare can load either two saved snapshots or two JSON files generated by binlogviz analyze --format json. It renders text, json, or html output. Raw numeric deltas are always available, while causal findings, recommendations, and drilldowns require an explicit matching non-empty --workload-id plus compatible report-v3 provenance, scope, and complete transaction evidence. Server IDs, versions, schemas, filenames, and producer flavor remain visible evidence but never prove workload identity. Missing identity or legacy v0-v2 metadata produces an unknown comparability guard; conflicting identity, producer flavor, or scope produces not_comparable. The text and HTML variants show that guard first and suppress ordinary causal narrative.
The compare report is written to stdout. If the compare command fails, the CLI reports the error through stderr.
binlogviz trend incident_week1 incident_week2 incident_week3 --format text
binlogviz trend --from-snapshots 'incident_week*' \
--baseline-snapshot baseline_weekly \
--format html > trend.htmltrend loads saved snapshots, orders them by effective window start time, and renders text, json, or html output. It applies the same comparability verdict across the optional baseline and every trend point: one unknown or not_comparable input suppresses causal findings, recommendations, and drilldowns for the series while preserving raw points and movements. New snapshots use snapshot.window.start_time; older snapshots can fall back to summary.start_time for ordering, but their legacy metadata cannot establish comparability.
The repository ships a runnable incident.yaml that points at the 1500-byte ROW sample in cmd/binlogviz/testdata/sample-binlog. From the repository root, this first command does not need a local /var/lib/mysql. Release archives ship a separate incident.yaml whose from_dir is testdata/sample-binlog so the same command works after extract:
binlogviz workflow run incident.yaml
tree artifacts/incidentThe same plan and fixture are also available as raw URLs:
- plan: https://raw.githubusercontent.com/Fanduzi/BinlogVisualizer/main/incident.yaml
- sample binlog: https://raw.githubusercontent.com/Fanduzi/BinlogVisualizer/main/cmd/binlogviz/testdata/sample-binlog/mysql-bin.000001
workflow run executes a declarative YAML plan that defines analysis windows, optional compare jobs, and optional trend jobs. It produces a deterministic artifact directory with analyze/, compare/, trend/, a manifest.json that records every step's status and output path, and an index.html landing page. manifest.json always persists a workflow_summary object with findings, recommendations, and warnings arrays. BinlogViz rebuilds that summary best-effort from successful compare/trend JSON artifacts only; missing or unreadable summary inputs become warnings and never change workflow or step status semantics. When summary items exist, index.html surfaces them as Workflow Recommendations, Workflow Findings, and Workflow Summary Warnings, linking to the preferred HTML source report and falling back to JSON when needed. stdout stays empty in v1; all status goes to stderr. See CLI Reference for the plan schema and flags.
If a workflow run fails partway through, workflow resume picks up from the existing output directory: it reuses successful steps, reruns failed or missing ones, and supports --rerun selectors to force specific steps. After a fully successful run, workflow resume exits 0 and prints nothing to resume on stderr; use --rerun to force work. Resume refuses to proceed if the plan file changed or the manifest is from a legacy pre-v2 run. Resume also rejects plan paths that resolve outside the workflow root or escape via symlinks (trust-boundary hardening). workflow status reports the same trust check: an untrusted plan still produces full status output but sets resumable to false with a trust-boundary resume_error.
Before execution, workflow validate checks whether a plan is statically runnable from plan.yaml alone, and workflow describe previews the deterministic analyze / compare / trend artifact layout that the plan would produce. Both commands support --format text and --format json, read only the plan file, and do not inspect output_dir, manifest.json, or index.html. workflow validate still exits 0 for a structurally valid plan, but warns when defaults.input.from_dir looks like a placeholder or does not exist.
workflow status is the read-only runtime inspection command for an existing workflow root. It reads manifest.json, checks artifact presence, reports runtime_state, resumable, and resume_error, carries the persisted workflow_summary through --format json, and includes a dry resume_preview when the saved plan can still be loaded. Text output renders Workflow Recommendations, Workflow Findings, and Workflow Summary Warnings only when those persisted arrays are non-empty. It never executes steps, never rebuilds workflow summary, and never rewrites workflow outputs.
workflow clean is the final maintenance command in that lifecycle. It uses the current manifest as the source of truth, defaults to dry-run, reports orphaned generated artifacts under analyze/, compare/, and trend/, and can optionally include orphaned snapshot JSON files when --include-snapshots is set. --apply performs best-effort deletion, while still refusing to touch manifest.json, index.html, plan files, or unknown out-of-scope files.
workflow export is the read-only handoff command for a completed workflow root. It reads manifest.json, bundles manifest-declared artifacts into a deterministic zip archive, includes manifest.json and best-effort index.html, and optionally includes referenced snapshots with --include-snapshots. It never reruns steps and rejects archive paths inside the workflow root.
binlogviz workflow resume ./artifacts/incident
binlogviz workflow resume ./artifacts/incident --rerun analyze:week2
binlogviz workflow status ./artifacts/incident
binlogviz workflow status ./artifacts/incident --format json
binlogviz workflow clean ./artifacts/incident
binlogviz workflow clean ./artifacts/incident --apply --include-snapshots
binlogviz workflow export ./artifacts/incident
binlogviz workflow export ./artifacts/incident --include-snapshots --format json
binlogviz workflow validate incident.yaml
binlogviz workflow validate incident.yaml --format json
binlogviz workflow describe incident.yaml
binlogviz workflow describe incident.yaml --format json# Markdown — paste into GitHub issues, wikis, or docs
binlogviz analyze mysql-bin.000123 --format markdown > report.md
# HTML — redirected stdout receives the document
binlogviz analyze mysql-bin.000123 --format html > report.html
# HTML — explicit output path
binlogviz analyze mysql-bin.000123 --format html --output report.html
# HTML — force stdout (or omit --output when stdout is already redirected)
binlogviz analyze mysql-bin.000123 --format html --output -The HTML report includes interactive charts (rows/txns per minute, top tables, operation mix), optional pattern drilldowns for high-signal write patterns, and a five-theme switcher.
For incident triage, the target for a 1 GB single-binlog analyze run is 10 seconds on the target DBA environment. Runs above 15 seconds should be treated as performance failures and profiled with pprof.
Default --detail-store none produces JSON equivalent to --detail-store duckdb while reducing peak RSS by roughly 38% (measured on a 988 MB MySQL 8.0 ROW binlog). Wall time remains parser/streaming-bound.
Recommended manual check:
time binlogviz analyze /path/to/mysql-bin.000044 --format text > /tmp/binlogviz-text.txt
time binlogviz analyze /path/to/mysql-bin.000044 --format html --output /tmp/binlogviz.htmlText output is intended to stay on a fast diagnostic path. HTML output builds the full visual evidence report.
BinlogViz is optimized for these common DBA questions:
- Which tables are taking the heaviest write load?
- Which transactions are large enough to deserve attention?
- Did a spike happen at a specific minute?
- What changed inside a known incident window?
- How does the current window differ from a trusted baseline report?
- Can I hand the result to another script or pipeline safely?
Homebrew is macOS-only. Linux users should use the tarball or install.sh one-liner below.
brew tap Fanduzi/binlogviz
brew install --cask binlogvizThis path installs the prebuilt release artifact and removes the macOS quarantine attribute during installation, so you do not need to install DuckDB separately.
# install.sh (current release)
curl -fsSLO https://raw.githubusercontent.com/Fanduzi/BinlogVisualizer/v0.23.7/install.sh
sh ./install.sh --version v0.23.7
# or linux/amd64 tarball
curl -fsSLO https://github.com/Fanduzi/BinlogVisualizer/releases/download/v0.23.7/binlogviz_0.23.7_linux_amd64.tar.gz
tar -xzf binlogviz_0.23.7_linux_amd64.tar.gz
install ./binlogviz /usr/local/bin/binlogvizDownload the release archive for your platform from GitHub Releases, verify the checksum, and move the binary onto your PATH.
The authoritative release artifacts are produced by the GitHub Actions release workflow. macOS artifacts are built on native runners, while Linux artifacts are built inside a manylinux2014 userspace so the glibc baseline stays compatible with CentOS 7 / glibc 2.17. Local goreleaser is intended for config validation and optional current-host checks, not as the primary release path.
Example for darwin/arm64 and the current release v0.23.7:
curl -fsSLO https://github.com/Fanduzi/BinlogVisualizer/releases/download/v0.23.7/binlogviz_0.23.7_darwin_arm64.tar.gz
curl -fsSLO https://github.com/Fanduzi/BinlogVisualizer/releases/download/v0.23.7/binlogviz_0.23.7_checksums.txt
shasum -a 256 -c binlogviz_0.23.7_checksums.txt 2>/dev/null | grep "binlogviz_0.23.7_darwin_arm64.tar.gz: OK"
tar -xzf binlogviz_0.23.7_darwin_arm64.tar.gz
install ./binlogviz /usr/local/bin/binlogvizOr fetch the install helper from the same release tag before running it:
curl -fsSLO https://raw.githubusercontent.com/Fanduzi/BinlogVisualizer/v0.23.7/install.sh
sh ./install.sh --version v0.23.7To preview the resolved artifact without downloading:
./install.sh --version v0.23.7 --dry-rungit clone https://github.com/Fanduzi/BinlogVisualizer.git
cd BinlogVisualizer
go build -o binlogviz .
go install .
go run . analyze <binlog files...>If you build from source without release ldflags, binlogviz --version reports dev instead of a tagged release version.
binlogviz --version
binlogviz versionbinlogviz --versionprints only the version stringbinlogviz versionprints the ASCII logo plusbinlogviz <version>
Pull requests and release builds now validate packaged artifacts, not only source-tree tests.
The maintainer-facing smoke path verifies that one built archive can:
- extract successfully
- include the binary,
testdata/minimal.binlog,testdata/sample-binlog/, andincident.yaml - run
--version - execute
analyzeon the bundled sample - save snapshots
- run
compare - run
trend - run
workflow run incident.yamlfrom the extract directory
curl -fsSLO https://raw.githubusercontent.com/Fanduzi/BinlogVisualizer/main/cmd/binlogviz/testdata/minimal.binlog
binlogviz analyze minimal.binlogUse this when you want the fastest check that:
- the file is readable
- the file parses successfully
- the default text report is already enough for a first look
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin.Discovery mode is usually the safest operator path when files live in one directory and follow a numeric suffix pattern. BinlogViz will:
- scan the immediate directory entries
- keep only files whose suffix after the prefix is numeric
- sort them by numeric suffix
- print the resolved ordered list to
stderr - analyze that ordered set
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--start "2026-03-15T10:00:00Z" \
--end "2026-03-15T10:30:00Z" \
--exclude-schema mysql,sys,information_schema,performance_schemabinlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--include-schema orders \
--include-table payments,refundsUse this when you are working a known incident window, a specific service schema, or a short list of hot tables.
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. --format json > analyze.jsonThis keeps the machine-readable report on stdout while leaving progress and runtime information on stderr.
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--top-tables 20 \
--top-transactions 20 \
--top-minutes 30binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--detect-spikes \
--large-trx-rows 5000 \
--large-trx-duration 60sbinlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--start "2026-03-15T10:00:00Z" \
--end "2026-03-15T10:30:00Z" \
--format json \
--snapshot-name incident_current > /tmp/incident_current.json
binlogviz analyze --from-dir /var/lib/mysql --prefix mysql-bin. \
--start "2026-03-08T10:00:00Z" \
--end "2026-03-08T10:30:00Z" \
--format json \
--snapshot-name incident_baseline > /tmp/incident_baseline.json
binlogviz snapshot list
binlogviz snapshot list --format json
binlogviz snapshot show incident_current
binlogviz snapshot show incident_current --format json
binlogviz snapshot rename incident_current incident_current_renamed
binlogviz snapshot delete incident_current_renamed
binlogviz compare --current-snapshot incident_current --baseline-snapshot incident_baseline
binlogviz compare --current-snapshot incident_current --baseline-snapshot incident_baseline --format json > compare.json
binlogviz compare --current-snapshot incident_current --baseline-snapshot incident_baseline --format html > compare.htmlThe default snapshot store is ~/.binlogviz/snapshots. Use binlogviz snapshot save <report.json> --name <name> when you already have an exported analyze JSON file and want to add it to that store later. snapshot list is the quickest human audit view for the store, while snapshot rename and snapshot delete let you manage long-lived snapshot history without manual file operations.
If you already manage exported JSON files yourself, the legacy file mode remains supported:
binlogviz compare /tmp/incident_current.json /tmp/incident_baseline.jsonThe compare report highlights workload deltas, top table shifts, operation mix changes, and alert additions/removals so DBAs can see whether a window is heavier, broader, or riskier than the baseline.
BinlogViz supports multiple languages for runtime output such as errors, reports, and progress messages.
binlogviz --lang zh-CN analyze mysql-bin.000123
LANG=zh_CN.UTF-8 binlogviz analyze mysql-bin.000123Supported languages:
en- English (default)zh-CN- Simplified Chinese
--help output currently remains in English because help text is generated before language initialization. Runtime output is localized.
The Cobra command layer streams parser output through normalization and transaction-aware analysis, then hands the shared result model to report, snapshot, compare, trend, or workflow consumers.
| Module | Responsibility | Doc |
|---|---|---|
cmd/binlogviz |
CLI commands and analyze orchestration | README |
internal/binlog |
Binlog parsing, probing, and normalization | README |
internal/analyzer |
Transaction reconstruction and workload aggregation | README |
internal/model |
Shared event, transaction, and report contracts | README |
internal/report |
Text, JSON, Markdown, and HTML renderers | README |
internal/compare |
Analyze-report loading and comparison | README |
internal/snapshot |
Named report persistence | README |
internal/trend |
Ordered multi-snapshot analysis | README |
internal/workflow |
Repeatable investigation plans | README |
- local MySQL
ROWbinlog files - Go 1.26.1+ if building from source
Apache 2.0

