Group stack traces from a log by fingerprint

Paste a log or many error reports. Get distinct errors with counts, first and last seen, a sample trace, and Markdown or JSON for an issue or an LLM.

How it works

  1. Paste a log or a pile of error reports
  2. Set how many top frames make the fingerprint
  3. Copy the Markdown or JSON groups into an issue or an LLM prompt

How traces are grouped

To group stack traces, build a fingerprint from the exception type and the first few frames, then put traces with the same fingerprint together, which is what this page does with up to 20,000 traces in a pasted log. Frame positions are written without the machine's folder, so /srv/app/src/orders.js and /home/ci/build/src/orders.js match, and line and column numbers are ignored by default, so a deploy that moves a line does not split a group. Worked example with the sample that opens on the page: two TypeError traces whose top frame moved from orders.js:88 to orders.js:91 are one group of 2, and Error: Order 2291 not found with Error: Order 3310 not found are another group of 2, because numbers in the message become a placeholder before comparing. Switch on Count line and column numbers and the TypeErrors split into 2 groups. The default of 3 top frames can be set from 1 to 10.

Languages and formats it reads

The page finds JavaScript and Node traces (at fn (file:line:col), also the fn@file:line:col form of Firefox and Safari), Python tracebacks including chained exceptions, Java and Kotlin traces with Caused by, .NET traces with the file and line when present, Go panics and fatal errors with their goroutine frames, Ruby backtraces, PHP traces with numbered frames, and Rust panics with or without a backtrace. A trace is found even when a log shipper puts its own timestamp before every line. The exception line before the frames gives the type and message; for Java, Python chains and .NET inner exceptions the root cause is added to the fingerprint, so a wrapper that hides two different failures does not merge them. A trace with no header line still counts, and its group is called no exception name.

Normalising and the options

Messages are normalised before comparing: UUIDs, timestamps, e-mail addresses, IPv4 addresses, hex values such as 0xdeadbeef, absolute paths and numbers become fixed placeholders, so two messages that differ only in such a value match. Words with a digit inside, such as utf8, are kept. File paths can be trimmed to the part from src, lib, node_modules or similar, reduced to the file name, or kept in full. Ignore library and runtime frames skips node_modules, site-packages, java.*, System.* and the Go and Rust runtime when choosing the top frames, and falls back to all frames when a trace has nothing else. The first and last seen times come from the log line that holds the exception, in ISO 8601, nginx or Apache, or epoch form, read as UTC when there is no zone. An AI agent can open this page with #input= followed by URL-encoded log text to have the groups ready.

What it does not do

Grouping is by text, not by meaning: the same bug thrown through two different call paths makes two groups, and a changed function name makes a new group. Minified code groups by its minified names. Frames from different languages in one trace, such as a Java call into native code, are read as the language of the first frame. Timestamps in syslog form carry no year and are not read, so those groups show no first or last seen. The page reads up to 2,000,000 characters and 20,000 traces, cuts each line to 2,000 characters for matching and each representative trace to 300 lines, and lists up to 500 groups. Counts always cover every trace found.

Frequently asked questions

How do I group stack traces from a log file?

Paste the log and read the groups table: each row is one fingerprint of exception type plus the top 3 frames, with its count and the first and last time seen. The sample of 7 traces collapses into 5 groups, the largest with 2 occurrences.

What is a stack trace fingerprint?

It is a short id made from the language, the exception type, the root cause type, the top frames and the message, with paths trimmed and numbers in the message replaced. The page shows it as 8 hex characters, such as d02bcf1a, and traces with the same fingerprint are counted as one error; if two different fingerprints ever share the same 8 characters they stay separate and the second id gets a -2 suffix.

Why did two traces of the same error end up in different groups?

Usually one of three things differs: a line number while Count line and column numbers is on, a full path while File paths is set to Full path, or a frame within the top N. Lower the Top frames setting from 3 to 2, or trim paths, and check again.

How do I send the groups to ChatGPT or Claude?

Copy the Markdown output. It lists each group with its count, fingerprint, top frames, first and last seen and one representative trace, so 200 repeated traces become a few kilobytes. The JSON output has the same fields for a script.

Does it handle stack traces with Caused by or chained exceptions?

Yes. For Java and Kotlin the last Caused by is added to the fingerprint as the root cause, for .NET the type after --->, and for Python the first exception of a During handling chain. The group shows the outer exception and lists the root cause.

Is my log uploaded or saved?

No. The text is processed in your browser and not uploaded. Only the option settings are saved on this device, never the log text.