logger: ERROR=254 vs CRITICAL=40 inverts standard severity ordering — intentional or accident? #143
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_lib#143
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Question
herolib_core/src/logger/level.rsdefines:The bottom five values follow a clean Python-style "gap of 10" progression (modeled on
logging.DEBUG=10 / INFO=20 / WARNING=30 / ERROR=40 / CRITICAL=50, shifted down by 10 with NOTICE inserted at 20 like syslog). That part is recognizable and intentional.But
LOG_LEVEL_ERROR = 254jumps far aboveLOG_LEVEL_CRITICAL = 40, which means hero_log is asserting ERROR is more severe than CRITICAL. That inverts every mainstream logging convention I checked:loggingCRITICAL=50 > ERROR=40critical=2 < error=3(lower = more severe)FATAL > ERROR > WARN > INFO > DEBUGjava.util.loggingSEVEREis top, no separate ERROR/CRITICAL distinctionIn all of them, "critical" (or "fatal") sits at or above "error" in severity.
What I think is going on (three possibilities)
Intentional redefinition: hero_log is saying "ERROR means system-down / catastrophic / page-someone-now", and "CRITICAL" is a step below — something that needs attention but isn't an outage. That's a defensible position; it's just idiosyncratic enough that callers will be surprised. If so, the README/docstring should call it out explicitly.
Intentional sentinel placement: ERROR is being pushed to the byte ceiling (254, with 255 reserved) so any reasonable
loglevel_maxfilter includes it. That makes ERROR effectively the catch-all "always-show" tier. Reasonable wire-format thinking, but the side-effect is the inverted severity ordering.Accidental ordering swap: someone wrote DEBUG/INFO/NOTICE/WARNING/CRITICAL in Python order, jammed ERROR at 254 as a wire-format reserve, and didn't notice the severity ordering had inverted.
I can't tell which of these it is without asking.
Why I'm raising this
In
hero_proc#33d4851I rewrote the local↔hero loglevel mapping to be 1:1 monotonic over0..=5, mapping local 5 toLOG_LEVEL_ERROR(preserving the existing ordering — local 5 ends up most severe). That fixed the lossy round-trip that was breakingfunctional::runs::structured_logs_all_levelsinhero_proc_test. But if the ordering of ERROR vs CRITICAL gets flipped later, that mapping needs to flip with it.So before more consumers grow code that depends on the current ordering, I wanted to surface the question.
Concrete asks
LOG_LEVEL_ERROR = 254placed aboveLOG_LEVEL_CRITICAL = 40deliberately? If yes:level.rsand the logger README so callers don't writeloglevel_max=CRITICALthinking they'll see errors too.LOG_LEVEL_FATALfor the 254 slot if "ERROR" is being used in a non-standard sense.LOG_LEVEL_ERROR = 50(Python-aligned) or somewhere ≥ 40 but below RESERVED.Either way I can adjust the hero_proc mapping to match — I just want the convention to be deliberate, not accidental.
cc whoever owns
herolib_core/logger.Audit: blast radius of correcting
ERROR=254 → 40, CRITICAL=40 → 50I grepped every
hero_*repo for usages ofLOG_LEVEL_ERROR/LOG_LEVEL_CRITICALand raw values254/40in log contexts. Conclusion: the correction is surgical — almost no consumer needs source edits.Consumer audit
12 repos check —
hero_collab,hero_db,hero_indexer,hero_lib(internal),hero_os,hero_osis,hero_proc,hero_proxy,hero_router,hero_slides,hero_voice,hero_whiteboard. Every one uses the named constant form, e.g.:Zero raw
254usage anywhere outside the constant definition itself. Zero raw40in log contexts (one hit inhero_lib/crates/crypt/symmetric/utils.rs:127islen >= 40— unrelated buffer-size check). So all 12 repos recompile transparently against the new constant values.What actually needs to change
herolib_core/src/logger/level.rsLOG_LEVEL_ERROR: 254 → 40,LOG_LEVEL_CRITICAL: 40 → 50. Update thefrom_u8match arms. Enum discriminants follow the constants. ~6 lines.herolib_core/src/logger/README.mdhero_proc/crates/hero_proc_server/src/logging/adapter.rslocal_level_to_hero(local 4 → ERROR,local 5 → CRITICAL) and the matching arms inhero_level_to_local. 6-line swap; my recent fix (33d4851) used named constants, so it'll re-build but I need to fix the LOCAL↔HERO ordering so monotonicity follows the corrected hero values.Pre-prod migration: not needed
Per Sameh: customer base is still developers-only, so existing log files with byte
254don't need migration. Anyone bothered by old TSV entries can justrm -rf ~/hero/var/logs/after the bump.Suggested PR sequence
level.rs+README.md. Single file pair, trivial. Tag a minor bump after.Cargo.toml+ the 6-line adapter swap. Re-runshero_proc_test --basic --functionalto confirmstructured_logs_all_levelsstill passes (it relies on the round-trip my mapping provides — if I get the swap right, it stays green).If you (or whoever owns the logger) take the hero_lib side, I'll handle the hero_proc follow-up.
Closes the ordering question regardless of outcome — either you confirm intentional inversion and I document it, or you take the fix.