Module Logs

module Logs: sig .. end
Logging.

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>



Reporting levels and sources


type level = 
| App
| Error
| Warning
| Info
| Debug
The type for reporting levels. For level semantics see the usage conventions.

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
level () is the reporting level given to new sources.
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 
The type for log sources. A source defines a named unit of logging whose reporting level can be set independently.
val default : src
default is a logging source that is reserved for use by applications. See usage conventions.
module Src: sig .. end
Sources.

Log functions


module Tag: sig .. end
Message tags.
type 'a msgf = (?header:string -> ?tags:Tag.set -> 'a) -> unit 
The type for message formatting functions.

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:


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
unit is Logs.unit_msgf ().
type 'a log = ('a, Format.formatter, unit) Pervasives.format -> 'a msgf -> unit 
The type for log functions.

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
kmsg k is like Logs.msg but calls k for returning.

Logging result value Errors


val 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:
val on_error_msg : ?src:src ->
?level:level ->
?header:string ->
?tags:Tag.set ->
use:(unit -> 'a) -> ('a, [ `Msg of string ]) Result.result -> 'a
on_error_msg is like Logs.on_error but uses Format.pp_print_text to format the message.

Source specific log functions


module type LOG = sig .. end
The type for source specific logging functions.
val src_log : src -> (module Logs.LOG)
src_log src is a set of logging functions for src.

Reporters


type reporter = {
   report : 'a 'b.
src ->
level ->
(unit -> 'b) ->
('a, Format.formatter, unit, 'b) Pervasives.format4 ->
((?header:string -> ?tags:Tag.set -> 'a) -> 'b) -> 'b
;
}
The type for reporters.

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:


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.

Logs monitoring


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.

Basics

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.

Usage conventions

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: