Created
March 13, 2012 20:05
-
-
Save hcarty/2031221 to your computer and use it in GitHub Desktop.
Simple OCaml logging, conceptually modeled after Log::Log4perl's easy mode
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open Batteries | |
module type Level_sig = sig | |
type t | |
val to_string : t -> string | |
val default_level : t | |
val compare : t -> t -> int | |
end | |
module type S = sig | |
type level_t | |
val set_logger : (level_t -> string -> unit) -> unit | |
val set_prefix : (level_t -> string) -> unit | |
val set_level : level_t -> unit | |
val set_flush : bool -> unit | |
(** [set_*] set the current functions and levels for the active logger *) | |
val get_logger : unit -> level_t -> string -> unit | |
val get_prefix : unit -> level_t -> string | |
val get_level : unit -> level_t | |
val get_flush : unit -> bool | |
(** [get_*] get the current functions and levels used by the active logger *) | |
(** [init l] (re)sets logging to use the default logging and prefix functions | |
and sets the logging level to [l]. The default prefix is the current | |
time stamp. The default logger outputs log entries on [stdout]. *) | |
val init : ?flush:bool -> 'a Batteries.IO.output -> level_t -> unit | |
(** [log l m] logs the message [m] using the current logging function if the | |
current log level is greater than or equal to [l]. *) | |
val log : level_t -> string -> unit | |
val logf : level_t -> ('a, 'b Batteries.IO.output, unit, unit) format4 -> 'a | |
end | |
module Make(L : Level_sig) = struct | |
type level_t = L.t | |
(** By default, the logger does nothing *) | |
let logger : (L.t -> string -> unit) ref = ref (const ignore) | |
(** By default, the prefix string is empty *) | |
let prefix : (L.t -> string) ref = ref (const "") | |
(** By default, the log level is the largest (most restrictive) *) | |
let level : L.t ref = ref L.default_level | |
(** By default, output is flushed after every log message *) | |
let flush = ref true | |
let default_prefix level = | |
let open Unix in | |
let now = gmtime (time ()) in | |
Printf.sprintf "%d-%02d-%02d %02d:%02d:%02d %s> " | |
(now.tm_year + 1900) (now.tm_mon + 1) now.tm_mday | |
now.tm_hour now.tm_min now.tm_sec | |
(L.to_string level) | |
let default_logger out level message = | |
IO.nwrite out (!prefix level); | |
IO.nwrite out message; | |
IO.nwrite out "\n"; | |
if !flush then IO.flush out | |
else () | |
(** Set a custom logger function *) | |
let set_logger f = | |
logger := f | |
(** Set a custom prefix function *) | |
let set_prefix f = | |
prefix := f | |
(** Set log level *) | |
let set_level l = | |
level := l | |
(** Set output flush flag *) | |
let set_flush b = | |
flush := b | |
(** Get current logger function *) | |
let get_logger () = !logger | |
(** Get current prefix function *) | |
let get_prefix () = !prefix | |
(** Get log level *) | |
let get_level () = !level | |
(** Get flush flag *) | |
let get_flush () = !flush | |
(** Initialize the logging system using the default logger and prefix | |
functions *) | |
let init ?flush out l = | |
Option.may set_flush flush; | |
set_logger (default_logger out); | |
set_prefix default_prefix; | |
set_level l | |
(** Main logging function *) | |
let log l m = | |
if L.compare l !level >= 0 then | |
!logger l m | |
else | |
() | |
(** Main logging function - printf-style *) | |
let logf l format = | |
if L.compare l !level >= 0 then | |
Printf.ksprintf2 (fun s -> !logger l s) format | |
else | |
Printf.ifprintf () format | |
end | |
module Basic = struct | |
type t = [ | |
| `trace | |
| `debug | |
| `info | |
| `warn | |
| `error | |
| `fatal | |
| `always | |
] | |
let to_string : (t -> string) = function | |
| `trace -> "TRACE" | |
| `debug -> "DEBUG" | |
| `info -> "INFO" | |
| `warn -> "WARN" | |
| `error -> "ERROR" | |
| `fatal -> "FATAL" | |
| `always -> "ALWAYS" | |
let to_int : (t -> int) = function | |
| `trace -> 0 | |
| `debug -> 1 | |
| `info -> 2 | |
| `warn -> 3 | |
| `error -> 4 | |
| `fatal -> 5 | |
| `always -> 6 | |
let default_level = `always | |
let compare a b = | |
Int.compare (to_int a) (to_int b) | |
end | |
module Easy = Make(Basic) | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(** {2 Logging} *) | |
(** Signature required to implement a logging module *) | |
module type Level_sig = sig | |
type t | |
(** Possible debug levels *) | |
(** [to_string l] returns a string describing or naming the log level [l] *) | |
val to_string : t -> string | |
(** The default log level *) | |
val default_level : t | |
(** [compare a b] should be [0] if [a] and [b] are equal, [< 0] if [a] is | |
less restrictive than [b], and [> 0] if [a] is more restrictive than | |
[b] *) | |
val compare : t -> t -> int | |
end | |
(** Signature of a logging module *) | |
module type S = sig | |
type level_t | |
val set_logger : (level_t -> string -> unit) -> unit | |
val set_prefix : (level_t -> string) -> unit | |
val set_level : level_t -> unit | |
val set_flush : bool -> unit | |
(** [set_*] set the current functions and levels for the active logger *) | |
val get_logger : unit -> level_t -> string -> unit | |
val get_prefix : unit -> level_t -> string | |
val get_level : unit -> level_t | |
val get_flush : unit -> bool | |
(** [get_*] get the current functions and levels used by the active logger *) | |
(** [init l] (re)sets logging to use the default logging and prefix functions | |
and sets the logging level to [l]. The default prefix is the current | |
date/time stamp. The default logger outputs log entries on [stdout]. *) | |
val init : ?flush:bool -> 'a Batteries.IO.output -> level_t -> unit | |
(** [log l m] logs the message [m] using the current logging function if the | |
current log level is greater than or equal to [l]. *) | |
val log : level_t -> string -> unit | |
(** [logf l format] logs the message [m] using the current logging function | |
if the current log level is greater than or equal to [l]. *) | |
val logf : level_t -> ('a, 'b Batteries.IO.output, unit, unit) format4 -> 'a | |
end | |
(** A functor to create a logging module using the log levels defined in [L] *) | |
module Make : functor (L : Level_sig) -> S with type level_t = L.t | |
(** A basic logging level structure *) | |
module Basic : sig | |
type t = [ | |
| `trace | |
| `debug | |
| `info | |
| `warn | |
| `error | |
| `fatal | |
| `always | |
] | |
val to_string : t -> string | |
val default_level : t | |
val compare : t -> t -> int | |
end | |
(** Logging module using the {!Basic} log levels *) | |
module Easy : S with type level_t = Basic.t | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open Batteries | |
module E = Log.Easy | |
let () = | |
let oc = IO.output_string () in | |
E.init oc `error; | |
E.set_prefix (fun _ -> "PREFIX: "); | |
E.log `error "test"; | |
assert (IO.close_out oc = "PREFIX: test\n"); | |
print_endline "ok" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment