module Logs:sig
..end
Logs
provides a basic logging infrastructure. Logging
is performed on sources whose reporting
level can be set independently. Log message
report is decoupled from logging and handled by a
reporter.
See the basics and a few usage conventions to respect.
Release 0.4.2 - Daniel Bünzli <daniel.buenzl i@erratique.ch>
type
level =
| |
App |
| |
Error |
| |
Warning |
| |
Info |
| |
Debug |
Logging sources have an optional reporting level. If
the level is Some l
then any message whose level is smaller or
equal to l
is reported. If the level is None
no message is
ever reported.
val level : unit -> level option
val set_level : ?all:bool -> level option -> unit
set_level ?all l
sets the reporting level given to
new sources. If all
is true
(default), also
sets the reporting level of all existing sources. Use
Logs.Src.set_level
to only affect a specific source. Only applications
should use this function directly see usage conventions.type
src
val default : src
module Src:sig
..end
module Tag:sig
..end
type'a
msgf =(?header:string -> ?tags:Tag.set -> 'a) -> unit
Message formatting functions are called with a message
construction function whenever a message needs to be reported. The
message formatting function must call the given message
construction function with the arguments of the message. The
arguments of the message are defined by the format string of the
log function see Logs.log
for examples. The optional arguments of the message
construction function are:
header
, an optional printable message header. Default to None
.tags
, a set of tags to attach to the message. Defaults
Logs.Tag.empty
.val unit_msgf : ?header:string -> ?tags:Tag.set -> unit -> unit msgf
unit_msgf ?header ?tags ()
is (fun m -> m ?header ?tags)
.val unit : unit msgf
type'a
log =('a, Format.formatter, unit) Pervasives.format -> 'a msgf -> unit
For minimizing the overhead whenever the message is not reported, message formatting only occurs on actual message report via the message formatting function. This leads to the following logging structure:
Logs.err "invalid key value pair (%a,%a)"
(fun m -> m pp_key key pp_val value);
The pattern is quite simple: it is as if you were formatting as
usual except you need to interpose the function with the m
argument standing for the format string. If your format string has no
directives, the type system will annoy you with the formatting function
because of the optional arguments. You have to write:
Logs.err "You are doomed!" (fun m -> m ?header:None ?tags:None);
To avoid this Logs
provides the constant formatter Logs.unit
so that you can simply write:
Logs.err "You are doomed!" Logs.unit;
val msg : ?src:src -> level -> 'a log
msg ?src l fmt (fun m -> m ...)
logs with level l
on the source
src
(defaults to Logs.default
) a message formatted with fmt
. For the
semantics of levels see the the usage conventions.val app : ?src:src -> 'a log
app
is msg App
.val err : ?src:src -> 'a log
err
is msg Error
.val warn : ?src:src -> 'a log
warn
is msg Warning
.val info : ?src:src -> 'a log
info
is msg Info
.val debug : ?src:src -> 'a log
debug
is msg Debug
.val kmsg : (unit -> 'a) ->
?src:src ->
level ->
('b, Format.formatter, unit, 'a) Pervasives.format4 ->
((?header:string -> ?tags:Tag.set -> 'b) -> 'a) -> 'a
result
value Error
sval on_error : ?src:src ->
?level:level ->
?header:string ->
?tags:Tag.set ->
pp:(Format.formatter -> 'b -> unit) ->
use:('b -> 'a) -> ('a, 'b) Result.result -> 'a
on_error ~level ~pp ~use r
is:
v
if r = Ok v
use e
if r = Error e
. As a side effect msg
is logged
with pp
on level level
(defaults to Logs.Error
).val on_error_msg : ?src:src ->
?level:level ->
?header:string ->
?tags:Tag.set ->
use:(unit -> 'a) -> ('a, [ `Msg of string ]) Result.result -> 'a
module type LOG =sig
..end
val src_log : src -> (module Logs.LOG)
type
reporter = {
|
report : |
A reporter formats and handles log messages that get
reported. Whenever a log function gets called on a source
with a level equal or smaller to the source's reporting
level, the current reporter's field r.report
gets called as r.report src level k fmt msgf
where:
src
is the logging source.level
is the reporting level.k
is the function to invoke to return.fmt
is the message format string.msgf
is the message formatting function to call.val nop_reporter : reporter
nop_reporter
is the initial reporter returned by Logs.reporter
, it
does nothing if a log message gets reported.val reporter : unit -> reporter
reporter ()
is the current repporter.val set_reporter : reporter -> unit
set_reporter r
sets the current reporter to r
.val err_count : unit -> int
err_count ()
is the number of messages logged with level Error
across all sources.val warn_count : unit -> int
warn_count ()
is the number of messages logged with level
Warning
across all sources.If you are writing an application you must remember to set the reporter before any logging operation takes place otherwise no messages will be reported. For example if you are using the standard outputs reporter, logging can be setup as follows:
let main () =
Logs.set_reporter (Logs_stdo.reporter ());
...
exit (if Logs.err_count > 0 then 1 else 0);
()
If you have logging code that is performed in the toplevel
initialization code of modules (not a good idea) or you depend on
(bad) libraries that do so, you must call and link the reporter
install code before these initialization bits are being
executed otherwise you will miss these messages.
The documentation of Logs_cli
module has a full setup
example that includes command line options to control color and log
reporting level.
The basics for using the logging functions is explained here. Note that log messages hit the reporter and are formatted only if they have not been filtered out by the current reporting level of the source you log on.
If you are writing a library you should neither install reporters, nor
set the reporting level of sources, nor log on the Logs.default
source or
at the App
level; follow the the usage conventions. A
library should simply log on an another existing source or define
its own source like in the example below:
let src = Logs.Src.create "mylib.network" ~doc:"logs mylib's network events"
module Log = (val Logs.src_log src : Logs.LOG)
The Log
module defines logging functions that are specific to the
source src
.
A library should never log on the Logs.default
source or at the
App
level these are reserved for use by the application. It
should either create a source for itself or log on the source
defined by one of its dependencies. It should also never set the
reporting level of the sources it deals with or install reporters since
control over this must be left to the application.
The semantics of reporting levels should be understood as follows:
App
, this level can be used for the standard output or console
of an application. It should never be used by libraries.Error
, error condition that prevent the program from
running normally.Warning
, suspicious condition that does not prevent the
program from running normally but may eventually lead to an
error condition.Info
, condition that allows the program user to get a better
understanding of what the program is doing.Debug
, condition that allows the program developer to get a
better undersanding of what the program is doing.