Skip to content

Core Concepts

Eduard Mishkurov edited this page May 4, 2026 · 3 revisions

Core Concepts

logme is built around a small number of concepts that work together on the hot path. The important part is not only what each object represents, but also where work is avoided when a message is filtered out.


General idea

A log call in logme starts with a cheap decision: should this message be processed at all? Only after that decision succeeds does logme build the message context, format the text and pass the result to backends.

This matters because logme macros are designed to keep disabled logging cheap. The first macro argument is used for the precheck, and formatting arguments are not evaluated when the message would not be logged.


Channel

A channel is the main runtime logging object. It is not just a name printed near a message.

A channel owns the settings that decide whether a message can pass through it: the enabled state, filter level, output flags, backend list and optional link to another channel. Runtime control commands such as channel --enable, channel --disable, level --channel ... and backend --channel ... operate on this object.

Typical channel names describe the source of messages, for example HTTP, TLS, DB or an application-specific component. The default channel is also a real channel; named channels are additional routing and filtering points.


Subsystem (SID)

A subsystem is an additional tag attached to a message. It is packed into a SID value and can be used to refine filtering inside the current logging configuration.

Subsystems are not channels. A subsystem does not own backends and is not enabled or disabled like a channel. Runtime subsystem control works through blocked and allowed lists:

logmectl -p 7791 subsystem --block http
logmectl -p 7791 subsystem --allow core
logmectl -p 7791 subsystem --check http

Blocked subsystems are never logged. If the allowed list is not empty, only listed subsystems are logged, unless they are also blocked. Messages without a subsystem are not affected by subsystem filtering.


Backend

A backend defines where already accepted messages are written: console, file, debugger, buffer, shared file or a custom destination.

Backends are called after filtering and formatting decisions have been made. In the normal flow, a message reaches backend code through Channel::Display(). If the precheck rejects a message, backend code is not involved at all.

A channel can have several backends. A message written to that channel can therefore be delivered to multiple destinations without changing the log call in application code.


Context

When a message passes the precheck, logme creates a Context. It carries the message text, level, source location, method name, timestamp state, channel, optional subsystem and other data needed by formatters and backends.

The same context can be rendered as normal text, JSON or XML depending on OutputFlags. Structured fields such as timestamp, level, channel, subsystem, file, line, method, message and duration are generated from this context when structured output is enabled.


Message flow

The practical flow is:

logging macro
  -> precheck using the first macro argument
  -> Context creation
  -> message formatting
  -> Logger::DoLog()
  -> Channel::Display()
  -> backend output

The exact macro family changes the entry point, but the same idea remains: do the cheap check first, and do expensive formatting only when the message will really be emitted.


Linked channels

A channel may be linked to another channel. This lets one channel forward messages after handling its own output. The DisableLink output flag can suppress this propagation for a particular output configuration.

This is useful when a project wants local routing for a component but still wants selected messages to reach a common destination.


Why it is structured this way

The split between channels, subsystems, contexts and backends is what allows logme to combine low overhead with runtime control. Filtering happens before message construction where possible. Routing is controlled by channels. Subsystem rules refine filtering without pretending that every tag is a separate channel. Backends remain focused on output.

That is why changing a level, adding a backend or blocking a noisy subsystem can be done in a running process without changing application logging calls.

Clone this wiki locally