Log.info vs. log.debug for printing console information

So I’ve recently started using std.log, and while I like the API in general, one thing is a bit confusing to me:

log.info and log.debug are both disabled in release modes, but enabled in debug builds, making them (to me) functionally identical.

What’s the difference between them?

I was historically very confused by the log levels. What deconfused me was approaching the levels not from the perspective of “what is the purpose of level, judging by name”, but rather from the perspective of “what the level actually does”? There, we have the following levels:

  • Page the operator immediately (log.error)
  • Page the operator if the message repeats (log.warning)
  • Show to the operator by default (log.info)
  • Show to the operator/developer via opt-in (log.debug)

Recently, I’ve come to realize that it’s perhaps wroth splitting info further into two:

  • messages that the operator sees in the terminal as the system operates, emitted at a human-perceptible rate (so, several messages a minute) (log.notice)
  • messages that are saved to a log file for processing via tail -f | grep (log.info)

In terms of Zig’s actual log levels, you can override them with

pub const std_options: std.Options = .{
    .log_level = .info,
};

placed in the file with pub fn main (stdlib introspects on the value of this constant via @import("root")). The default log level is info in ReleaseSafe

pub const default_level: Level = switch (builtin.mode) {
    .Debug => .debug,
    .ReleaseSafe => .info,
    .ReleaseFast, .ReleaseSmall => .err,
};
6 Likes

I think log levels can be very project dependent. i.e., you define what they mean and how they’re used. You may even decide you don’t want to use some levels, or even roll your own (e.g., critical or fatal that’s above error that could mean its an error that’s more system wide than more isolated to one session)

I see the the base levels like

  • error - something went wrong and needs immediate attention (e.g., Failed to save game file)
  • warning - something looks like it may need attentions (e.g., Disk space low - may impact saving games)
  • info - simple, short and “informational” (e.g., User successfully saved X kb game file)
  • debug - more detailed trace information or object dumps that may span multiple lines (e.g., “User game file object: { … }”)

On a related note, regarding what goes into a log message, you generally want to avoid personally identifiable information in logs, which is easy to mess up when you just start dumping all of the things while debugging.

1 Like

The concept of lig levels debug, info, warning, error (and sometimes: fatal or severe) is used in nearly all logging frameworks and programming languages, so you should get used to it.
Usually, they are ordered in the sense of severity, and you configure the minimum severity your want to log.
Debug means you only want to enable this while debugging. The messages don’t really need to be understood by end users, but they should help the support team and the developers.
Info is what you usually want to see to understand what is going on in normal situations. Insofar I think this should be the default level when no explicit configuration is available, instead of warning. Zig’s default is a little unfortunate IMHO.
Warning means, something is not ok but the program can handle it automatically.
Error means, something is wrong, the program cannot simply work around this and you should expect that the program cannot generate the intended output from the given input.
Fatal is even more severe, it usually means that the program actually has to stop as a consequence.
When a program runs successfully for months, in some cases you want to switch from info to warning, to avoid writing too much log output. Always keep in mind that a good logging framework should support automatic housekeeping (clean up old log files).

I sometimes use an additional level (not yet in Zig), like “notice” or “important” or “always”, for messages that should always been logged, independent from the configured min level.

1 Like

Maybe it wasn’t obvious, but my question was specific to the Zig std.log API and not to logging levels in general. Still, lots of good info in the thread now, that never hurt anyone. :sweat_smile:

I was wondering why log.info didn’t seem to be different from log.debug.

It’s because I’m only using ReleaseSmall, which has both disabled by default, and Debug, which has both enabled by default. Building in ReleaseSafe they’d be different.

1 Like

Having thought a little about it, I think Zig’s default is very understandable.

The general recommendation AFAIK is that people release their software in ReleaseSafe mode, which has optimization enabled (and debug info stripped?), but still performs runtime safety checks.

If you’re building in ReleaseSmall or ReleaseFast you’re opting out of runtime safety to improve a performance metric. In either of those cases you’d probably want to disable non-critical logging anyway.

If you didn’t you’d be leaving (speed | binary size) on the table, and if you’re doing that you may as well release in ReleaseSafe to get the runtime safety checks.

Note that the behaviour actually changed in master about a week ago with commit 36cf22c5. .info is the default in all Release modes now.

5 Likes