Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Explain (Part 1)

Ok, what’s happening in this code?

Let’s look at the first part:

use flogging::*;
use std::{error::Error, result::Result};

// Setting up the module level logger.
const_logger!({ // <= [1]
    Logger::builder(module_path!())
        .add_console_handler()
        .remove_file("test_logs/usage.log")
        .add_file_handler("test_logs/usage.log")
        .set_level(Level::ALL)
        .build() // <= [2]
}); // <= [1] [3]

Some gotchas. Well atleast they keep getting me:

  • [1] - You must have the internal braces wrapping the
    { Logger::builder(...) ... } code.
  • [2] - Do not terminate the braced code with a “;”.
    In this example, after the .build()
  • [3] - Don’t forget the final “;” after the macro: “});

I think the first two lines are self explanatory.

So let’s dive into the const_logger({...}); macro.

The API says:

Setup module level logger access.

The basic macro syntax is:

    const_logger!({/* the block of Rust code to build a Logger goes here */});

Notice there are curly braces "{}" wrapping the inner Rust code. **They are required**.

The code you put in here will depend on what configuration of Logger you want to setup.

As you can see, we are using the Logger::builder(...) method. With this we can be very specific about the logger that we end-up with. Note that this method returns a LoggerBuilder object and not a Logger object. The appended methods, are all implemented under LoggerBuilder. The final method above, build(), returns the fully configured Logger object.

The primary purpose of this macro, is to setup a mod/file level logger environment. This is required to be able to use the rest of the macros.

If you look into the API, you will find many possible options for your logger configuration.


Please note:

It states “module level”.

Each module or file will require its own instance of this setup. This is intentional, to keep things simple to follow and maintain. Each mod/file has a different module_path! which can only be set within its own instance of this setup. Without this distinction, your logs would be an anonymous mess, such that you would not easily know from where a log entry came.

Let’s assume you want to setup just a “global” instance in lib.rs, to be used by all of its “child” mods/files. This is what you might get from logging a function - do_it():

my_project->do_it [FINER  ] Entry

or with individual instances (as currently required):

my_project::core::control->do_it [FINER  ] Entry

where both examples are from the file: src/core/control.rs.

Another reason for separate instances, is that you may want different logger configurations for each one, or atleast, for one or more of them.

One possibility, might be a ‘mod’ that uses add_pconsole_handler(), to be able to have INFO level log entries output to the console without any formatting, like this:

This text came from the file `src/core/mod.rs`, just to let you know.

instead of:

my_project::core::mod->do_it [INFO   ] This text came from the file `src/core/mod.rs`, just to let you know.

You might set this particular file’s instance to log level Level::INFO, and have regular types of textual output that would be a normal part of the running program.

Mix and match - Have fun!!!