I needed to write a custom reporter that will output my logs in a file like Lwt_log.file
.
Here is what I have so far:
open Lwt.Infix
open Logs
let lwt_file_reporter () =
let open Logs in
let buf_fmt ~like =
let b = Buffer.create 512 in
Fmt.with_buffer ~like b,
fun () -> let m = Buffer.contents b in Buffer.reset b; m
in
let app, app_flush = buf_fmt ~like:Fmt.stdout in
let dst, dst_flush = buf_fmt ~like:Fmt.stderr in
let reporter = Logs_fmt.reporter ~app ~dst () in
let report src level ~over k msgf =
let k () =
let write () =
Lwt_io.open_file ~flags:[Unix.O_WRONLY; Unix.O_CREAT; Unix.O_APPEND] ~perm:0o777 ~mode:Lwt_io.Output "my_file.log"
>>= fun fd -> (
match level with
| Logs.App -> Lwt_io.write fd (app_flush ())
| _ -> Lwt_io.write fd (dst_flush ())
)
>>= fun () ->
Lwt_io.close fd
in
let unblock () = over (); Lwt.return_unit in
Lwt.finalize write unblock |> Lwt.ignore_result;
k ()
in
reporter.Logs.report src level ~over:(fun () -> ()) k msgf;
in
{ Logs.report = report }
let setup () =
Logs.set_reporter (lwt_file_reporter ());
Logs.set_level (Some Debug);
Lwt.return_unit
let log message i =
Logs.app (fun m -> m "thread %d %s" i message);
Lwt.return_unit
let threads = [
setup ();
(Lwt_unix.sleep 1.0
>>= fun () ->
log "hop a" 1
>>= fun () ->
Lwt_unix.sleep 2.0
>>= fun () ->
log "hop b" 1
);
(Lwt_unix.sleep 2.0
>>= fun () ->
log "pop a" 2
>>= fun () ->
Lwt_unix.sleep 3.0
>>= fun () ->
log "pop b" 2
);
]
let () =
Lwt_main.run(Lwt.join threads)
when I compile and run with
~> ocamlfind ocamlc -o custom_lwt_file_reporter -package fmt,logs,lwt,lwt.unix,logs.fmt -linkpkg -g custom_lwt_file_reporter.ml
~> ./custom_lwt_file_reporter
I have the following output:
~> cat my_file.log
thread 1 hop a
thread 2 pop a
thread 1 hop b
It seems that the last log is not printed. I am not sure where lies the problem, is it my reporter or the way I use the threads.