easy_logging
Easy logging
Logging library inspired by the Python logging module.
Easy_logging allows fine-grained tuning of of when and where and how log messages are printed, with relatively low configuration, and simple logger configuration and usage.
It has the following features :
- one line logger creation
- log messages printf style, or provide
string
orstring lazy_t
message - loggers for tree architecture for easy level and handlers configuration
- handlers associated to each logger will filter, format and treat the message independantly
- use tags and tag generators to add contextual information to log messages
- use default handlers for outputing log messages to stdout, stderr or to a file
- declare your own handler for anything else
Basic example
open Easy_logging
logger = Logging.make_logger "my_logger" (Some Debug) [Cli Debug]
logger#info "log_message"
will output to the stdout a message of the form
1.306 my_logger Info log_message
Table of contents
- Overall description (see also
Easy_logging
) defaults
- Handlers (see also
Easy_logging__Handlers
) - Loggers (see also
Easy_logging.Logging.logger
) - The Logging module (see also
Easy_logging.Logging
)
- Handlers (see also
- The MakeLogging functor (see also
Easy_logging__Make_logging.MakeLogging
) - More examples
- Index of modules
Overall description
The logging infrastructure is based on four concepts:
loggers, handlers, log items and logging tree.
A call to logger will create a log item, which it will pass to its handlers. Each handler will treats the item (e.g. transform it to a string, and then outputs to stdout or to a file).
___________ | handler 1 | _______________ |-----------| | logger | ==> | ( * ) | |---------------| |___________| (message) ==> | -> log item | ___________ [_______________| ==> | handler 2 | | ... |
Logging tree
Loggers are stored in a tree structure, with the following properties :
- messages handled by a logger (after level filtering) are passed to its ancestor's handlers (this can be overriden with the
set_propagate
method). - if not set, the level of a logger is that of its closest ancestor whose level is set (or NoLevel if there is no such ancestor)
Example
A (Info, Cli Debug) / \ A.B A.C / \ A.B.D (Warning) A.C.E (Debug, (File "f", Debug), propagate=false)
For example, with the above logging tree
- logs made to
A
,A.B
orA.C
of levelInfo
or more are written to the stdout. - logs made to
A.B.D
of levelWarning
or above are written the stdout. - logs made to
A.C.E
are only written to the file"f"
Levels
To each logger and log message are associated a level, which will be used to filter the messages going through the logging infrastructure.
The predefined levels are, in increasing order of precedence :
- Debug : used for debugging.
- Trace : used between info and debug
- Info : used to trace program execution.
- Warning : used for warnings.
- Error : used for errors.
- Flash : used for one-shot debugging: displays an easy to spot message.
- NoLevel : used to filter out all messages.
Log items
A log item has type
type log_item = {
level : level; (* the level of the log item *)
logger_name : string; (* the name of the logger to which the log call was passed *)
msg : string; (* the actual log message *)
tags : string list (* a list of tags *)
}
Handlers
Four handler creation helper function are provided. They instantiate handlers with a level of their own to filter messages :
Cli handler: outputs colored messages to stdout.
let h = Handlers.make (Cli Debug)
CliErr handler: outputs colored messages to stderr.
let h = Handlers.make (CliErr Debug)
File handler : outputs messages to a given file.
let h = Handlers.make (File ("filename", Debug))
RotatingFile handler : outputs messages to a given file. Takes as argument the max number of kb per log file, and the number of backup log files.
let h = Handlers.make (RotatingFile ("filename", Debug, 65536, 3))
Log file creation is governed by configuration values (setting up file name prefix/suffix, folder, file creation mode, etc...). The configuration can be specified when creating the handlers explicitely (like above), and a default configuration can be set in the Logging module.
See more at Easy_logging.Handlers
Loggers
See complete class documentation at Easy_logging.Logging.logger
Creation
A logger object can be created directly (in which case it will not be part of the logging tree)
let logger1 = new Logging.logger "my_logger1"
or through helper functions of the The Logging module module.
Usage
A logger object has three methods for each of the log levels:
one that takes a formatting string and parameters (printf like)
logger1#debug "Myvar : %s" (to_string myvar);
one that takes a
string lazy_t
logger1#ldebug (lazy (heavy_calculation ()));
one that takes a
string
logger1#sdebug (to_string myvar);
The Logging module
The Easy_logging.Logging
module is the application of MakeLogging
over Handlers
. It provides two functions :
val make_logger : ?propagate:bool -> string -> log_level -> Handlers.desc list
Instantiates a logger with some paramters, and adds it to the logging tree.
val get_logger : string -> logger
Returns a registered logger, or creates a new one if it doesn't exist.
val set_handlers_config : Handlers.config -> unit
Sets the default handlers configuration, used when creating new handlers via
make_logger
.
The MakeLogging functor
The MakeLogging functor takes a Easy_logging__
.Easy_logging_types.HandlersT typed module, and creates a Logging module.
WARNING
When declaring your Handlers module, do not coerce it the type HandlersT
, because then its internal types t
and desc
won't be accessible.
Examples
See the examples page for more examples.