TNT/docs/MESSAGE_LOG.md

3.1 KiB

Message Log

This document defines the persisted chat-history format used by TNT 1.x.

Format: messages.log v1

Each record is one UTF-8 line:

RFC3339_UTC|username|content\n

Example:

2026-05-27T12:34:56Z|alice|hello

Rules:

  • Timestamp is strict UTC RFC3339: YYYY-MM-DDTHH:MM:SSZ.
  • The separator is literal |.
  • A valid record has exactly three fields and exactly two separators.
  • username and content must be non-empty valid UTF-8.
  • username must fit MAX_USERNAME_LEN; content must fit MAX_MESSAGE_LEN.
  • Every complete record ends with \n.

The file has no header. The version is defined by this record contract so existing append-only logs remain readable.

Write Behavior

message_save() sanitizes fields before appending:

  • |, \n, and \r in usernames become _.
  • |, \n, and \r in content become spaces.
  • Timestamps are written in UTC.

Private messages are not written to messages.log. :inbox stores incoming and sent private-message copies only in each participant's live session memory, so inbox state is lost on disconnect and never appears in tail, dump, :last, or :search.

Replay and search use the same strict parser. TNT skips records that are:

  • malformed or missing fields
  • invalid UTF-8
  • too long
  • outside the accepted timestamp window
  • terminated without a trailing newline
  • written with extra separators

Skipping a bad record is intentional recovery behavior. A truncated final line is treated as a partial append and ignored rather than replayed.

Export

dump [N] and dump -n N export valid persisted records through the SSH exec interface and tntctl. The output format is exactly the v1 record format above. Without N, dump exports all valid records; with N, it exports the last N valid records.

Maintenance

scripts/logrotate.sh is the manual archive and compaction tool for messages.log:

scripts/logrotate.sh [--dry-run] [--keep-archives N] LOG_FILE MAX_SIZE_MB KEEP_LINES

When the log exceeds MAX_SIZE_MB, the script archives the full file, compacts the active file to the last KEEP_LINES records, compresses the archive when gzip is available, and removes older archives beyond the retention limit. Run it while TNT is stopped or during a quiet maintenance window if strict log consistency matters.

Recovery

Installed tnt binaries provide offline log checking and recovery:

tnt --log-check LOG_FILE
tnt --log-recover LOG_FILE > recovered.messages.log

--log-check prints a summary:

path /var/lib/tnt/messages.log
records_seen 120
valid_records 119
invalid_records 1
first_invalid_line 120

It exits 0 when every record is valid and 1 when invalid records are found or the log cannot be read. --log-recover writes only valid v1 records to stdout, prints the same summary to stderr, and also exits 1 if records were skipped. It never modifies the source log.

Compatibility

The v1 record format is stable for TNT 1.x. Future incompatible storage changes must document downgrade behavior in release notes and provide an operator-visible migration or export path.