A few recipes and starting blueprints for using More.
Note. Some of the code snippets here assume they are done after:
open MoreYou can use the spawn tracing facility. At initialization time a tracer that logs spawns on level Debug is installed. So setting your level to Debug will trace the process spawns on stderr.
If you want them to be traced at another level use More.Os.Cmd.spawn_tracer_log. For example this traces process spawns at the More.Log.level.Stderr level:
let main () =
Os.Cmd.set_spawn_tracer (Os.Cmd.spawn_tracer_log Stderr);
…ANSI text styling is controlled globally on all formatters by the More.Fmt.set_styler function. The initial value depends on a bunch of conditions which are documented here. Text styling can be selectively stripped on strings and formatters with the More.String.strip_ansi_escapes and More.Fmt.strip_styles functions.
If you are using Cmdliner the recommended way to let users control ANSI text styling is to use the More_cli.set_no_color term which sets the styler by side side effect. The term allows to set the styler to Plain with the --no-color command line flag or the NO_COLOR environment variable (which also happens at initialization time). See More_cli.no_color for more information and this blueprint for an example.
We advise against changing the styler according to Unix.isatty. Think about your outputs as being styled text rather than plain text. Users often pipe styled text and and expect it to survive. For example when they page your outputs or redirect messages to a log file. This doesn't mean that you should not support a --no-color option; only that Unix.isatty should not be used as signifier for plain text.
Use More.Fmt.cardinal.
let example : int Fmt.t = Fmt.cardinal ~one:(Fmt.any "example") ()
let woman_count : int Fmt.t =
let zero = Fmt.any "no woman" in
let one = Fmt.any "one woman" in
let other ppf c = Fmt.pf ppf "%d women" c in
Fmt.cardinal ~zero ~one ~other ()The log level is controlled by the More.Log.set_level function. The initial value is More.Log.level.Warning.
If you are using Cmdliner the recommended way to let users control the log level is to use the More_cli.set_log_level term which sets the log level by side effect. The term allows to set the log level with the --log-level command line option and a few other flags or the LOG_LEVEL environment variable. See More_cli.log_level for more information and this blueprint for an example.
Simply wrap the body of your main function by a call to More.Log.time. The call respects the reporting level even if changed in the wrapped function itself. See this this blueprint for an example.
It depends.
The More.Log module has two specific levels before Quiet that allow to directly output to stdout and stderr by using More.Log.stdout and More.Log.stderr.
Using these functions is useful to flush newline ended messages on standard outputs without them being prefixed by the executable name or a log level header and retain the ability to suppress these messages when the reporting level is set to More.Log.level.Quiet.
Now if you are writing data on your standard output, you should likely not use More.Log.stdout. This will prevent it from being output when More.Log.level.Quiet is set which the user may request to silence other diagnostics message.
This blueprint setups ANSI text styling and the log level by side effect. It also reports the total time taken by the tool when the log level is set to Info.
open More
let tool () =
Log.stdout (fun m -> m "Invoke with %a to silence me" Fmt.code "--quiet");
Cmdliner.Cmd.Exit.ok
open Cmdliner
open Cmdliner.Term.Syntax
let tool_cmd =
Cmd.make (Cmd.info "TODO" ~version:"%%VERSION%%") @@
let+ () = More_cli.set_no_color () in
let+ () = More_cli.set_log_level () in
tool ()
let main () =
Log.time (fun _ m -> m "total time %%VERSION%%") @@ fun () ->
Cmd.eval' tool_cmd
let () = if !Sys.interactive then () else exit (main ())