TinyLog is a project scaffold for high-density log storage and low-memory log access.
It targets the two main pain points of traditional plaintext logging: excessive storage cost and expensive traversal of very large files.
Traditional logs are usually stored as plaintext. That creates two systemic issues:
- Storage overhead: plaintext logs contain high redundancy and grow quickly over time.
- Read amplification: once files become large, scanning, browsing, filtering, and locating entries can consume too much memory.
The project is initialized around two product surfaces:
- Java SDK for application integration, with business-facing logging APIs similar in role to
slf4j. - Rust tools for converting plaintext logs into proprietary TinyLog files and browsing them with a
vim-like workflow for searching and positioning.
| Module | Responsibility |
|---|---|
tinylog-core |
Core log domain model, codec abstractions, and reader/writer contracts |
tinylog-sdk |
Business-facing Java logging API, logger factories, direct .tog file backend, and SLF4J 2.0.17 bridge support |
tinylog-rust-common |
Shared Rust TinyLog format and protobuf support |
tinylog-converter |
Rust CLI for converting plaintext logs into .tog files |
tinylog-viewer |
Rust CLI for interactive TinyLog browsing |
Repository collaboration rules, engineering conventions, and commit conventions live in AGENTS.md.
TinyLog releases follow MAJOR.MINOR.PATCH.
- Increment
PATCHfor small optimizations and bug fixes - Increment
MINORand resetPATCHto0for backward-compatible features - Increment
MAJORand resetMINORandPATCHto0for breaking or materially incompatible upgrades
The current release target is v0.1.0.
- Java namespace:
com.huimang.tinylog - Java build: Maven multi-module project for
tinylog-coreandtinylog-sdk - Java SDK compatibility:
slf4j-api:2.0.17with verifiedslf4j-simple:2.0.17integration plus a direct.togfile logger factory - Rust workspace: split into
tinylog-rust-common,tinylog-converter, andtinylog-viewer - Shared contract: protobuf schema in
tinylog-core/src/main/proto/tinylog/prototype.proto - Java protobuf generation notes:
docs/protobuf-java-generation.md - Storage structure docs (EN):
docs/log-storage-structure.md - Storage structure docs (ZH-CN):
docs/zh-CN/log-storage-structure.md
The current prototype uses a trunk-based .tog binary layout with whole-trunk compression, lightweight indexing, and low-memory windowed reads for interactive browsing.
The full storage structure, field definitions, and design rationale live in:
- English:
docs/log-storage-structure.md - Chinese:
docs/zh-CN/log-storage-structure.md
The current prototype accepts plaintext log lines in this format:
<yyyy-MM-dd HH:mm:ss,SSS> [LEVEL] <message>
The converter interprets that timestamp text as a UTC calendar value, extracts the first [LEVEL] token into a dedicated one-byte field, removes that token from the stored message body, and the viewer reconstructs the line using the persisted level plus the UTC timestamp offset. Inputs up to 100 MiB use serial conversion to avoid scheduling overhead; larger inputs switch to a master/worker pipeline where the master plans trunk boundaries, workers compress contiguous trunk batches in parallel, and the master merges the worker outputs in order while reporting per-worker progress.
cat > normal.log <<'EOF'
2026-05-01 22:01:00,253 [INFO] service started
2026-05-01 22:01:00,278 [WARN] user signed in
2026-05-01 22:01:00,353 [ERROR] order created
EOFcargo run --quiet --manifest-path tinylog-converter/Cargo.toml -- normal.log normal.togHelper script:
scripts/tinylog-convert.sh normal.logReverse conversion is also available:
scripts/tinylog-convert.sh --reverse normal.togExpected output:
using serial conversion mode for inputs up to 100.00 MiB
progress: 0/120 (0.00%)
progress: 120/120 (100.00%)
converted normal.log to normal.tog using gzip
source size: 120 (120 B)
output size: 111 (111 B)
compression ratio: 92.50%
elapsed: 4ms
For large inputs above 100 MiB, the converter starts indexing immediately by byte range and prints one live horizontal worker line based on completed trunks / assigned trunks, for example:
building trunk index and preparing worker assignments for huge.log
indexing: 0/10737418317 (0.00%)
indexing: 10737418317/10737418317 (100.00%)
compressing 157 trunks with 16 workers
writing: 1: 0% 2: 0% 3: 0% 4: 0%
writing: 1: 10% 2: 20% 3: 24% 4: 10%
cargo run --quiet --manifest-path tinylog-viewer/Cargo.toml -- normal.togHelper scripts:
scripts/tinylog-view.sh normal.tog
scripts/tinylog-open.sh normal.logtinylog-example now includes:
TinylogSdkYamlExample: console +.togoutput demoTinylogLargeTogExample: generates a large.togfixture, defaulting to roughly120 MiB
Example command:
java -cp "tinylog-example/target/classes:tinylog-sdk/target/classes:tinylog-core/target/classes:$HOME/.m2/repository/org/yaml/snakeyaml/2.2/snakeyaml-2.2.jar" \
com.huimang.tinylog.example.TinylogLargeTogExampleKey bindings:
j / DownArrow move down
k / UpArrow move up
Enter move down by 1/4 page
d / PageDown page down
u / PageUp page up
g jump to top
G jump to bottom
:N jump to line N
/keyword search keyword by trunk and jump to the nearest result
:debug filter one level (also :trace/:info/:warn/:error)
:help open the help popup
n move to next cached search result / continue trunk scan
p move to previous cached search result / continue trunk scan
Esc clear filter/search or close help
q quit
Expected screen content:
TinyLog viewer | file=normal.tog | records=3 | line=1 | j/k move enter +1/4 d/u page g/G ends q quit
1 ▪2026-05-01 22:01:00,253 [INFO] service started
2 2026-05-01 22:01:00,278 [WARN] user signed in
3 2026-05-01 22:01:00,353 [ERROR] order created
The viewer stays open like a lightweight vim-style browser. The display area is rendered as two independent panes: a blue left logical line-number pane and a right content pane, with a pale-orange rectangular marker offset slightly to the right of the line numbers for the focused row. The marker is shown only on the first physical row of the focused logical log entry. One logical log line can span multiple rendered rows because of width limits or embedded newlines, but it still keeps a single sequence number in the left pane. The focused line moves freely inside the viewport and the screen scrolls only when another move would push that focused row past the top or bottom edge.
cargo test -p tinylog-converter convert_plaintext_log_writes_parseable_togBuild the current release binaries and pack them into a versioned archive with:
scripts/package-release.shFor v0.1.0 on Darwin arm64, the generated archive is:
dist/v0.1.0/tinylog-v0.1.0-darwin-arm64.tar.gz
- Define the TinyLog file header, block layout, and index structure
- Implement streaming writer/reader paths and compression codecs
- Add a default Java SDK implementation behind the abstract logging API
- Add paging, search, and jump workflows to the Rust viewer
This project is licensed under the MIT License.
