English · Русский
A library and command-line tool for large logs: folds lines into templates and compares two runs.
logfold reads a log and replaces the variable parts of messages (numbers, IP addresses, UUIDs, paths) with masks. Lines
with the same text are then grouped into templates. For every template it counts the records, the first and last time it
appeared, the highest severity level and an example line. The diff command compares two runs, for example before and
after a deploy, and shows the templates that are new, gone or noticeably changed in share.
The core is written in Rust; you can use it from Python or from the command line. Everything runs locally and no data is sent anywhere.
$ logfold diff before.log after.log --out diff.html --fail-on-new
before.log -> after.log: 1,265,631 -> 1,246,573 records, 2 new (2 WARN+), 1 disappeared, 3 changed, 9 unchanged, native engine, 3.41s
New templates (2)
before after change level template
0 44,102 new ERROR circuit breaker opened for upstream <IP>
0 44,310 new WARN queue depth <NUM> exceeds limit on worker-<NUM>
What it does
- Templates.
user alice failed login from 10.0.0.7and the other lines like it are reduced to one entry,user <*> failed login from <IP>. The algorithm is compatible with Drain3. Average grouping accuracy on the 16 Loghub-2k datasets: Drain3 0.7658, logfold in sequential mode 0.7658, in parallel mode 0.7643. - Comparing two runs. Shares of templates are computed from the number of records in each run, so different log
sizes do not matter. A template counts as changed when its share grew or fell by at least a factor of 2, it has at
least 10 records in either run (both thresholds are configurable) and a G-test finds the change unlikely to be noise
(
--significance, default 0.01); the most significant changes come first. Identical inputs give an empty result. - One log, several baselines.
diff app.log --split-at TIMEcompares the part of one log before a time with the part after it (--sinceand--untilbound any command to a time range).--baseline(repeatable) pools several good runs so that a template counts as new only if none of them has it, which removes the noise of rare messages. - Exit code for CI.
--fail-on-newexits with code 2 when there are new templates,--fail-on-new-alertswhen any of them is WARN, ERROR or FATAL. A reworded message that the default matcher pairs with an old one counts as changed, not new;--matcher exactmakes the gate strict.--out FILE --appendadds a text or Markdown report to the end of a file instead of replacing it, so several steps of a job can write one job summary ($GITHUB_STEP_SUMMARY); see logfold in CI. - Memory. The file is read as a stream, and memory use does not depend on its size. Inputs: files, gzip, standard input, several files as one run.
- Parallelism. A large file is cut into chunks (64 MiB by default) and the chunk trees are merged in order. For a
fixed chunk size the result does not depend on the number of threads. The strategy is chosen automatically: a large file
is mined in parallel, and sequentially when the first chunk shows that almost every line is a new message (
--strategy auto, the default).--warm-startstarts every chunk from the tree of the first one: far fewer stray templates, at the price of mining the first chunk alone. - Value masks. By default UUIDs, timestamps, IPs, hex values, paths and numbers are replaced; the rules can be changed.
- Reports. HTML (one file, no network requests, strict CSP), JSON with a versioned schema, text, Markdown, CSV. A
report includes raw example lines by default;
--examples maskedornoneremoves them. - Extensions. Log formats, reports and template matchers for
diffare plugins, loaded through entry points or from a folder of.pyfiles.
Install
pip install "logfold[cli]"
Python 3.10 or newer. PyPI has prebuilt packages for Linux (x86_64, aarch64, musl), macOS (x86_64, arm64) and Windows
(x86_64), so pip installs without compiling and you do not need Rust. On any other platform pip builds the package from
source, which needs a Rust compiler. Without [cli] you get the library only.
Quick start
Analyze a log:
logfold analyze app.log --top 30 --out report.html
logfold analyze app.log --only-alerts # only WARN, ERROR and FATAL templates
logfold inspect app.log # how the file is read: format, first records, levels
The format is detected from a sample of the file (nginx, apache, syslog, journald, Kubernetes, JSON lines, logfmt and
others). If it is not sure, the command lists the candidates and asks you to pass --format. Indented stack-trace lines
are joined to the record that started them.
Compare two runs:
logfold diff before.log after.log --out diff.html --fail-on-new-alerts
logfold diff app.log --split-at 2026-10-06T12:00 # the part of one log before a time against the part after it
logfold diff good1.log after.log --baseline good2.log --baseline good3.log # new = in none of the good runs
logfold diff before.log after.log --report github-summary --out "$GITHUB_STEP_SUMMARY" --append # in CI: add to the job summary
Exit codes: 0 success, 1 error, 2 something requested by a --fail-on-* flag was found.
Compare saved results without reading the logs again:
logfold analyze before.log --out before.json
logfold analyze after.log --out after.json
logfold diff before.json after.json
A JSON file written with --out holds every template, so it is suitable for this kind of comparison.
See which formats, reports and matchers you have, and which plugins you can still install:
logfold plugins list # built-in, installed and available from the catalog
logfold plugins info NAME # what a plugin does and how to install or use it
From Python
from logfold import analyze, diff, load_analysis
result = analyze("app.log") # the format is detected
for template in result.top(10):
print(template.count, template.level, template.text)
result.to_html("report.html")
result.filter(min_level="WARN").save("alerts.md") # the reporter comes from the suffix
comparison = diff("before.log", "after.log")
comparison.new_templates
comparison.new_alerts # new WARN/ERROR/FATAL templates
comparison.to_html("diff.html")
# compare saved results
diff(load_analysis("before.json"), load_analysis("after.json"))
analyze() and diff() return immutable dataclass objects.
Formats and parameters
| Formats | nginx, apache, nginx-error, syslog, journald, k8s (CRI/containerd), jsonl, app (<time> LEVEL message), logfmt, serilog-clef, haproxy, postgresql, postgresql-csv, docker-json, github-actions, log4j (or your own log4j:<pattern>), plain, your own regex:<pattern>. List: logfold formats. |
| Multi-line records | --multiline; with --format auto it turns on by itself when indented lines are found. |
| Folding | --depth (4), --sim-th (0.4), --max-children (100), --max-templates (100000). The defaults are the same as in Drain3. |
| Execution | --strategy auto (default; parallel chunks, sequential for logs of unique messages), sequential, chunked; --threads, --chunk-mb; --warm-start (opt-in, chunked only). |
| Logs with almost unique lines | --high-cardinality: at most 5000 templates, the rest go into catch-all templates, runs sequentially. On a 10 MB file with 84 thousand distinct lines 2.0 s becomes 0.14 s. |
| Reports | HTML, JSON, text, Markdown, CSV; for pipelines github-summary, junit (.xml), chat-message and prometheus (.prom); the --out suffix picks the format, --report NAME picks the report explicitly, including one from a plugin. |
Matchers for diff |
jaccard (default), jaccard-idf, overlap, rules:FILE (your own pairs), token_subset, exact: they link a reworded message to its earlier version so it is not counted as both new and gone. |
| Plugins | logfold plugins list (built-in, installed, available), info NAME, check, install NAME, new; an unknown format, report or matcher name gets a hint with the closest name or the install command. In Python: logfold.plugins.list_plugins(). |
| Scripting | --json prints JSON to stdout, exit codes are stable, the JSON format is described by a schema in docs/schema. |
Speed
Measured on one machine (8 cores, Windows 11); the protocol was fixed before the runs, details and data are in
bench/RESULTS.md.
| logfold, 16 threads | Drain3 (Python) | |
|---|---|---|
| nginx access log, 100 MB | 0.38 s | 5.26 s |
| application log, 100 MB | 0.41 s | 9.03 s |
| nginx access log with value masking | 0.45 s | 26.82 s |
| HDFS, 1.57 GB, a real log | 0.94 s | not measured |
diff of two 100 MB logs |
0.7 s | no diff |
On the real logs of 0.7 to 1.6 GB peak memory is 42 to 51 MB with one thread and 107 to 129 MB with 16 threads.
Limitations
Warning. Keep these in mind before running logfold on large logs and comparing results.
- Speed was measured on Windows 11 only; on Linux and macOS correctness is tested, but speed is not.
- The parallel mode builds a tree per chunk and merges them, so on logs without masks it can return more templates than the sequential mode (HDFS without masks: 341 against 43;
--warm-startbrings it to 45 at the cost of a serial first chunk). On logs with a very large number of distinct messages the defaultautostrategy notices that after the first chunk and mines sequentially;--high-cardinalitymakes it faster still.- Saved results are compared without a recount against a shared template tree, so the same event can end up both in new and in gone; the matcher (
jaccardby default) exists for this.
Measurements and bug reports
logfold was measured on one machine (Windows 11, 8 cores). If you can run it on other hardware (Linux, macOS, ARM, a slower disk, more cores) or on your own logs, we would be glad to get the numbers. We also want to hear about wrong results, crashes, templates that are grouped badly, and runs that are slow or use too much memory.
- Measurements. Run the benchmark as described in
bench/README.md(the protocol is inbench/PROTOCOL.md) or time your own command, and open a performance issue. Include the wall time, throughput and peak memory, the command, the size and format of the input, the CPU and number of cores, RAM, disk type, OS, the logfold version and the number of threads. - Bugs. Open a bug report with what you expected and what happened, a
command or Python snippet that reproduces it, the output of
logfold --versionandlogfold info, and a few lines of the input with secrets removed.
All issue forms are listed on the new issue page; how issues are written is described in CONTRIBUTING.md.
How it compares to other tools
| logfold | Drain3 | logdrain | logdelta | |
|---|---|---|---|---|
| Language | Rust core, Python API and CLI | Python | Rust | Rust |
| Template quality | same as Drain3 on Loghub-2k | reference | Drain | Drain-based |
| Comparing two runs | yes (diff, shares normalized, recount) |
no | no (online "template created" signal) | yes (diff, several baselines, blocks) |
| Python API | yes | yes | no | no |
| Multi-threaded mining of one big file | yes, deterministic | no | not documented for the CLI | not documented |
| Reports | JSON, HTML, text, Markdown, CSV | - | text, JSON, CSV | terminal, JSON, Markdown |
Template quality: python eval/quality.py (grouping accuracy on the 16 Loghub-2k datasets).
Documentation
- Guide: formats, parameters, plugins, engines.
- Using logfold in CI: GitHub Actions and GitLab CI, job summary, gates, where the baseline comes from.
- Command-line reference: commands, options, exit codes.
- Plugins: using and writing formats, reports and
matchers; an example package is in
examples/logfold-example-plugin. - Python API reference.
- Algorithm, JSON schemas and the changelog.
Design
A pure core (masking, tokenizer, Drain-compatible tree, merge) with no I/O, adapters for files and formats, an
execution layer, a thin PyO3 shim, and a Python package on top. The algorithm is described in
docs/ALGORITHM.md. A pure-Python reference
engine implements the same specification, and the Rust engine is tested against it for exactly equal results.
Development
Rules for branches, commits and the definition of done are in CONTRIBUTING.md. Report vulnerabilities privately, see SECURITY.md.
License
MIT, see LICENSE. Copyright (c) 2026 Andrey Kilanov.
Metadata
Release files for logfold 0.4.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 | |
|---|---|---|---|
| logfold-0.4.0.tar.gz | 193.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| logfold-0.4.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| logfold-0.4.0-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| logfold-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| logfold-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| logfold-0.4.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| logfold-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 9.2 MB
Release files / logfold-0.4.0.tar.gz
| Download URL | logfold-0.4.0.tar.gz |
|---|---|
| Size | 193.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
65a5ad9f350da2ebd1bb7182356c072962e87d59740e3c09356afa62cdeac4fd
|
|
BLAKE2b-256 checksum How to use checksums |
72f6631989fb4b5cb14937e6de2abf8b891c551690cc6422f7cb9368d4973206
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / logfold-0.4.0-cp310-abi3-win_amd64.whl
| Download URL | logfold-0.4.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 1.4 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
ae7a6fab9e6e4f8a8c7a26959c6042404444a8b256f729ecd2213c9b6b962cee
|
|
BLAKE2b-256 checksum How to use checksums |
726ccfcf1a05b4b0bf59cd4ac25a4fe3382d3f8f166d01348162614666c563e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / logfold-0.4.0-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | logfold-0.4.0-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
90098b439735ea110d0e58a336da4e8d7dfbc6e4f1225a43ecee7f354c868118
|
|
BLAKE2b-256 checksum How to use checksums |
b5d1a646a6d7ba5f4896cb654ab9195231b0836f973983f6938c41d9d8ec7c1a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / logfold-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | logfold-0.4.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
ec0ec314df763145015d776a6d6b4b6c98c9fa3ab4cb3cee6ad2e40a2d3494c0
|
|
BLAKE2b-256 checksum How to use checksums |
8891554fe72fef3ccf432c8f34c616b3e83255fcca12c34a0713f7e090261a55
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / logfold-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | logfold-0.4.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.4 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
c23a5d984006c9796ed9d7fb060683ba0283570fc89647a44a71d75c45735c75
|
|
BLAKE2b-256 checksum How to use checksums |
27b8697f365481b6cbccf54c3ce171ebd717c1c2463302b314f80542ecd2ec06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / logfold-0.4.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | logfold-0.4.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.4 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
c7cceb8f2118fdfd7eafd378bfdabe064d2be488453e218bdc879f576bbd27ae
|
|
BLAKE2b-256 checksum How to use checksums |
0166bf7879088d9f31e7e66ababa47fb3b3e9ddeac5b79502b976a6605ba5820
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / logfold-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | logfold-0.4.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
b1707188056964cdd6e18aa17c36aa3e4c84e3ee429b718607beb5e3d4538ed1
|
|
BLAKE2b-256 checksum How to use checksums |
419bdbc46af3359386ec4a3f64c66bbf2c99b788d04673a7f9c6b584dbe6d948
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log