Skip to main content

English · Русский

logfold

A library and command-line tool for large logs: folds lines into templates and compares two runs.

CI PyPI Python versions License: MIT Rust core


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 --fail-on-new-alerts
before.log -> after.log: 364 -> 600 records, 1 new (1 WARN+), 0 disappeared, 1 changed, 2 unchanged, native engine, 0.01s

New templates (1)
    before       after    change  level  template
         0         180       new  ERROR  db connection timeout after <*> <*>

Changed templates (1)
    before       after    change       p  level  template
         4          60     x9.10  <0.001  WARN   retry <NUM> for order <NUM>
$ echo $?
2

Try it in a minute

pip install "logfold[cli]"
logfold analyze app.log --out report.html                 # the templates of one log, with counts and examples
logfold diff before.log after.log --out diff.html         # what is new, gone or changed between two runs

The reports are one HTML file each: no network requests, a strict content security policy, and every value that comes from a log is escaped.

The HTML report of logfold diff: new, changed and disappeared templates, and the values that differ

What do you want to do?

Stop a job on a new error in CI

      - uses: AndreyKilanov/logfold@v0.5.0
        with:
          log: current.log

The action compares the log of the run with the last good one, writes the summary of the job and fails it when a new WARN, ERROR or FATAL template appears. Without GitHub: logfold diff good.log current.log --fail-on-new-alerts (exit code 2), or a saved model, logfold learn good.log --state model.json and logfold check current.log --state model.json. Recipes for GitHub Actions and GitLab CI: logfold in CI.

Find what changed in an incident

logfold diff app.log --split-at 2026-10-06T12:00           # the log before a time against the log after it
logfold diff before.log after.log --new-values             # the values that only one run has
logfold diff docker:web-old docker:web-new                 # read straight from docker, kubectl or journalctl

Finding what changed in an incident goes step by step and says how to read the result.

Share a log or a report safely

logfold analyze app.log --masks all --examples none --out report.html

The mask sets hide keys, tokens, passwords, e-mail addresses, phone numbers, card numbers and IBANs before the log is mined, and --examples none leaves the example lines out. They lower the risk and do not remove it; names and the words of the messages stay. Sharing a log or a report safely says what each option hides and how to check a file before it is sent.

Use it from Python

from logfold import analyze, check, diff

result = analyze("app.log")  # the format is detected
for template in result.top(10):
    print(template.count, template.level, template.text)

comparison = diff("before.log", "after.log")
comparison.new_alerts  # new WARN, ERROR and FATAL templates
comparison.to_html("diff.html")

analyze("good.log", save_state="model.json")  # a model: templates and counts, never an example line
check("model.json", "today.log").passed

The results are immutable dataclasses. logfold in a Python program says which call does what and links to the reference.

Keep a model, check a log, watch a stream

logfold learn good.log --state model.json                  # save what a good run looks like
logfold check today.log --state model.json                 # exit code 2 when the log holds anything the model does not know
logfold match model.json today.log                         # how many records fit no template
tail -F app.log | logfold stream -f app                    # print each new template when it first appears

In Python the same is logfold.Miner, which takes records in batches and tells which template a record fits.

Coming from Drain3

The calls and the settings that correspond, and what differs, are in Migrating from Drain3.

What it does

  • Templates. user alice failed login from 10.0.0.7 and the other lines like it are reduced to one entry, user <*> failed login from <IP>. The algorithm is compatible with Drain3: on the 16 Loghub-2k datasets the average grouping accuracy is 0.7658 in sequential mode (the same as Drain3) and 0.7643 in parallel mode.
  • 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 TIME compares the part of one log before a time with the part after it (--since and --until bound 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.
  • Values. analyze --values counts the values at the variable positions (top values, and the percentiles of numbers); diff --new-values lists the values that only one of two runs has, for the templates that both have.
  • Exit code for CI. --fail-on-new exits with code 2 when there are new templates, --fail-on-new-alerts when 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 exact makes the gate strict. --out FILE --append adds 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).
  • Safe to share. Mask sets (secrets, pii, credentials, payment, all, your own files) hide values before they reach a template, a saved model or a report; --examples masked or none handles the example lines. HTML reports escape everything.
  • Inputs. Files, gzip, standard input, several files as one run, and docker:NAME, kubectl:NAMESPACE/POD and journalctl:UNIT read through your own tools, read-only and bounded. The file is read as a stream, and memory use does not depend on its size.
  • 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).
  • Reports. HTML, JSON with a versioned schema, text, Markdown, CSV; for pipelines github-summary, junit, chat-message and prometheus.
  • Settings and extensions. A logfold.toml keeps the options you repeat. Log formats, reports, template matchers, mask sets and sources are plugins, loaded through entry points or from a folder of .py files.

Install

pip install "logfold[cli]"

Python 3.11 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.

Formats and what each was checked on

logfold formats lists the formats. --format auto (the default) picks one from a sample of the file: nginx, apache, syslog, journald, Kubernetes, JSON lines, logfmt and others; if it is not sure it lists the candidates and asks you to pass --format. logfold inspect app.log shows how a file is read: the format, the first records, the levels. Indented stack-trace lines are joined to the record that started them.

Each format was compared with something outside this project, and the table says with what. A check does not promise that a format reads every log of that program: the settings of the program that were not tried, and the limits that were found, are listed in the table of the guide and in logfold plugins info NAME.

Checked on Formats
The real program, every record compared with what it wrote (HAProxy 2.8 to 3.2, PostgreSQL 13 to 17, log4j2, logback and log4j 1.x, Docker 28) haproxy, postgresql, postgresql-csv, log4j, docker-json
The job logs of this project's own GitHub Actions runs github-actions
Samples and logs of other projects (Filebeat, Fluent Bit, Loki, Loghub) and generated logs nginx, apache, nginx-error, syslog, k8s, jsonl, logfmt, app
Damaged logs only (fuzzing); no real program or samples yet plain, journald, serilog-clef

Your own format: --format regex:<pattern> or log4j:<pattern>. A log of another program with a time and a level in the same place is read by app (<time> LEVEL message).

Options

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), --on-full evict (at the cap drop the least recently used templates instead of pooling new ones), --delimiters (the characters that separate tokens). 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: far fewer stray templates, at the price of mining the first chunk alone).
Logs with almost unique lines --high-cardinality: at most 5000 templates, the rest go into catch-all templates, runs sequentially.
Masks the default masks replace UUIDs, timestamps, IPs, hex values, paths and numbers; --masks secrets,pii, --masks all, --masks-file FILE add sets that run first (logfold masks list).
Values analyze --values, diff --new-values (--values-templates N); logfold params TEMPLATE MESSAGE (Python: logfold.extract_parameters) gives the values of one message at the variable parts of a template.
Time range --since, --until; diff --split-at TIME.
Levels --level ERROR keeps the templates whose most severe level is at least that; --only-alerts is --level WARN.
Saved results logfold analyze before.log --out before.json, then logfold diff before.json after.json compares them without reading the logs again.
Models and streams learn, check, match, stream; --save-state and --load-state continue a run from a saved model, also in parallel.
Reports the --out suffix picks the format (.html, .json, .txt, .md, .csv, .xml for JUnit, .prom), --report NAME picks one 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.
Scripting --json prints JSON to stdout, exit codes are stable (0, 1, 2 for a --fail-on-* finding), the JSON format is described by a schema in docs/schema.

Every command and option: the command-line reference.

Speed

Measured on one machine (8 cores, Windows 11) with this version; the protocol is in bench/PROTOCOL.md, the comparison with other tools in bench/RESULTS.md.

1 thread 16 threads
analyze, nginx access log, 100 MB 0.93 s 0.45 s
analyze, application log, 100 MB 0.83 s 0.45 s
diff of two 100 MB logs 2.55 s 0.69 s

Peak memory is 46 MB with one thread and 97 to 110 MB with 16, on files of 100 MB, and does not grow with the size of the file. The mask sets add 5 to 15% (secrets and pii) or 11 to 24% (all); --values takes three to four times as long as analyze, and diff --new-values 1.5 to 3 times as long as diff.

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-start brings it to 45 at the cost of a serial first chunk). On logs with a very large number of distinct messages the default auto strategy notices that after the first chunk and mines sequentially; --high-cardinality makes 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 (jaccard by default) exists for this.
  • The mask sets lower the risk of sharing a log and do not remove it, and a format was checked on what the table above says, not on every setting of the program.

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 in bench/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 --version and logfold info, and a few lines of the input with secrets removed.
  • A log that is not read correctly. Lines lost or split wrongly, a field in the wrong place, -f auto picking the wrong format: use the log format form. Name the program and its version, the log settings you changed, the output of logfold inspect FILE, and about 20 real lines with secrets removed. The formats were checked on real programs and on logs of other projects, but not on every setting; this form is how the rest gets found.

All issue forms are listed on the new issue page; how issues are written is described in CONTRIBUTING.md.

Documentation

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. The Rust engine is the only implementation; golden results, property tests and a comparison with Drain3 on Loghub hold it to the specification.

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.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for logfold 0.5.0
File Size Uploaded
logfold-0.5.0.tar.gz 296.3 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for logfold 0.5.0
File
logfold-0.5.0-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
logfold-0.5.0-cp311-abi3-musllinux_1_2_x86_64.whl CPython 3.11 abi3 Linux musl 1.2+ x86-64 Details
logfold-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
logfold-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
logfold-0.5.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
logfold-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 11.8 MB

Release files / logfold-0.5.0.tar.gz

Download URL logfold-0.5.0.tar.gz
Size 296.3 kB
Tags Source
SHA-256 checksum
How to use checksums
49aeac1a412996fbae2d6856a74a4d73c4197212d2b5caa1a9087f4eb166a739
BLAKE2b-256 checksum
How to use checksums
f90f58f1abc0675bd40ec5a1644689d052450db7198e85a2ff87f3f5227364d6
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 15, 2026.

Transparency log

Release files / logfold-0.5.0-cp311-abi3-win_amd64.whl

Download URL logfold-0.5.0-cp311-abi3-win_amd64.whl
Size 1.8 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
bcf41f846676e5348d05814d9cd58aa1fd8d5dd61c3f187dc677b1679c5d909a
BLAKE2b-256 checksum
How to use checksums
d4dbc766a7eff02c921ccba7385a0e7838ae1e70adc826a86ef178dce70f27da
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 15, 2026.

Transparency log

Release files / logfold-0.5.0-cp311-abi3-musllinux_1_2_x86_64.whl

Download URL logfold-0.5.0-cp311-abi3-musllinux_1_2_x86_64.whl
Size 2.2 MB
Tags CPython 3.11 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
9fa53527d3fba52dc9bb67af9430c5acdec5546f3314292a040064eaf7000be6
BLAKE2b-256 checksum
How to use checksums
22850d55bf784e71f6be917b54945dc2a1c607a753d9a3b901190b272354f6c9
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 15, 2026.

Transparency log

Release files / logfold-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL logfold-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.0 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
a387315825fa3d4953e4e33b1423c7c08e268bdaf6fef1e167b9923ce7ab1de9
BLAKE2b-256 checksum
How to use checksums
1dcfb15ecd296a8d060454cc9c134002f91aa52dfab5f090cbaf93c8cea8d5d2
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 15, 2026.

Transparency log

Release files / logfold-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL logfold-0.5.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.8 MB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
405b5826b34a18429dfcd66251f579fb29591cdb6d19e6b72c4940d6a17105bd
BLAKE2b-256 checksum
How to use checksums
74f729fe4d103710e84dd7f400669c5ff70ca33dee19616e6b1e5eb1fd44d952
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 15, 2026.

Transparency log

Release files / logfold-0.5.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL logfold-0.5.0-cp311-abi3-macosx_11_0_arm64.whl
Size 1.7 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
075fb280d81d843f8f155f84afce6a64d68113b51a8e735dd04ae0bc6df11809
BLAKE2b-256 checksum
How to use checksums
f51f32129ad2f3e230524436f93d375dec9b6aa8a60597fdad2486b8dee53887
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 15, 2026.

Transparency log

Release files / logfold-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL logfold-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 1.9 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
b82088cba42042bbcf0252f27943549a26092c09027af796a355ea91650b4f5f
BLAKE2b-256 checksum
How to use checksums
9b9373654352c247f2581d69cf22e95830b8bebe2e674cc439883a2805db6d65
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 15, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

7 release files

0.4.0

7 release files

0.3.0

7 release files

0.2.1

7 release files

0.2.0

7 release files

0.1.0

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page