Source file logger_impl.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
module type S = sig
module IO : Types.IO
type addr
type handler = addr Handler.Make(IO).t
type clock
val set_level : Logs.level -> unit
val logger : clock -> handler -> handler
val debug : 'a Logs.log
val info : 'a Logs.log
val warning : 'a Logs.log
val error : 'a Logs.log
end
module Make
(Clock : Types.PCLOCK) (IO : sig
include Types.IO
val finally : (unit -> 'a t) -> ('a -> 'b t) -> (exn -> 'b t) -> 'b t
end)
(Addr : Types.ADDR) :
S with module IO = IO and type addr = Addr.t and type clock = Clock.t = struct
module IO = IO
type addr = Addr.t
type handler = addr Handler.Make(IO).t
type clock = Clock.t
let src = Logs.Src.create "mehari.log"
module Log = (val Logs.src_log src)
let debug = Log.debug
let info = Log.info
let warning = Log.warn
let error = Log.err
let set_level lvl = Logs.Src.set_level src (Some lvl)
let iter_backtrace f backtrace =
String.split_on_char '\n' backtrace
|> List.iter (function "" -> () | l -> f l)
let now clock = Clock.now_d_ps clock |> Ptime.v |> Ptime.to_float_s
let logger clock handler req =
let start = now clock in
IO.finally
(fun () -> handler req)
(fun resp ->
Log.info (fun log ->
log "Serve '%s' %a"
(Request.uri req |> Uri.path_and_query)
Addr.pp (Request.ip req));
(match resp.Response.status with
| None -> ()
| Some code ->
let elapsed = now clock -. start in
Log.info (fun log -> log "%i in %f µs" code (elapsed *. 1e6)));
IO.return resp)
(fun exn ->
let backtrace = Printexc.get_backtrace () in
Log.warn (fun log -> log "Aborted by: %s" (Printexc.to_string exn));
iter_backtrace
(fun line -> Log.warn (fun log -> log "%s" line))
backtrace;
raise exn)
end