|
| 1 | +[@@@ocaml.warning "-unused-var-strict"] |
| 2 | +[@@@ocaml.warning "-unused-field"] |
| 3 | + |
| 4 | +open Cmdliner |
| 5 | + |
| 6 | +(* https://erratique.ch/software/logs/doc/Logs_lwt/index.html#report_ex *) |
| 7 | +let lwt_reporter () = |
| 8 | + let buf_fmt ~like = |
| 9 | + let b = Buffer.create 512 in |
| 10 | + ( Fmt.with_buffer ~like b, |
| 11 | + fun () -> |
| 12 | + let m = Buffer.contents b in |
| 13 | + Buffer.reset b; |
| 14 | + m ) |
| 15 | + in |
| 16 | + let app, app_flush = buf_fmt ~like:Fmt.stdout in |
| 17 | + let dst, dst_flush = buf_fmt ~like:Fmt.stderr in |
| 18 | + let report (src : Logs.Src.t) level ~over k msgf = |
| 19 | + let k _ = |
| 20 | + let write () = |
| 21 | + match level with |
| 22 | + | Logs.App -> Lwt_io.write Lwt_io.stdout (app_flush ()) |
| 23 | + | _ -> Lwt_io.write Lwt_io.stderr (dst_flush ()) |
| 24 | + in |
| 25 | + let unblock () = |
| 26 | + over (); |
| 27 | + Lwt.return_unit |
| 28 | + in |
| 29 | + Lwt.finalize write unblock |> Lwt.ignore_result; |
| 30 | + k () (* this is 'k' from 'report' not 'k ()' *) |
| 31 | + in |
| 32 | + (* Adapted from https://erratique.ch/software/logs/doc/Logs/index.html#ex1 *) |
| 33 | + let with_source h k ppf fmt = |
| 34 | + Format.kfprintf k ppf |
| 35 | + ("%a [%s] @[" ^^ fmt ^^ "@]@.") |
| 36 | + Logs_fmt.pp_header (level, h) (Logs.Src.name src) |
| 37 | + in |
| 38 | + match level with |
| 39 | + | Logs.App -> msgf @@ fun ?header ?tags fmt -> with_source header k app fmt |
| 40 | + | _ -> msgf @@ fun ?header ?tags fmt -> with_source header k dst fmt |
| 41 | + in |
| 42 | + { Logs.report } |
| 43 | + |
| 44 | +(* Inspired by |
| 45 | + https://github.com/mjambon/cmdliner-cheatsheet/blob/main/src/Demo_arg_main.ml *) |
| 46 | + |
| 47 | +type conf = { |
| 48 | + name : string; |
| 49 | + log : unit; |
| 50 | +} |
| 51 | + |
| 52 | +let name_term = |
| 53 | + let default = "John Doe" in |
| 54 | + let info = |
| 55 | + Arg.info |
| 56 | + [ "N"; "name" ] (* '-N' and '--name' will be synonyms *) |
| 57 | + ~docv:"NAME" ~doc:"User to use when connecting" |
| 58 | + in |
| 59 | + Arg.value (Arg.opt Arg.string default info) |
| 60 | + |
| 61 | +let setup_log style_renderer level = |
| 62 | + Fmt_tty.setup_std_outputs ?style_renderer (); |
| 63 | + Logs.set_level level; |
| 64 | + Logs.set_reporter (lwt_reporter ()); |
| 65 | + () |
| 66 | + |
| 67 | +let setup_log_term = |
| 68 | + Term.(const setup_log $ Fmt_cli.style_renderer () $ Logs_cli.level ()) |
| 69 | + |
| 70 | +let conf_term run = |
| 71 | + let combine name log = |
| 72 | + let conf = { name; log } in |
| 73 | + run conf |
| 74 | + in |
| 75 | + Term.(const combine $ name_term $ setup_log_term) |
| 76 | + |
| 77 | +let parse_command_line_and_run run = |
| 78 | + let info = |
| 79 | + Cmd.info "lwt-reporter-example" |
| 80 | + (* program name as it will appear in --help *) |
| 81 | + in |
| 82 | + Cmd.v info (conf_term run) |> Cmd.eval |> Stdlib.exit |
| 83 | + |
| 84 | +let main conf = |
| 85 | + Logs.info (fun m -> m "My name is: %s" conf.name); |
| 86 | + Lwt_reporter_example.A_module.log_name conf.name |
| 87 | + |
| 88 | +let () = parse_command_line_and_run main |
0 commit comments