ComponentLogging.jl gives you fine-grained, per-group control over logs with function-first APIs (clog
/ clogenabled
/ clogf
) and a plain, IO-agnostic design that keeps hot paths cheap. It is maintained under the JuliaLogging organization.
Why ComponentLogging
Many compute-heavy functions need different levels of verbosity, and printing intermediates can slow hot loops unless you can cheaply decide when to log and when to skip work.
ComponentLogging builds on Julia’s CoreLogging
to route/filter by “component” (symbol or tuple of symbols), so you can enable exactly the areas you care about and let everything else be silent.
Nanosecond-scale routing: the router itself is nanosecond-level; end-to-end cost is dominated by your chosen AbstractLogger
(formatting/IO) and by message construction (e.g., string interpolation or recomputation). clogenabled(...)
lets you defer construction until logging is actually enabled, preserving hot-path performance.
Usage at a glance
using ComponentLogging
rules = Dict(
:core => 0, # Info+
:io => 1000, # Warn+
(:net, :http) => 2000, # Error+
:__default__ => 0,
)
sink = PlainLogger() # any AbstractLogger sink works
clogger = ComponentLogger(rules; sink) # router / filter
# App-wide forwarding helpers
clog(args...; kwargs...) = ComponentLogging.clog(clogger, args...; kwargs...)
clogenabled(args...) = ComponentLogging.clogenabled(clogger, args...)
clogf(f, args...) = ComponentLogging.clogf(f, clogger, args...)
# Use it
clog(:core, 0, "starting job"; jobid=12)
if clogenabled(:core, 1000)
stats = compute_expensive_stats()
clog(:core, 1000, "stats ready"; stats)
end
clogf(:core, 1000) do
stats = compute_expensive_stats()
"lazy message built only when enabled"
end
This setup lets you control output granularity with a small set of rules and keep expensive work behind guards or lazy blocks.
Deeper docs, options, and benchmarks live in the README.md.
PlainLogger in a nutshell
If you prefer output that looks like println
, PlainLogger
is a tiny sink that writes messages without the usual [Info:
prefixes, and it uses MIME"text/plain"
to pretty-print 2D/3D matrices for readability You can use it standalone or as the sink behind ComponentLogger
.
A note on levels
You can pass integers instead of LogLevel
, which keeps call sites simple while remaining compatible with the stdlib interface For example, 0
corresponds to Info
, and you can set group thresholds via integers in the rules table.
Temporarily silence everything
Wrap work in with_min_level
to raise the global minimum temporarily—for instance when benchmarking a function without logging overhead.
with_min_level(2000) do
@benchmark compute_expensive_stats()
end