~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

Reading the logs by message walks that message's index

Merged
Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:serve/logs-by-message

What changes

Logs::read now uses a separate statement for each way of asking. A read by trace is unchanged. A read by message walks line_message (message, id) newest first, its level and duration filters checked on the way. A read by level or duration alone walks the table newest first, as before.

Why

There used to be one statement for every filter, with the message test written (?2 IS NULL OR message = ?2), and no index can answer that. A read by message walked every line kept, up to 30 days of them, newest first, until it had enough. A common message such as request stops early, but a rare one reads nearly the whole table. On prod, the first read of the newly logged mcp tool lines took 9.0s in getLogs, while the store held one such line.

How it was checked

keeps_reads_and_lets_go already reads by trace, message, level and duration, so it covers each statement. The rest is left to CI. Once this is deployed, I'll time a getLogs read of message=mcp tool again on prod: it was 9.0s before.

Shortcomings

A read by a rare level or a long minMs alone still walks lines newest first until it has enough. An index on ms would only help if reads used it in place of the newest-first order, and slow lines are common enough that the walk ends soon.

🤖 Generated with Claude Code

Approved

This splits Logs::read into three statements: by trace, by message, and by level or duration alone. The message statement uses INDEXED BY line_message, and that index is created in the schema at logs.rs:68 on (message, id). So message = ?2 ... ORDER BY id DESC should walk the index newest first and stop at the limit. I found no bugs.

  • Parameters: the shared params! list still binds all five values, as the old trace statement already did with its unused ones. This is fine.
  • Trace reads: a trace read still ignores message, as it did before.
  • INDEXED BY: it errors if the index is missing. Here the index is created with IF NOT EXISTS, so that shouldn't happen.
  • Tests: I didn't confirm that keeps_reads_and_lets_go covers the by-message path, and I didn't check CI. Your plan to time the prod read after deploy is a good check.
Merged as cf8fb93