This release marks almost four years since the first version of tailspin. Since then, there have been many changes and
many refinements´, so for 7.0.0, thought it would be a good time to reflect a bit on the journey.
Starting out, I read lots of colorless logs in the terminal in very different formats. After a while, I got a very
simple idea: I know what a timestamp / IP address / UUID etc. looks like. I recognize this and this part of the log line
as distinct things, and if I can distinguish these different elements from each other, then surely a cli should be able
to as well.
The first version of tailspin (1.0) was written in Go and focused on highlighting the correct elements without
producing false positives. This version was unnecessarily inefficient because the regexes were re-compiled each line
and the engine was single threaded. However, the cli did the job for me, logs were easier to read and I didn't have to
think about what schema or format the log was in.
Since then, the cli has been re-written in Rust and become a lot faster, but the core is still the same:
"I know what a timestamp looks like--color it".
Below is a benchmark test ran over a 44 MB log file on the same machine.
| version | date | wall time | highlights |
|---|---|---|---|
0.1 |
sep 2023 | 74.90 s |
original Go version; single-threaded, regexes recompiled per line |
1.6.1 |
nov 2023 | 08.80 s |
rust rewrite; compile regexes once |
2.3.0 |
jan 2024 | 01.40 s |
parallel highlighting with rayon |
2.4.0 |
jan 2024 | 01.70 s |
added more highlighters |
3.0.2 |
aug 2024 | 02.20 s |
added more highlighters |
4.0.0 |
oct 2024 | 01.40 s |
highlighting moved to inlet_manifold |
5.5.0 |
aug 2025 | 00.90 s |
use aho-corasick for keyword highlighting |
6.0.0 |
apr 2026 | 00.40 s |
span pipeline: match once, merge, render |
6.1.0 |
may 2026 | 00.38 s |
cached style prefixes, pooled scratch buffers |
7.0.0 |
jul 2026 | 00.15 s |
single keyword automaton, batched reads, per-thread highlighters |
Breaking Changes
- Builtin keywords (log severities, booleans, nulls and common rest verbs) are now a regular
highlight group namedkeywords: use--disable keywordsinstead of the removed
--disable-builtin-keywords --config-pathhas been renamed to--theme- the hidden
--generate-bash-completions,--generate-fish-completionsand
--generate-zsh-completionsflags have been replaced by--completions <shell> - the
[ip_addresses]theme table has been split into[ipv4]and[ipv6], matching the
highlight group names; each table now styles only its own highlighter - the
numberkey in the[numbers]theme table has been renamed tostyle - Windows: the theme now resolves to
%appdata%\tailspin\theme.tomlinstead of
%userprofile%\tailspin\theme.toml, following the platform convention
New Features
tailspin_themeenvironment variable to set the theme path without the--themeflag--completions <shell>prints shell completions to stdout, now also forelvishandpowershell--highlightaccepts the full 16-color palette (e.g.bright_red), using the same color names
astheme.toml--generate-default-themeis no longer hidden and is documented in the man pagehighlighterimplementsclone- Added
durationhighlighter - Generate
default-theme.tomlwith the default style of every highlight group
Crate
- theme config struct now derives
serializeanddeserialize, sotheme.tomltables
deserialize directly into the config structs highlighterbuilder::with_date_time_highlightersrenamed towith_date_time_highlighterhighlighterbuilder::with_keyword_highlighterrenamed towith_keyword_highlighters, matching
itsvec<keywordconfig>parameter
Changed
--execnow takes precedence over pipedstdinwhen both are present--execnow exits with an error when the spawned command exits non-zero--pagernow rejects commands missing the[FILE]placeholder- Theme style tables now reject unknown keys
- The missing-filename message now prints to stderr
Performance
- Match all keyword groups with a single automaton instead of one per style
- Batch lines in a shared buffer instead of allocating one string per line
- Skip the JVM exception header scan on lines without
ExceptionorError - Highlight batches through per-thread highlighter clones to avoid regex cache contention
- Intern styles into a build-time palette so render resolves ANSI prefixes by index
Fixed
Highlighter::default()now applies groups in the same precedence order as the CLI- Dates embedded in longer digit runs (e.g.
12022-09-09) no longer highlight as dates - Ctrl+C while the pager is open exits cleanly instead of printing an error
- Keywords sharing a prefix with a shorter keyword (e.g.
WARNINGvs.WARN) are now highlighted - Overlapping background-styled keywords no longer lose their badge padding
- IPv6 addresses with a netmask over 128 no longer highlight
Build
- Replace the
tokioruntime with plain threads and blocking IO