Repository navigation
Replies: 1 comment 2 replies
|
Thanks for this, really thorough writeup and the side-by-side made it easy to check! Most of it is in. I'll go with the first option and improve the renderer here. In as proposed
In, with changes
Not doing
Order I'd like: (1, 2, 3, 9) -> (4, 5, 6) -> 7 -> 8, one PR each. Happy to take your PR on 1, 2 and 9 - just go the local ordered map route for 1, not |
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Thanks again for the record view (#800) and
json_view(#804): we now use it as our default for all our clusters. After a few days on it, we compared it with hl on the same logs: a controller-runtime operator logging zap JSON. hl is still noticeably easier to read. Below is everything we found, ordered by how much it would help. Every item keeps one display row per source line, so follow, search, markers and the warn/error filter are unaffected.Same 20 lines, hl first, then Sofka 0.31.5 in record view:
(screenshot: hl)
(screenshot: Sofka record view)
1. Keep the fields in the order the application wrote them
Sofka sorts the fields alphabetically.
serde_jsonis built without itspreserve_orderfeature, soas_object()iterates aBTreeMap(render_record,src/app/logs.rs). The order a developer chose is usually meaningful: the most identifying field comes first.On a narrow terminal, the fields that matter (
process,version) end up cut off at the right edge. Enablingpreserve_orderwould fix it (and the pretty view would also show the keys in their original order).2. Separate the message from the fields
The message is free text with spaces, so nothing tells where it ends and the fields begin:
hl puts a dim
›between them. Any distinct separator would do.3. Show the logger name before the message
zap writes the logger name under
logger(setup,leaderelection,controller-runtime.metrics,events). hl shows it as a prefix in its own color (setup: Loaded global config). Sofka prints it as an ordinary field, among the others (logger=setup), often at the end of the line. Promoting it next to the message, like the time, level and message keys already are, makes it easy to scan which component logged a line. Candidate keys:logger(zap, logr),name(pino, bunyan),component.4. Style each part of the row instead of coloring the whole row
render_recordreturns a plainString, and the row gets one color from its severity. hl styles each part:=,›) dimmed.This needs
render_recordto return styled spans instead of aString, so it is the largest change here. It is also the one that makes the biggest difference.5. Color the level, not the whole row
A DEBUG row is entirely dimmed gray (the
became leaderline in the screenshot), which makes its content the hardest to read on screen. hl colors only the level badge ([DBG],[INF],[WRN],[ERR]) and leaves the message readable. Coloring the level token, plus the whole row only for WARN and ERROR (or making the row tint optional), would keep severities visible without hurting the text.6. Color values by type
hl gives booleans, numbers,
nulland quoted strings their own colors:secure=falsestands out at once. In Sofka every value has the color of the row.7. Flatten nested objects
A nested object is printed as compact JSON, which is long and noisy:
Flattening objects into dotted keys keeps them on the row and readable. Arrays can stay compact JSON.
8. A shorter time
2026-10-08T15:00:20.444Ztakes 24 columns on every row; hl'sOct 08 15:00:20.444takes 19, and the date is rarely needed in a live tail.talready hides the time entirely; a format option would sit between the two, for example:The time is kept as the application wrote it when it is a string, so this would apply only when it parses as RFC 3339.
9. Quote keys that contain spaces
controller-runtime logs a key with a space:
worker count.record_valuequotes ambiguous values, but keys are written as is, soworker count=1reads as a bare wordworkerfollowed bycount=1. Quoting a key that contains whitespace,=or"("worker count"=1) would remove the ambiguity. hl does not do it either; it would be an easy improvement over both.Smaller points
INF,DBG,WRN,ERR) would save 2 columns per row and align the messages. This is a matter of taste: a config option or the current names are both fine.Implementation options
Two ways to get there:
lib.rsexportsParser,RecordFormatter::format_recordandTheme. The formatter writes one line with ANSI styles, which the log view already maps. Running in-process avoids most of the problems you listed for an external formatter: no child process, no buffering, one output line per input line (with hl's multi-line expansion turned off). The blockers:hlname belongs to another, older crate), and a crates.io package cannot depend on a git repository. hl would first need to publish a library crate.clap,capnp,pager,notify,config...): about 80 in total.We lean towards the first option, but you know the codebase better. If the second one appeals to you, we can ask hl's maintainer about a lighter library crate.
If some of these are welcome, we're happy to help: test builds, or a PR on the easy ones (1, 2, 9).
All reactions