Skip to main content

Crate flogging

Crate flogging 

Source
Expand description

§FLogging

The primary purpose of logging, is to facilitate fault diagnosis through the provision of specific information as, when, and from where, it is needed. This could be during development, testing, or even during production runs.

There is a new tutorial guide: The FLogging Guide.

§Setting up

You need to add this crate to your project:

$ cargo add flogging

or add this text to the projects Cargo.toml file:

[dependencies]
flogging = "0.6.0"

§** Warning **

Before proceeding, please read the README.md file.

§Features

  • Levels - There are nine (9) levels of message logging, with two (2) special ones.
  • Choice - You can use either macros, methods, or a mix of both.
  • Built-in options - A range of handlers and formatters.
  • Customization - You can create your own handlers and/or formatters.

§Choice

§Macros

This crate has very easy to use macros. By using them, you remove a lot of the complexity from the process. Thus making it both simpler and less code cluttering, to use.

Check out the Examples below, or The FLogging Guide, for how easy it is to get started.

§Special Note

For the macros that accept the parameter: msg, the following is true:

  • They accept parameters the same as for std::format!
    • plain text &str: ("It's your time.")
    • format &str with interpolated variables: ("Var: {var}")
    • format &str with supporting parameters: ("Var: {}", var)
    • Combination of the last two: ("Vars {var1} - {}:{}", var2, var3)
  • Additional Feature
    • Just one or more variables without a supplied format string: (var1, var2, var3)
    • In this case, a default format string will be used: "{}, {}, {}"
    • The number of "{}" will depend on the number of parameters.
    • Ideal for logging concrete instances that have very good Display implementations, or you just need their data without further explanation.
  • Special Cases
    • entering! and exiting!
    • These two macros have the same features as the others, but they may also be used without any parameters. In such a case, their defaults will be used.
§Methods

Now for the coding geeks! Yes I didn’t forget you lot.

Though the macros are the easiest and simplest way to use this crate, those macros are just candy coating over the real workers, the methods. There are two main mods/structs in this crate, Logger and LoggerBuilder.

§Logger

Logger is the work-horse of the crate. It has all the methods for initializing each function/method for logging, and all of the message logging methods.

Using the “methods” option is more complex, as-in, you have to write a lot more code, and manage it. To see how much more is involved, check-out the Logger’s methods. There are plenty of examples throughout.

§LoggerBuilder

LoggerBuilder is used by Logger to provide various configuration options for setting up your logger. The available options/methods are:

And to finish:

These options/methods allow you a lot of flexibility in how you configure your logger. As you will typically have a different logger for each mod/file, you have a lot of control over what is logged, how it is formatted, and where it is stored/viewed. With the set_level() method, you can control this on a mod/file basis. Logging each mod/file differently, or even turning logging off when you no-longer require it.

Check out The FLogging Guide for examples and further help.

Note

As of version (0.4.0), you can only set the logging level for the logger. All handlers process every log entry that the logger accepts, based on the logger’s current log level setting. This may change in a future version, allowing each handler to have its own logging level.

§Built-in options

I have included a number of handlers to get you started:

There are also a number of formatters as well:

§Customization

Now for the fun part - “Doing it your way!!!”

Though I have provided some “standard” handlers and formatters, not everyone, or every project, will want to use them. I expect there will be a need for:

  • sending log entries to remote system log servers,
  • sending log entries to another program (local or remote) for live analysis, or some other processing,
  • storing log entries in a specific file format (xml, json, csv),
  • storing log entries in a database.

And I’m sure you’ll come-up with more requirements at some time in the future. So, you have the option to create your own custom handlers and custom formatters. Mixing them up with the built-in ones as you need to.

OK now, how do you do it. Well this is going to require some work on your part.


For a more in-depth tutorial refer to The FLogging Guide.


§Custom Handler

To create a custom handler, I would suggest looking at the source code for the built-in ones, and copying the code from the one that is closest to your requirements. Make sure that you rename as appropriate! Then make the necessary changes, adding in your own code, to get it doing what you need.

When you are ready to try-out your new custom handler, check-out these methods:

§Custom Formatter

Now for the custom formatter. This may require a bit more investigation on your part, as to the actual formatting options that are available.

Firstly, this crate uses crono for the date/time functionality. Check out the available specifiers. You will need to use the formatting options from this crate for the dt_fmt string, of your custom formatter.

Secondly, the fmt_string uses the format options available in accordance with std::fmt. Though I am actually using the strfmt crate to do the formatting, because it does not require a ‘static’ string like format!().

Again, check-out the built-in formatters, and copy the code from the one that is closest to your requirements. As before, renaming as necessary! Also, check-out the trait: FormatTrait. You will need to implement it for your custom formatter, as you will notice when you look at the built-in formatters. Also, you will find that the ‘provided method’, ft_fmt(), provides certain variables that you can include, via interpolation, in your fmt_string.

Once you have got your custom formatter set up, you can then use it with:

§Examples

This example demonstrates the use of the macros. The reason I am demoing the macros, is that I expect most people will want to use them, instead of the methods, for ease of use.

Let’s see what is required:

  1. At the module/file level:
    • use flogging::*;
    • const_logger!({...});=>
  2. On each function/method you want to add logging to:
    • #[logger]=>
  3. Inside each such attributed function/method:
use flogging::*;
use std::{error::Error, result::Result};

// Setting up the module level logger.
const_logger!({
    Logger::builder(module_path!())
        .add_console_handler()
        .add_file_handler("test_logs/debug.log")
        .set_level(Level::FINEST)
        .build()
});

#[logger]
fn do_something() {
    entering!();

    // do some work worth noting
    let result = "Just something to log.";
    info!("Did some work here.\n  {result}");

    // ...

    fine!("Bit more detail.");

    if let Err(e) = error_prone() {
        warning!("Error: {}", e);
    }

    exiting!();
}

#[logger]
fn error_prone() -> Result<(), Box<dyn Error>> {
    entering!();
    let rtn = Err(Box::from("Bad day!"));
    exiting!();
    rtn
}

#[logger]
fn main() {
    entering!();
    info!("All logging macros accept the same parameters as `std::format!(...)`");
    warning!("Those same macros (info, etc.) MUST have atleast one parameter.");
    config!("This is running on Fedora Linux 42.");
    do_something();
    info!("Job's done.");
    exiting!();
}

Output:

flogging->main [FINER  ] Entry
flogging->main [INFO   ] All logging macros accept the same parameters as `std::format!(...)`
flogging->main [WARNING] Those same macros (info, etc.) MUST have atleast one parameter.
flogging->main [CONFIG ] This is running on Fedora Linux 42.
flogging->do_something [FINER  ] Entry
flogging->do_something [INFO   ] Did some work here.
  Just something to log.
flogging->do_something [FINE   ] Bit more detail.
flogging->error_prone [FINER  ] Entry
flogging->error_prone [FINER  ] Return
flogging->do_something [WARNING] Error: Bad day!
flogging->do_something [FINER  ] Return
flogging->main [INFO   ] Job's done.
flogging->main [FINER  ] Return

Macros§

config
Log a CONFIG message.
const_logger
Setup module level logger access.
entering
Log entry into a function/method.
exiting
Log return from a function/method.
fine
Log a FINE message.
finer
Log a FINER message.
finest
Log a FINEST message.
get_handler
Get the required Handler.
info
Log an INFO message.
is_logging
Checks whether or not this logger is processing log requests.
set_level
Set the logging level for this Logger instance.
severe
Log a SEVERE message.
warning
Log a WARNING message.

Structs§

ConsoleHandler
Publishes log entries to the console.
ConsoleTypeError
Returned from FromStr::from_str() when an unknown string is passed-in.
ConsoleTypeIter
An iterator over the variants of ConsoleType
FileHandler
Publishes log entries to the file whose name was provided during initialization.
Iso8601Formatter
ISO 8601 / RFC 3339 date & time format.
LogEntry
Used to provide relevant information about each log entry.
Logger
This is the work-horse, providing the primary methods of the crate.
LoggerBuilder
Used by Logger to provide more flexibility in the configuration of the final logger.
MockFormatter
Mock Formatter.
MockHandler
This is used as a fake or mock handler.
SimpleFormatter
Simple format.
StringHandler
Publishes log entries to an internal list.
UnixTimestampFormatter
Unix Timestamp format.

Enums§

ConsoleType
ConsoleType configures the ConsoleHandler’s output.
FormatType
Used as a simple way to obtain the various Formatters.
Formatter
Provides wrappers for holding each type of formatter.
Handler
Available handlers.
Level
Log entry level setting.

Traits§

FormatTrait
Provides methods for formatting LogEntrys.
HandlerTrait
Provides common methods required for all handlers.

Attribute Macros§

logger
Provides for logging within the attributed function/method.