···11+22+33+* Make log mutex immune to raising logging functions.
44+ Thanks to Nathan Taylor for the report and the repro (#57).
55+66+v0.9.0 2025-07-08 Zagreb
77+------------------------
88+99+* Replace references and mutable fields by atomic references to avoid
1010+ race conditions (#56). Thanks to Nathan Taylor for reporting.
1111+* Fix `Logs.{err,warn}_count`. The counts were counting the reports
1212+ not the logs which is not what the spec says. This means the counts
1313+ were wrong when the reporting level was below the corresponding
1414+ level (#55). Thanks to Mathieu Barbin for the report.
1515+* Fix `Log.Tag.list` always returning the empty list.
1616+* `Logs.format_reporter` and `Logs_fmt.reporter` replace a few format
1717+ strings and `^^` uses by direct calls to `Format` primitives.
1818+* Requires OCaml >= 4.14.
1919+* Use Format.pp_print_text instead of our own.
2020+* Export `logs` from each sub library.
2121+2222+v0.8.0 2025-03-10 La Forclaz (VS)
2323+---------------------------------
2424+2525+* Install one library per directory (#48). Thanks to @mefyl
2626+ for the suggestion.
2727+* Requires OCaml >= 4.08, Cmdliner >= 1.3.0, Fmt >= 0.9.0
2828+ and js_of_ocaml-compiler >= 5.5.0
2929+* Depend on the `js_of_ocaml-compiler.runtime` library rather than
3030+ `js_of_ocaml`.
3131+* Handle `cmdliner` deprecations.
3232+3333+v0.7.0 2019-08-09 Zagreb
3434+------------------------
3535+3636+Support for thread safe logging, thanks to Jules Aguillon for the
3737+work.
3838+3939+* Add `Logs.set_reporter_mutex` for installing mutual exclusion
4040+ primitives to access the reporter.
4141+* Add `Logs_threaded.enable` to install mutual exclusion
4242+ primitives for OCaml threads.
4343+4444+v0.6.3 2019-04-19 La Forclaz (VS)
4545+---------------------------------
4646+4747+* Make the package compatible with `js_of_ocaml` 3.3.0's
4848+ namespacing. Thanks to Hugo Heuzard for the patch.
4949+* Fix toplevel initialisation for `Omod` (#21).
5050+* Fix 4.08 `Pervasives` deprecation.
5151+* Drop support for ocaml < 4.03.0
5252+* Doc: various improvements and typo fixing.
5353+5454+v0.6.2 2016-08-10 Zagreb
5555+------------------------
5656+5757+* 4.04.0 compatibility. Thanks to Damien Doligez for the patch.
5858+5959+6060+v0.6.1 2016-06-08 Cambridge (UK)
6161+--------------------------------
6262+6363+* Fix logs.top package on case sensitive file systems.
6464+6565+v0.6.0 2016-05-23 La Forclaz (VS)
6666+---------------------------------
6767+6868+* Build depend on topkg.
6969+* Relicensed from BSD3 to ISC.
7070+* Revise the command line interface provided by `Logs_cli`. Removes
7171+ the argument from option `-v`. See issue #13 for details.
7272+* Add `Logs.format_reporter` a reporter like `Logs_fmt.reporter`
7373+ but without colors and hence without the dependency on `Fmt`.
7474+ Thanks to Simon Cruanes for the suggestion.
7575+* `Logs_fmt.reporter`, the optional argument `prefix` is changed to
7676+ `pp_header` and becomes a formatter. The default prefix now favors
7777+ the basename of `Sys.argv.(0)` if it exists over
7878+ `Sys.executable_name`; this gives better results for interpreted
7979+ programs.
8080+* Fix colors in `Logs_fmt.pp_header`, only `Logs.err_style` was
8181+ being used.
8282+* Add `Logs.level_{of,to}_string`.
8383+8484+8585+v0.5.0 2016-01-07 La Forclaz (VS)
8686+---------------------------------
8787+8888+* Support for OCaml 4.01.0
8989+* Change the logging structure from `Logs.err fmt (fun m -> m ...)`
9090+ to `Logs.err (fun m -> m fmt ...)`. See the documentation basics
9191+ for more details. Thanks to Edwin Török for suggesting this.
9292+* Remove the `Logs.unit[_msgf]` functions, they are no longer needed.
9393+* Rename the `Logs_stdo` library to `Logs_fmt`.
9494+* Changes the signature of reporters to take a callback function to
9595+ call unconditionally once the report is over. Thanks to Edwin Török
9696+ for suggesting the mecanism.
9797+* Add the optional `Logs_lwt` library. Provides logging functions
9898+ returning `lwt` threads that proceed only once the report is over.
9999+* Add `Logs_fmt.pp_header` and `Logs_fmt.{err_warn,info_debug}_style`.
100100+* Add `Logs.pp_{level,header}`.
101101+102102+103103+v0.4.2 2015-12-03 Cambridge (UK)
104104+--------------------------------
105105+106106+First release.
+6
vendor/opam/logs/DEVEL.md
···11+This project uses (perhaps the development version of) [`b0`] for
22+development. Consult [b0 occasionally] for quick hints on how to
33+perform common development tasks.
44+55+[`b0`]: https://erratique.ch/software/b0
66+[b0 occasionally]: https://erratique.ch/software/b0/doc/occasionally.html
+13
vendor/opam/logs/LICENSE.md
···11+Copyright (c) 2016 The logs programmers
22+33+Permission to use, copy, modify, and/or distribute this software for any
44+purpose with or without fee is hereby granted, provided that the above
55+copyright notice and this permission notice appear in all copies.
66+77+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
88+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
99+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1010+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1111+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1212+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1313+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+51
vendor/opam/logs/README.md
···11+Logs — Logging infrastructure for OCaml
22+=======================================
33+44+Logs provides a logging infrastructure for OCaml. Logging is performed
55+on sources whose reporting level can be set independently. Log message
66+report is decoupled from logging and is handled by a reporter.
77+88+A few optional log reporters are distributed with the base library and
99+the API easily allows to implement your own.
1010+1111+`Logs` has no dependencies. The optional `Logs_fmt` reporter on OCaml
1212+formatters depends on [Fmt][fmt]. The optional `Logs_browser`
1313+reporter that reports to the web browser console depends on
1414+[js_of_ocaml][jsoo]. The optional `Logs_cli` library that provides
1515+command line support for controlling Logs depends on
1616+[`Cmdliner`][cmdliner]. The optional `Logs_lwt` library that provides
1717+Lwt logging functions depends on [`Lwt`][lwt]
1818+1919+Logs and its reporters are distributed under the ISC license.
2020+2121+[fmt]: http://erratique.ch/software/fmt
2222+[jsoo]: http://ocsigen.org/js_of_ocaml/
2323+[cmdliner]: http://erratique.ch/software/cmdliner
2424+[lwt]: http://ocsigen.org/lwt/
2525+2626+Home page: <http://erratique.ch/software/logs>
2727+2828+## Installation
2929+3030+Logs can be installed with `opam`:
3131+3232+ opam install logs
3333+ opam install fmt cmdliner lwt js_of_ocaml logs # Install all opt libraries
3434+3535+If you don't use `opam` consult the [`opam`](opam) file for build
3636+instructions.
3737+3838+## Documentation
3939+4040+The documentation can be consulted [online][doc] or via `odig doc logs`.
4141+4242+Questions are welcome but better asked on the [OCaml forum][ocaml-forum]
4343+than on the issue tracker.
4444+4545+[doc]: https://erratique.ch/software/logs/doc
4646+[ocaml-forum]: https://discuss.ocaml.org/
4747+4848+## Sample programs
4949+5050+A few tests can be found in the [`test`](test/) directory.
5151+
···11+{0 Logs {%html: <span class="version">%%VERSION%%</span>%}}
22+33+Logs provides a logging infrastructure.
44+55+Logging is performed on sources whose reporting level can be set
66+independently. Log message report is decoupled from logging and is
77+handled by a reporter. A few optional log reporters are distributed
88+with the package and the API easily allows to implement your own.
99+1010+See the {{!Logs.basics}basics}.
1111+1212+{1:library_logs Library [logs]}
1313+1414+{!modules: Logs}
1515+1616+{1:libraries Libraries [logs.{browser,cli,fmt,lwt,threaded}]}
1717+1818+Each of these modules lives in its own library.
1919+2020+{!modules:
2121+Logs_browser
2222+Logs_cli
2323+Logs_fmt
2424+Logs_lwt
2525+Logs_threaded
2626+}
+49
vendor/opam/logs/dune-project
···11+(lang dune 3.0)
22+(name logs)
33+44+(generate_opam_files false)
55+66+(source (github dbuenzli/logs))
77+(license ISC)
88+(authors "The logs programmers")
99+(maintainers "Daniel Bünzli <daniel.buenzl i@erratique.ch>")
1010+1111+(package
1212+ (name logs)
1313+ (synopsis "Logging infrastructure for OCaml")
1414+ (description "Logs provides a logging infrastructure for OCaml. Logging is performed
1515+on sources whose reporting level can be set independently. Log message
1616+report is decoupled from logging and is handled by a reporter.
1717+1818+A few optional log reporters are distributed with the base library and
1919+the API easily allows to implement your own.
2020+2121+`Logs` has no dependencies. The optional `Logs_fmt` reporter on OCaml
2222+formatters depends on [Fmt][fmt]. The optional `Logs_browser`
2323+reporter that reports to the web browser console depends on
2424+[js_of_ocaml][jsoo]. The optional `Logs_cli` library that provides
2525+command line support for controlling Logs depends on
2626+[`Cmdliner`][cmdliner]. The optional `Logs_lwt` library that provides
2727+Lwt logging functions depends on [`Lwt`][lwt]
2828+2929+Logs and its reporters are distributed under the ISC license.
3030+3131+[fmt]: http://erratique.ch/software/fmt
3232+[jsoo]: http://ocsigen.org/js_of_ocaml/
3333+[cmdliner]: http://erratique.ch/software/cmdliner
3434+[lwt]: http://ocsigen.org/lwt/
3535+3636+Home page: <http://erratique.ch/software/logs>")
3737+ (depends
3838+ (ocaml (>= 4.14.0)))
3939+ (depopts
4040+ cmdliner
4141+ js_of_ocaml-compiler
4242+ fmt
4343+ lwt
4444+ base-threads)
4545+ (conflicts
4646+ (cmdliner (< 1.3.0))
4747+ (js_of_ocaml-compiler (< 5.5.0))
4848+ (fmt (< 0.9.0)))
4949+ (tags (log system "org:erratique")))
+51
vendor/opam/logs/opam
···11+opam-version: "2.0"
22+name: "logs"
33+synopsis: "Logging infrastructure for OCaml"
44+description: """\
55+Logs provides a logging infrastructure for OCaml. Logging is performed
66+on sources whose reporting level can be set independently. Log message
77+report is decoupled from logging and is handled by a reporter.
88+99+A few optional log reporters are distributed with the base library and
1010+the API easily allows to implement your own.
1111+1212+`Logs` has no dependencies. The optional `Logs_fmt` reporter on OCaml
1313+formatters depends on [Fmt][fmt]. The optional `Logs_browser`
1414+reporter that reports to the web browser console depends on
1515+[js_of_ocaml][jsoo]. The optional `Logs_cli` library that provides
1616+command line support for controlling Logs depends on
1717+[`Cmdliner`][cmdliner]. The optional `Logs_lwt` library that provides
1818+Lwt logging functions depends on [`Lwt`][lwt]
1919+2020+Logs and its reporters are distributed under the ISC license.
2121+2222+[fmt]: http://erratique.ch/software/fmt
2323+[jsoo]: http://ocsigen.org/js_of_ocaml/
2424+[cmdliner]: http://erratique.ch/software/cmdliner
2525+[lwt]: http://ocsigen.org/lwt/
2626+2727+Home page: <http://erratique.ch/software/logs>"""
2828+maintainer: "Daniel Bünzli <daniel.buenzl i@erratique.ch>"
2929+authors: "The logs programmers"
3030+license: "ISC"
3131+tags: ["log" "system" "org:erratique"]
3232+homepage: "https://erratique.ch/software/logs"
3333+doc: "https://erratique.ch/software/logs/doc"
3434+bug-reports: "https://github.com/dbuenzli/logs/issues"
3535+depends: [
3636+ "ocaml" {>= "4.14.0"}
3737+ "dune" {>= "3.0"}
3838+ "mtime" {with-test}
3939+]
4040+depopts: ["cmdliner" "js_of_ocaml-compiler" "fmt" "lwt" "base-threads"]
4141+conflicts: [
4242+ "cmdliner" {< "1.3.0"}
4343+ "js_of_ocaml-compiler" {< "5.5.0"}
4444+ "fmt" {< "0.9.0"}
4545+]
4646+build: [
4747+ ["dune" "subst"] {dev}
4848+ ["dune" "build" "-p" name "-j" jobs]
4949+]
5050+dev-repo: "git+https://erratique.ch/repos/logs.git"
5151+x-maintenance-intent: ["(latest)"]
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(* Console reporter *)
77+88+open Jsoo_runtime
99+1010+let console_obj = Js.pure_js_expr "console"
1111+let console : Logs.level -> string -> unit =
1212+fun level s ->
1313+ let meth = match level with
1414+ | Logs.Error -> "error"
1515+ | Logs.Warning -> "warn"
1616+ | Logs.Info -> "info"
1717+ | Logs.Debug -> "debug"
1818+ | Logs.App -> "log"
1919+ in
2020+ ignore (Js.meth_call console_obj meth [| Js.string s |])
2121+2222+let ppf, flush =
2323+ let b = Buffer.create 255 in
2424+ let flush () = let s = Buffer.contents b in Buffer.clear b; s in
2525+ Format.formatter_of_buffer b, flush
2626+2727+let console_report src level ~over k msgf =
2828+ let k _ = console level (flush ()); over (); k () in
2929+ msgf @@ fun ?header ?tags fmt ->
3030+ match header with
3131+ | None -> Format.kfprintf k ppf ("@[" ^^ fmt ^^ "@]@.")
3232+ | Some h -> Format.kfprintf k ppf ("[%s] @[" ^^ fmt ^^ "@]@.") h
3333+3434+let console_reporter () = { Logs.report = console_report }
+19
vendor/opam/logs/src/browser/logs_browser.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Web browser reporters for {!Logs}. *)
77+88+(** {1 Reporters} *)
99+1010+val console_reporter : unit -> Logs.reporter
1111+(** [console_reporter ()] logs message using the
1212+ {{:https://github.com/DeveloperToolsWG/console-object/blob/master/api.md}
1313+ browser console object} at the corresponding level and uses
1414+ [console.log] for the [App] level.
1515+1616+ The reporter does not process or render information about
1717+ message sources or tags.
1818+1919+ Consult the {{:http://caniuse.com/#search=console}browser support}. *)
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+open Cmdliner
77+88+let strf = Format.asprintf
99+1010+let level ?env ?docs () =
1111+ let vopts =
1212+ let doc = "Increase verbosity. Repeatable, but more than twice does
1313+ not bring more."
1414+ in
1515+ Arg.(value & flag_all & info ["v"; "verbose"] ~doc ?docs)
1616+ in
1717+ let verbosity =
1818+ let enum =
1919+ [ "warning", None; (* Hack for the option's absent rendering *)
2020+ "quiet", Some None;
2121+ "error", Some (Some Logs.Error);
2222+ "warning", Some (Some Logs.Warning);
2323+ "info", Some (Some Logs.Info);
2424+ "debug", Some (Some Logs.Debug); ]
2525+ in
2626+ let log_level = Arg.enum enum in
2727+ let enum_alts = Arg.doc_alts_enum List.(tl enum) in
2828+ let doc = strf "Be more or less verbose. $(docv) must be %s. Takes over
2929+ $(b,-v)." enum_alts
3030+ in
3131+ Arg.(value & opt log_level None &
3232+ info ["verbosity"] ?env ~docv:"LEVEL" ~doc ?docs)
3333+ in
3434+ let quiet =
3535+ let doc = "Be quiet. Takes over $(b,-v) and $(b,--verbosity)." in
3636+ Arg.(value & flag & info ["q"; "quiet"] ~doc ?docs)
3737+ in
3838+ let choose quiet verbosity vopts =
3939+ if quiet then None else match verbosity with
4040+ | Some verbosity -> verbosity
4141+ | None ->
4242+ match List.length vopts with
4343+ | 0 -> Some Logs.Warning
4444+ | 1 -> Some Logs.Info
4545+ | n -> Some Logs.Debug
4646+ in
4747+ Term.(const choose $ quiet $ verbosity $ vopts)
+76
vendor/opam/logs/src/cli/logs_cli.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** {!Cmdliner} support for {!Logs}.
77+88+ See a full {{!ex}example}. *)
99+1010+(** {1 Options for setting the report level} *)
1111+1212+val level : ?env:Cmdliner.Cmd.Env.info -> ?docs:string -> unit ->
1313+ Logs.level option Cmdliner.Term.t
1414+(** [level ?env ?docs ()] is a term for three {!Cmdliner} options that
1515+ can be used with {!Logs.set_level}. The options are documented
1616+ under [docs] (defaults to the default of {!Cmdliner.Arg.info}).
1717+1818+ The options work as follows:
1919+ {ul
2020+ {- [-v] or [--verbose], if it appears once, the value of
2121+ the term is [Some Logs.Info] and more than once
2222+ [Some Logs.Debug].}
2323+ {- [--verbosity=LEVEL], the value of the term is [l] where
2424+ [l] depends on on [LEVEL]. Takes over the option [-v].}
2525+ {- [-q] or [--quiet], the value of the term is [None]. Takes
2626+ over the [-v] and [--verbosity] options.}
2727+ {- If both options are absent the default value is
2828+ [Some Logs.warning]}}
2929+3030+ If [env] is provided, the default value in case all options are
3131+ absent can be overridden by the corresponding environment
3232+ variable. *)
3333+3434+(** {1:ex Example}
3535+3636+ The following example shows how to setup {!Logs} and {!Fmt} so
3737+ that logging is performed on standard outputs with ANSI coloring
3838+ if these are [tty]s. The command line interface provides options
3939+ to control the use of colors and the log reporting level.
4040+{[
4141+let hello _ msg =
4242+ Logs.app (fun m -> m "%s" msg);
4343+ Logs.info (fun m -> m "End-user information.");
4444+ Logs.debug (fun m -> m "Developer information.");
4545+ Logs.err (fun m -> m "Something bad happened.");
4646+ Logs.warn (fun m -> m "Something bad may happen in the future.");
4747+ if Logs.err_count () > 0 then 1 else 0
4848+4949+let setup_log ~style_renderer ~level =
5050+ Fmt_tty.setup_std_outputs ?style_renderer ();
5151+ Logs.set_level level;
5252+ Logs.set_reporter (Logs_fmt.reporter ())
5353+5454+(* Command line interface *)
5555+5656+open Cmdliner
5757+open Cmdliner.Term.Syntax
5858+5959+let cmd =
6060+ Cmd.make (Cmd.info "tool") @@
6161+ let env = Cmd.Env.info "TOOL_VERBOSITY" in
6262+ let+ style_renderer = Fmt_cli.style_renderer ()
6363+ and+ level = Logs_cli.level ~env ()
6464+ and+ msg =
6565+ let doc = "The message to output." in
6666+ Arg.(value & pos 0 string "Hello horrible world!" & info [] ~doc)
6767+ in
6868+ setup_log ~style_renderer ~level;
6969+ hello msg
7070+7171+7272+let main () = Cmd.eval' cmd
7373+let () = if !Sys.interactive then () else exit (main ())
7474+]}
7575+7676+*)
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+let app_style = `Cyan
77+let err_style = `Red
88+let warn_style = `Yellow
99+let info_style = `Blue
1010+let debug_style = `Green
1111+1212+let pp_brackets pp_v ppf v = Fmt.char ppf '['; pp_v ppf v; Fmt.char ppf ']'
1313+1414+let pp_header ~pp_h ppf (l, h) = match l with
1515+| Logs.App ->
1616+ begin match h with
1717+ | None -> ()
1818+ | Some h ->
1919+ pp_brackets Fmt.(styled app_style string) ppf h; Fmt.char ppf ' '
2020+ end
2121+| Logs.Error ->
2222+ pp_h ppf err_style (match h with None -> "ERROR" | Some h -> h)
2323+| Logs.Warning ->
2424+ pp_h ppf warn_style (match h with None -> "WARNING" | Some h -> h)
2525+| Logs.Info ->
2626+ pp_h ppf info_style (match h with None -> "INFO" | Some h -> h)
2727+| Logs.Debug ->
2828+ pp_h ppf debug_style (match h with None -> "DEBUG" | Some h -> h)
2929+3030+let pp_exec_header =
3131+ let exec = match Array.length Sys.argv with
3232+ | 0 -> Filename.basename Sys.executable_name
3333+ | n -> Filename.basename Sys.argv.(0)
3434+ in
3535+ let pp_h ppf style h =
3636+ Fmt.string ppf exec;
3737+ Fmt.string ppf ": ";
3838+ pp_brackets Fmt.(styled style string) ppf h;
3939+ Fmt.char ppf ' ';
4040+ in
4141+ pp_header ~pp_h
4242+4343+let reporter ?(pp_header = pp_exec_header) ?app ?dst () =
4444+ Logs.format_reporter ~pp_header ?app ?dst ()
4545+4646+let pp_header =
4747+ let pp_h ppf style h = pp_brackets Fmt.(styled style string) ppf h in
4848+ pp_header ~pp_h
+40
vendor/opam/logs/src/fmt/logs_fmt.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** {!Format} colorful reporter for {!Logs}. *)
77+88+(** {1 Reporter} *)
99+1010+val reporter :
1111+ ?pp_header:(Logs.level * string option) Fmt.t ->
1212+ ?app:Format.formatter ->
1313+ ?dst:Format.formatter -> unit -> Logs.reporter
1414+(** [reporter] is like {!Logs.format_reporter} except ANSI colors may be
1515+ used in message header rendering if the formatters are configured to do so;
1616+ see {!Fmt.set_style_renderer} and {!Fmt_tty}.
1717+1818+ Consult a full command line {{!Logs_cli.ex}setup example}. *)
1919+2020+(** {1:cheader Colored message headers} *)
2121+2222+val app_style : Fmt.style
2323+(** [app_style] is the style used to render headers at app level. *)
2424+2525+val err_style : Fmt.style
2626+(** [err_style] is the style used to render headers at error level. *)
2727+2828+val warn_style : Fmt.style
2929+(** [warn_style] is the style used to render headers at warning level. *)
3030+3131+val info_style : Fmt.style
3232+(** [info_style] is the style used to render headers at info level. *)
3333+3434+val debug_style : Fmt.style
3535+(** [debug_style] is the style used to render headers at debug level. *)
3636+3737+val pp_header : (Logs.level * string option) Fmt.t
3838+(** [pp_header] is like {!Logs.pp_header} but may use ANSI colors if the
3939+ formatter is configured to do so, see {!Fmt.set_style_renderer} and
4040+ {!Fmt_tty}. *)
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+let () =
77+ Logs.set_reporter (Logs_fmt.reporter ());
88+ ()
+328
vendor/opam/logs/src/logs.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+let rec atomic_list_cons v atomic =
77+ let l = Atomic.get atomic in
88+ if Atomic.compare_and_set atomic l (v :: l) then () else
99+ atomic_list_cons v atomic
1010+1111+(* Reporting levels *)
1212+1313+type level = App | Error | Warning | Info | Debug
1414+let level' = Atomic.make (Some Warning)
1515+let level () = Atomic.get level'
1616+let pp_level ppf = function
1717+| App -> ()
1818+| Error -> Format.pp_print_string ppf "ERROR"
1919+| Warning -> Format.pp_print_string ppf "WARNING"
2020+| Info -> Format.pp_print_string ppf "INFO"
2121+| Debug -> Format.pp_print_string ppf "DEBUG"
2222+2323+let level_to_string = function
2424+| None -> "quiet" | Some App -> "app" | Some Error -> "error"
2525+| Some Warning -> "warning" | Some Info -> "info" | Some Debug -> "debug"
2626+2727+let level_of_string = function
2828+| "quiet" -> Ok None
2929+| "app" -> Ok (Some App)
3030+| "error" -> Ok (Some Error)
3131+| "warning" -> Ok (Some Warning)
3232+| "info" -> Ok (Some Info)
3333+| "debug" -> Ok (Some Debug)
3434+| l -> Error (`Msg (Printf.sprintf "%S: unknown log level" l))
3535+3636+(* Sources *)
3737+3838+module Src = struct
3939+ type t =
4040+ { uid : int;
4141+ name : string;
4242+ doc : string;
4343+ level : level option Atomic.t }
4444+4545+ let uid =
4646+ let id = Atomic.make 0 in
4747+ fun () -> Atomic.fetch_and_add id 1
4848+4949+ let list = Atomic.make []
5050+5151+ let create ?(doc = "undocumented") name =
5252+ let level = Atomic.make (Atomic.get level') in
5353+ let src = { uid = uid (); name; doc; level } in
5454+ atomic_list_cons src list; src
5555+5656+ let name s = s.name
5757+ let doc s = s.doc
5858+ let level s = Atomic.get (s.level)
5959+ let set_level s l = Atomic.set s.level l
6060+ let equal src0 src1 = src0.uid = src1.uid
6161+ let compare src0 src1 = (compare : int -> int -> int) src0.uid src1.uid
6262+6363+ let pp ppf src = Format.fprintf ppf
6464+ "@[<1>(src@ @[<1>(name %S)@]@ @[<1>(uid %d)@] @[<1>(doc %S)@])@]"
6565+ src.name src.uid src.doc
6666+6767+ let list () = Atomic.get list
6868+end
6969+7070+type src = Src.t
7171+7272+let default = Src.create "application" ~doc:"The application log"
7373+7474+let set_level ?(all = true) l =
7575+ Atomic.set level' l;
7676+ if all then List.iter (fun s -> Src.set_level s l) (Src.list ())
7777+7878+(* Message tags *)
7979+8080+module Tag = struct
8181+8282+ (* Universal type, see http://mlton.org/UniversalType.
8383+ Note: we can get rid of that once we have OCaml >= 5.1 *)
8484+8585+ type univ = exn
8686+ let univ (type s) () =
8787+ let module M = struct exception E of s option end in
8888+ (fun x -> M.E (Some x)), (function M.E x -> x | _ -> None)
8989+9090+ (* Tag definitions *)
9191+9292+ type 'a def =
9393+ { uid : int;
9494+ to_univ : 'a -> univ;
9595+ of_univ : univ -> 'a option;
9696+ name : string;
9797+ doc : string;
9898+ pp : Format.formatter -> 'a -> unit; }
9999+100100+ type def_e = Def : 'a def -> def_e
101101+102102+ let list = Atomic.make ([] : def_e list)
103103+ let uid =
104104+ let id = Atomic.make 0 in
105105+ fun () -> Atomic.fetch_and_add id 1
106106+107107+ let def ?(doc = "undocumented") name pp =
108108+ let to_univ, of_univ = univ () in
109109+ let tag = { uid = uid (); to_univ; of_univ; name; doc; pp } in
110110+ atomic_list_cons (Def tag) list;
111111+ tag
112112+113113+ let name d = d.name
114114+ let doc d = d.doc
115115+ let printer d = d.pp
116116+ let pp_def ppf d = Format.fprintf ppf "tag:%s" d.name
117117+ let list () = Atomic.get list
118118+119119+ (* Tag values *)
120120+121121+ type t = V : 'a def * 'a -> t
122122+123123+ let pp ppf (V (d, v)) =
124124+ Format.fprintf ppf "@[<1>(%a@ @[%a@])@]" pp_def d d.pp v
125125+126126+ (* Tag sets *)
127127+128128+ module Key = struct
129129+ type t = V : 'a def -> t
130130+ let compare (V k0) (V k1) = (compare : int -> int -> int) k0.uid k1.uid
131131+ end
132132+133133+ module M = Map.Make (Key)
134134+135135+ type set = t M.t
136136+137137+ let empty = M.empty
138138+ let is_empty = M.is_empty
139139+ let mem k s = M.mem (Key.V k) s
140140+ let add k v s = M.add (Key.V k) (V (k, v)) s
141141+ let rem k s = M.remove (Key.V k) s
142142+ let find : type a. a def -> set -> a option =
143143+ fun k s ->
144144+ try match M.find (Key.V k) s with
145145+ | V (k', v) -> k.of_univ (k'.to_univ v)
146146+ with Not_found -> None
147147+148148+ let get k s = match find k s with
149149+ | None -> invalid_arg (Printf.sprintf "tag named %s not found in set" k.name)
150150+ | Some v -> v
151151+152152+ let fold f s acc = M.fold (fun _ t acc -> f t acc) s acc
153153+ let pp_set ppf s =
154154+ let pp_tag tag is_first =
155155+ if is_first then () else Format.fprintf ppf "@,";
156156+ Format.fprintf ppf "%a" pp tag;
157157+ false
158158+ in
159159+ Format.fprintf ppf "@[<1>{";
160160+ ignore (fold pp_tag s true);
161161+ Format.fprintf ppf "}@]";
162162+ ()
163163+end
164164+165165+(* Reporters *)
166166+167167+type ('a, 'b) msgf =
168168+ (?header:string -> ?tags:Tag.set ->
169169+ ('a, Format.formatter, unit, 'b) format4 -> 'a) -> 'b
170170+171171+type reporter_mutex = { lock : unit -> unit; unlock : unit -> unit }
172172+let reporter_mutex' =
173173+ Atomic.make { lock = (fun () -> ()); unlock = (fun () -> ()) }
174174+175175+let set_reporter_mutex ~lock ~unlock =
176176+ Atomic.set reporter_mutex' { lock; unlock }
177177+178178+type reporter =
179179+ { report :
180180+ 'a 'b. src -> level -> over:(unit -> unit) -> (unit -> 'b) ->
181181+ ('a, 'b) msgf -> 'b }
182182+183183+let nop_reporter = { report = fun _ _ ~over k _ -> over (); k () }
184184+let reporter' = Atomic.make nop_reporter
185185+let set_reporter r = Atomic.set reporter' r
186186+let reporter () = Atomic.get reporter'
187187+let report src level ~over k msgf =
188188+ let mutex = Atomic.get reporter_mutex' in
189189+ let over () = over (); mutex.unlock () in
190190+ mutex.lock ();
191191+ try (Atomic.get reporter').report src level ~over k msgf with
192192+ | exn ->
193193+ let bt = Printexc.get_raw_backtrace () in
194194+ over ();
195195+ Printexc.raise_with_backtrace exn bt
196196+197197+let pp_brackets pp_v ppf v =
198198+ Format.pp_print_char ppf '['; pp_v ppf v; Format.pp_print_char ppf ']'
199199+200200+let pp_header ppf (l, h) = match h with
201201+| None -> if l = App then () else pp_brackets pp_level ppf l
202202+| Some h -> pp_brackets Format.pp_print_string ppf h
203203+204204+let pp_exec_header =
205205+ let exec = match Array.length Sys.argv with
206206+ | 0 -> Filename.basename Sys.executable_name
207207+ | n -> Filename.basename Sys.argv.(0)
208208+ in
209209+ fun ppf (l, h) ->
210210+ if l = App then match h with
211211+ | None -> ()
212212+ | Some h ->
213213+ pp_brackets Format.pp_print_string ppf h;
214214+ Format.pp_print_char ppf ' '
215215+ else match h with
216216+ | None ->
217217+ Format.pp_print_string ppf exec;
218218+ Format.pp_print_string ppf ": ";
219219+ pp_brackets pp_level ppf l;
220220+ Format.pp_print_char ppf ' '
221221+ | Some h ->
222222+ Format.pp_print_string ppf exec;
223223+ Format.pp_print_string ppf ": ";
224224+ pp_brackets Format.pp_print_string ppf h;
225225+ Format.pp_print_char ppf ' '
226226+227227+let format_reporter
228228+ ?(pp_header = pp_exec_header)
229229+ ?(app = Format.std_formatter)
230230+ ?(dst = Format.err_formatter) ()
231231+ =
232232+ let report src level ~over k msgf =
233233+ let k ppf =
234234+ Format.pp_close_box ppf ();
235235+ Format.pp_print_newline ppf ();
236236+ over (); k ()
237237+ in
238238+ msgf @@ fun ?header ?tags fmt ->
239239+ let ppf = if level = App then app else dst in
240240+ pp_header ppf (level, header);
241241+ Format.pp_open_box ppf 0;
242242+ Format.kfprintf k ppf fmt
243243+ in
244244+ { report }
245245+246246+(* Log functions *)
247247+248248+let err_count' = Atomic.make 0
249249+let err_count () = Atomic.get err_count'
250250+let incr_err_count () = Atomic.incr err_count'
251251+252252+let warn_count' = Atomic.make 0
253253+let warn_count () = Atomic.get warn_count'
254254+let incr_warn_count () = Atomic.incr warn_count'
255255+256256+type 'a log = ('a, unit) msgf -> unit
257257+258258+let over () = ()
259259+let kmsg k ?(src = default) level msgf =
260260+ begin match level with
261261+ | Error -> Atomic.incr err_count'
262262+ | Warning -> Atomic.incr warn_count'
263263+ | _ -> ()
264264+ end;
265265+ match Src.level src with
266266+ | None -> k ()
267267+ | Some current_level when level > current_level -> k ()
268268+ | Some _ -> report src level ~over k msgf
269269+270270+let kunit _ = ()
271271+let msg ?src level msgf = kmsg kunit ?src level msgf
272272+let app ?src msgf = kmsg kunit ?src App msgf
273273+let err ?src msgf = kmsg kunit ?src Error msgf
274274+let warn ?src msgf = kmsg kunit ?src Warning msgf
275275+let info ?src msgf = kmsg kunit ?src Info msgf
276276+let debug ?src msgf = kmsg kunit ?src Debug msgf
277277+278278+(* Log result errors *)
279279+280280+let on_error ?src ?(level = Error) ?header ?tags ~pp ~use = function
281281+| Ok v -> v
282282+| Error e ->
283283+ kmsg (fun () -> use e) ?src level @@ fun m ->
284284+ m ?header ?tags "@[%a@]" pp e
285285+286286+let on_error_msg ?src ?(level = Error) ?header ?tags ~use = function
287287+| Ok v -> v
288288+| Error (`Msg msg) ->
289289+ kmsg use ?src level @@ fun m ->
290290+ m ?header ?tags "@[%a@]" Format.pp_print_text msg
291291+292292+(* Source specific logging functions *)
293293+294294+module type LOG = sig
295295+ val msg : level -> 'a log
296296+ val app : 'a log
297297+ val err : 'a log
298298+ val warn : 'a log
299299+ val info : 'a log
300300+ val debug : 'a log
301301+ val kmsg : (unit -> 'b) -> level -> ('a, 'b) msgf -> 'b
302302+ val on_error :
303303+ ?level:level -> ?header:string -> ?tags:Tag.set ->
304304+ pp:(Format.formatter -> 'b -> unit) -> use:('b -> 'a) -> ('a, 'b) result ->
305305+ 'a
306306+307307+ val on_error_msg :
308308+ ?level:level -> ?header:string -> ?tags:Tag.set ->
309309+ use:(unit -> 'a) -> ('a, [`Msg of string]) result -> 'a
310310+end
311311+312312+let src_log src =
313313+ let module Log = struct
314314+ let msg level msgf = msg ~src level msgf
315315+ let kmsg k level msgf = kmsg k ~src level msgf
316316+ let app msgf = msg App msgf
317317+ let err msgf = msg Error msgf
318318+ let warn msgf = msg Warning msgf
319319+ let info msgf = msg Info msgf
320320+ let debug msgf = msg Debug msgf
321321+ let on_error ?level ?header ?tags ~pp ~use =
322322+ on_error ~src ?level ?header ?tags ~pp ~use
323323+324324+ let on_error_msg ?level ?header ?tags ~use =
325325+ on_error_msg ~src ?level ?header ?tags ~use
326326+ end
327327+ in
328328+ (module Log : LOG)
+609
vendor/opam/logs/src/logs.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Logging.
77+88+ [Logs] provides a basic logging infrastructure. {{!func}Logging}
99+ is performed on {{!srcs}sources} whose reporting
1010+ {{!type:level}level} can be set independently. Log message
1111+ report is decoupled from logging and handled by a
1212+ {{!reporters}reporter}.
1313+1414+ See the {{!basics}basics}, a few {{!usage}usage conventions} to
1515+ respect and a note on {{!sync}synchronous logging}. *)
1616+1717+(** {1:levels Reporting levels} *)
1818+1919+(** The type for reporting levels. For level semantics see the
2020+ {{!usage}usage conventions}.
2121+2222+ Log {{!srcs}sources} have an optional {{!Src.level}reporting level}. If
2323+ the level is [Some l] then any message whose level is smaller or
2424+ equal to [l] is reported. If the level is [None] no message is
2525+ ever reported. *)
2626+type level = App | Error | Warning | Info | Debug
2727+2828+val level : unit -> level option
2929+(** [level ()] is the reporting level given to {{!Src.create}new sources}. *)
3030+3131+val set_level : ?all:bool -> level option -> unit
3232+(** [set_level ?all l] sets the reporting level given to
3333+ {{!Src.create}new sources}. If [all] is [true] (default), also
3434+ sets the reporting level of all {{!Src.list}existing sources}. Use
3535+ {!Src.set_level} to only affect a specific source. Only applications
3636+ should use this function directly see {{!usage}usage conventions}. *)
3737+3838+val pp_level : Format.formatter -> level -> unit
3939+(** [pp_level ppf l] prints an unspecified representation of [l] on
4040+ [ppf]. *)
4141+4242+val level_to_string : level option -> string
4343+(** [level_to_string l] converts [l] to an US-ASCII string that can be
4444+ parsed back by {!level_of_string} and by the [LEVEL] option
4545+ argument of {!Logs_cli.level}. *)
4646+4747+val level_of_string : string -> (level option, [`Msg of string]) result
4848+(** [level_of_string s] parses the representation of {!level_to_string}
4949+ from [s]. *)
5050+5151+(** {1:srcs Log sources} *)
5252+5353+type src
5454+(** The type for log sources. A source defines a named unit of logging
5555+ whose reporting level can be set independently. *)
5656+5757+val default : src
5858+(** [default] is a logging source that is reserved for use by
5959+ applications. See {{!usage}usage conventions}. *)
6060+6161+(** Sources. *)
6262+module Src : sig
6363+6464+ (** {1 Sources} *)
6565+6666+ type t = src
6767+ (** The type for log sources. *)
6868+6969+ val create : ?doc:string -> string -> src
7070+ (** [create ?doc name] is a new log source. [name] is the name of
7171+ the source; it doesn't need to be unique but it is good practice
7272+ to prefix the name with the name of your package or library
7373+ (e.g. ["mypkg.network"]). [doc] is a documentation string
7474+ describing the source, defaults to ["undocumented"]. The initial
7575+ reporting level of the source is defined by {!Logs.level}. *)
7676+7777+ val name : src -> string
7878+ (** [name] is [src]'s name. *)
7979+8080+ val doc : src -> string
8181+ (** [doc src] is [src]'s documentation string. *)
8282+8383+ val level : src -> level option
8484+ (** [level src] is the report level of [src] (if any). *)
8585+8686+ val set_level : src -> level option -> unit
8787+ (** [set_level src l] sets the report level of [src] to [l]. Only
8888+ applications should use this function directly, see {{!usage}usage
8989+ conventions}. *)
9090+9191+ val equal : src -> src -> bool
9292+ (** [equal src src'] is [true] iff [src] and [src'] are the same source. *)
9393+9494+ val compare : src -> src -> int
9595+ (** [compare src src'] is a total order on sources. *)
9696+9797+ val pp : Format.formatter -> src -> unit
9898+ (** [pp ppf src] prints an unspecified representation of [src] on
9999+ [ppf]. *)
100100+101101+ val list : unit -> src list
102102+ (** [list ()] is the current exisiting source list. *)
103103+end
104104+105105+(** {1:func Log functions} *)
106106+107107+(** Message tags.
108108+109109+ Message tags are arbitrary named and typed values that can be
110110+ associated to log messages. See an {{!ex1}example}. *)
111111+module Tag : sig
112112+113113+ (** {1 Tag definitions} *)
114114+115115+ type 'a def
116116+ (** The type for tag definitions. The type ['a] is the type of the
117117+ tag. The definition specifies a name for the tag, a pretty-printer
118118+ for the type of the tag and a documentation string. See {!val:def}. *)
119119+120120+ (** The type for existential tag definitions. *)
121121+ type def_e = Def : 'a def -> def_e
122122+123123+ val def : ?doc:string -> string -> (Format.formatter -> 'a -> unit) -> 'a def
124124+ (** [def ~doc name pp] is a tag definition. [name] is the name of
125125+ the tag, it doesn't need to be unique. [pp] is a printer for the
126126+ type of the tag. [doc] is a documentation string describing
127127+ the tag (defaults to ["undocumented"]). *)
128128+129129+ val name : 'a def -> string
130130+ (** [name d] is [d]'s name. *)
131131+132132+ val doc : 'a def -> string
133133+ (** [doc d] is [d]'s documentation string. *)
134134+135135+ val printer : 'a def -> (Format.formatter -> 'a -> unit)
136136+ (** [printer d] is [d]'s type pretty-printer. *)
137137+138138+ val pp_def : Format.formatter -> 'a def -> unit
139139+ (** [pp_def ppf d] prints an unspecified representation of [d] on [ppf]. *)
140140+141141+ val list : unit -> def_e list
142142+ (** [tag_list ()] is the list of currently existing tag definitions. *)
143143+144144+ (** {1 Tags} *)
145145+146146+ (** The type for tags. Tuples the tag definition and its value. *)
147147+ type t = V : 'a def * 'a -> t
148148+149149+ val pp : Format.formatter -> t -> unit
150150+ (** [pp ppf t] prints an unspecified representation of [t] on [ppf]. *)
151151+152152+ (** {1 Tag sets} *)
153153+154154+ type set
155155+ (** The type for tag sets. A tag set contains at most one tag per
156156+ tag definition. *)
157157+158158+ val empty : set
159159+ (** [empty] is the empty set. *)
160160+161161+ val is_empty : set -> bool
162162+ (** [is_empty s] is [true] iff [s] is empty. *)
163163+164164+ val mem : 'a def -> set -> bool
165165+ (** [mem d s] is [true] iff [s] has a tag with definition [d]. *)
166166+167167+ val add : 'a def -> 'a -> set -> set
168168+ (** [add d v s] is [s] with the tag [(V (d, v))] added. If there was a tag
169169+ with definition [d] in [s] it is replaced. *)
170170+171171+ val rem : 'a def -> set -> set
172172+ (** [rem d s] is [s] without the tag defined by [d] (if there was one). *)
173173+174174+ val find : 'a def -> set -> 'a option
175175+ (** [find d s] is the tag value with definition [d] in [s] (if any). *)
176176+177177+ val get : 'a def -> set -> 'a
178178+ (** [get d s] is like [find d s] but @raise Invalid_argument if there
179179+ is no tag with definition [d] in [s]. *)
180180+181181+ val fold : (t -> 'a -> 'a) -> set -> 'a -> 'a
182182+ (** [fold f s acc] is the result of folding [f] over the tags
183183+ of [s] starting with [acc]. *)
184184+185185+ val pp_set : Format.formatter -> set -> unit
186186+ (** [pp_set ppf s] prints an unspecified representation of s on [ppf]. *)
187187+end
188188+189189+type ('a, 'b) msgf =
190190+ (?header:string -> ?tags:Tag.set ->
191191+ ('a, Format.formatter, unit, 'b) format4 -> 'a) -> 'b
192192+(** The type for client specified message formatting functions.
193193+194194+ Message formatting functions are called with a message
195195+ construction function whenever a message needs to be reported. The
196196+ message formatting function must call the given message
197197+ construction function with a format string and its arguments to
198198+ define the message contents, see the {{!logging}basics} for examples.
199199+ The optional arguments of the message construction function are:
200200+ {ul
201201+ {- [header], an optional printable message header. Default to [None].}
202202+ {- [tags], a set of tags to attach to the message. Defaults
203203+ {!Tag.empty}.}} *)
204204+205205+type 'a log = ('a, unit) msgf -> unit
206206+(** The type for log functions. See the {{!logging}basics} to understand
207207+ how to use log functions. *)
208208+209209+val msg : ?src:src -> level -> 'a log
210210+(** [msg ?src l (fun m -> m fmt ...)] logs with level [l] on the source
211211+ [src] (defaults to {!default}) a message formatted with [fmt]. For the
212212+ semantics of levels see the {{!usage}the usage conventions}. *)
213213+214214+val app : ?src:src -> 'a log
215215+(** [app] is [msg App]. *)
216216+217217+val err : ?src:src -> 'a log
218218+(** [err] is [msg Error]. *)
219219+220220+val warn : ?src:src -> 'a log
221221+(** [warn] is [msg Warning]. *)
222222+223223+val info : ?src:src -> 'a log
224224+(** [info] is [msg Info]. *)
225225+226226+val debug : ?src:src -> 'a log
227227+(** [debug] is [msg Debug]. *)
228228+229229+val kmsg : (unit -> 'b) -> ?src:src -> level -> ('a, 'b) msgf -> 'b
230230+(** [kmsg k] is like {!msg} but calls [k] for returning. *)
231231+232232+(** {2:result Logging [result] value [Error]s} *)
233233+234234+val on_error : ?src:src -> ?level:level -> ?header:string -> ?tags:Tag.set ->
235235+ pp:(Format.formatter -> 'b -> unit) -> use:('b -> 'a) -> ('a, 'b) result -> 'a
236236+(** [on_error ~level ~pp ~use r] is:
237237+ {ul
238238+ {- [v] if [r = Ok v]}
239239+ {- [use e] if [r = Error e]. As a side effect [msg] is logged
240240+ with [pp] on level [level] (defaults to {!Logs.Error}).}} *)
241241+242242+val on_error_msg : ?src:src -> ?level:level -> ?header:string ->
243243+ ?tags:Tag.set -> use:(unit -> 'a) ->
244244+ ('a, [`Msg of string]) result -> 'a
245245+(** [on_error_msg] is like {!on_error} but uses
246246+ {!Format.pp_print_text} to format the message. *)
247247+248248+(** {1:srcfunc Source specific log functions} *)
249249+250250+(** The type for source specific logging functions. *)
251251+module type LOG = sig
252252+253253+ (** {1:func Log functions} *)
254254+255255+ val msg : level -> 'a log
256256+ (** See {!Logs.msg}. *)
257257+258258+ val app : 'a log
259259+ (** [app] is [msg App]. *)
260260+261261+ val err : 'a log
262262+ (** [err] is [msg Error]. *)
263263+264264+ val warn : 'a log
265265+ (** [warn] is [msg Warning]. *)
266266+267267+ val info : 'a log
268268+ (** [info] is [msg Info]. *)
269269+270270+ val debug : 'a log
271271+ (** [debug] is [msg Debug]. *)
272272+273273+ val kmsg : (unit -> 'b) -> level -> ('a, 'b) msgf -> 'b
274274+ (** See {!Logs.kmsg}. *)
275275+276276+ (** {2:result Logging [result] value [Error]s} *)
277277+278278+ val on_error : ?level:level -> ?header:string -> ?tags:Tag.set ->
279279+ pp:(Format.formatter -> 'b -> unit) -> use:('b -> 'a) -> ('a, 'b) result ->
280280+ 'a
281281+ (** See {!Logs.on_error}. *)
282282+283283+ val on_error_msg : ?level:level -> ?header:string -> ?tags:Tag.set ->
284284+ use:(unit -> 'a) -> ('a, [`Msg of string]) result -> 'a
285285+ (** See {!Logs.on_error_msg}. *)
286286+end
287287+288288+val src_log : src -> (module LOG)
289289+(** [src_log src] is a {{!LOG}set of logging functions} for [src]. *)
290290+291291+(** {1:reporters Reporters} *)
292292+293293+type reporter =
294294+ { report : 'a 'b. src -> level -> over:(unit -> unit) -> (unit -> 'b) ->
295295+ ('a, 'b) msgf -> 'b }
296296+(** The type for reporters.
297297+298298+ A reporter formats and handles log messages that get
299299+ reported. Whenever a {{!func}log function} gets called on a source
300300+ with a level equal or smaller to the {{!Src.level}source's reporting
301301+ level}, the {{!reporter}current reporter}'s field [r.report]
302302+ gets called as [r.report src level ~over k msgf]
303303+ where:
304304+ {ul
305305+ {- [src] is the logging source.}
306306+ {- [level] is the reporting level.}
307307+ {- [over] must be called by the reporter once the logging operation is
308308+ over from the reporter's perspective. This may happen before or
309309+ after [k] is called.}
310310+ {- [k] is the function to invoke to return.}
311311+ {- [msgf] is the {{!msgf}message formatting function} to call.}}
312312+ See an {{!ex1}example}. *)
313313+314314+val nop_reporter : reporter
315315+(** [nop_reporter] is the initial reporter returned by {!reporter}, it
316316+ does nothing if a log message gets reported. *)
317317+318318+val format_reporter :
319319+ ?pp_header:(Format.formatter -> (level * string option) -> unit) ->
320320+ ?app:Format.formatter -> ?dst:Format.formatter -> unit -> reporter
321321+(** [format_reporter ~pp_header ~app ~dst ()] is a reporter that reports
322322+ {!App} level messages on [app] (defauts to {!Format.std_formatter})
323323+ and all other level on [dst] (defaults to {!Format.err_formatter}).
324324+325325+ [pp_header] determines how message headers are rendered. The default
326326+ prefixes the program name and renders the header with {!pp_header}.
327327+ Use {!Logs_fmt.reporter} if you want colored headers rendering.
328328+329329+ The reporter does not process or render information about message
330330+ sources or tags.
331331+332332+ {b Important.} This is a synchronous reporter it considers the log
333333+ operation to be over once the message was formatted and before
334334+ calling the continuation (see the {{!Logs.sync}note on synchronous
335335+ logging}). In particular if the formatters are backed by channels,
336336+ it will block until the message has been formatted on the channel
337337+ before proceeding which may not be suitable in a cooperative
338338+ concurrency setting like {!Lwt}. *)
339339+340340+val reporter : unit -> reporter
341341+(** [reporter ()] is the current repporter. *)
342342+343343+val set_reporter : reporter -> unit
344344+(** [set_reporter r] sets the current reporter to [r]. *)
345345+346346+val set_reporter_mutex : lock:(unit -> unit) -> unlock:(unit -> unit) -> unit
347347+(** [set_reporter_mutex ~lock ~unlock] sets the mutex primitives used
348348+ to access the reporter. [lock] is called before invoking the
349349+ reporter and [unlock] after it returns. Initially both [lock] and
350350+ [unlock] are [fun () -> ()]. *)
351351+352352+(**/**)
353353+val report : src -> level -> over:(unit -> unit) -> (unit -> 'b) ->
354354+ ('a, 'b) msgf -> 'b
355355+val incr_err_count : unit -> unit
356356+val incr_warn_count : unit -> unit
357357+(**/**)
358358+359359+val pp_header : Format.formatter -> (level * string option) -> unit
360360+(** [pp_header ppf (l, h)] prints an unspecified representation
361361+ of log header [h] for level [l]. *)
362362+363363+(** {1:monitoring Logs monitoring} *)
364364+365365+val err_count : unit -> int
366366+(** [err_count ()] is the number of messages logged with level [Error]
367367+ across all sources. *)
368368+369369+val warn_count : unit -> int
370370+(** [warn_count ()] is the number of messages logged with level
371371+ [Warning] across all sources. *)
372372+373373+(** {1:basics Basics}
374374+375375+ {2:logging Logging}
376376+377377+ In order to minimize the overhead whenever a log message is not reported,
378378+ message formatting only occurs on actual message report via the
379379+ {{!msgf}message formatting function} you provide to log functions. This
380380+ leads to the following logging structure:
381381+{[
382382+let k, v = ... in
383383+Logs.err (fun m -> m "invalid kv (%a,%a)" pp_key k pp_val v);
384384+Logs.err (fun m -> m "NO CARRIER");
385385+]}
386386+ The pattern is quite simple: it is as if you were formatting with
387387+ a [printf]-like function except you get this function in the [m]
388388+ argument of the function you give to the logging function.
389389+390390+ If you want to abstract a repeated log report it is better to keep
391391+ the message formatting function structure for the arguments of the
392392+ messages. Here's how the above examples can be abstracted and
393393+ invoked:
394394+{[
395395+let err_invalid_kv args =
396396+ Logs.err @@ fun m ->
397397+ args (fun k v -> m "invalid kv (%a,%a)" pp_key k pp_val v)
398398+399399+let err_no_carrier args =
400400+ Logs.err @@ fun m -> args (m "NO CARRIER")
401401+402402+let () =
403403+ err_invalid_kv (fun args -> args "key" "value");
404404+ err_no_carrier (fun () -> ());
405405+ ()
406406+]}
407407+ Note that log messages are formatted and hit the reporter only if
408408+ they have not been filtered out by the current
409409+ {{!Src.level}reporting level} of the source you log on. See also
410410+ the log source and reporting level {{!usage}usage conventions}.
411411+412412+ {2:setupreporter Reporter setup}
413413+414414+ If you are writing an application you must remember to
415415+ {{!set_reporter}set} the reporter before any logging operation
416416+ takes place otherwise no messages will be reported. For example if
417417+ you are using the {{!Logs_fmt}formatter reporter}, logging
418418+ can be setup as follows:
419419+{[
420420+let main () =
421421+ Logs.set_reporter (Logs_fmt.reporter ());
422422+ ...
423423+ if Logs.err_count () > 0 then 1 else 0
424424+425425+let () = if !Sys.interactive then () else exit (main ())
426426+]}
427427+ If you have logging code that is performed in the toplevel
428428+ initialization code of modules (not a good idea) or you depend on
429429+ (bad) libraries that do so, you must call and link the reporter
430430+ install code before these initialization bits are being executed
431431+ otherwise you will miss these messages.
432432+433433+ In multi-threaded programs you likely want to ensure mutual
434434+ exclusion on reporter access. This can be done by invoking
435435+ {!Logs.set_reporter_mutex} with suitable mutual exclusion
436436+ primitives. If you use OCaml {!Thread}s simply calling
437437+ {!Logs_threaded.enable} with handle that for you.
438438+439439+ If you need to use multiple reporters in your program see this
440440+ {{!ex2}sample code}.
441441+442442+ The documentation of {!Logs_cli} module has a {{!Logs_cli.ex}full setup
443443+ example} that includes command line options to control color and log
444444+ reporting level.
445445+446446+ If you are writing a library you should neither install reporters, nor
447447+ set the reporting level of sources, nor log on the {!default} source or
448448+ at the [App] level; follow the {{!usage}the usage conventions}. A
449449+ library should simply log on another existing source or define
450450+ its own source like in the example below:
451451+{[
452452+let src = Logs.Src.create "mylib.network" ~doc:"logs mylib's network events"
453453+module Log = (val Logs.src_log src : Logs.LOG)
454454+]}
455455+ The [Log] module defines logging functions that are specific to the
456456+ source [src].
457457+458458+ {1:usage Usage conventions}
459459+460460+ A library should never log on the {!default} source or at the
461461+ [App] level these are reserved for use by the application. It
462462+ should either create a source for itself or log on the source
463463+ defined by one of its dependencies. It should also never set the
464464+ reporting level of the sources it deals with or install reporters since
465465+ control over this must be left to the application.
466466+467467+ The semantics of {{!type:level}reporting levels} should be understood
468468+ as follows:
469469+ {ul
470470+ {- [App], this level can be used for the standard output or console
471471+ of an application. It should never be used by libraries.}
472472+ {- [Error], error condition that prevent the program from
473473+ running normally.}
474474+ {- [Warning], suspicious condition that does not prevent the
475475+ program from running normally but may eventually lead to an
476476+ error condition.}
477477+ {- [Info], condition that allows the program {e user} to get a better
478478+ understanding of what the program is doing.}
479479+ {- [Debug], condition that allows the program {e developer} to get a
480480+ better understanding of what the program is doing.}}
481481+482482+ {1:sync Note on synchronous logging}
483483+484484+ In synchronous logging, a client call to a log function proceeds
485485+ only once the reporter has finished the report operation. In
486486+ [Logs] this depends both on the reporter and the log functions
487487+ that the client uses.
488488+489489+ Whenever the client uses a log function that results in a report,
490490+ it gives the reporter a continuation that defines the result type
491491+ of the log function and a callback to be called whenever the log
492492+ operation is over from the reporter's perspective (see {!type:reporter}).
493493+ The typical use of the callback is to unblock the continuation given
494494+ to the reporter. This is used by {!Logs_lwt}'s log functions to make
495495+ sure that the threads they return proceed only once the report is over.
496496+ In the functions of {!Logs} however the callback does nothing as there
497497+ is no way to block the polymorphic continuation.
498498+499499+ Now considering reporters, at the extreme we have:
500500+ {ul
501501+ {- A completely asynchronous reporter. This reporter formats the
502502+ message in memory and immediately invoke the callback followed
503503+ by the continuation. This provides no guarantee of persistency
504504+ in case a crash occurs. All log functions behave asynchronously
505505+ and return as soon as possible.}
506506+ {- A completely synchronous reporter. This reporter formats the
507507+ message, persist it, invoke the client callback followed by the
508508+ continuation. All log functions behave synchronously. An
509509+ example of such a reporter is {!Logs_fmt.reporter} with
510510+ formatters baked by channels: when formatting returns the
511511+ message has been written on the channel.}}
512512+513513+ However a purely synchronous reporter like {!Logs_fmt.reporter}
514514+ acting on channels does not play well with [Lwt]'s cooperative
515515+ runtime system. It is possible to reuse {!Logs_fmt.reporter} to
516516+ define a cooperative reporter, see {{!Logs_lwt.report_ex}this
517517+ example}. However while this reporter makes {!Logs_lwt}'s log
518518+ functions synchronous, those of {!Logs} behave asynchronously. For
519519+ now it seems it that this is unfortunately the best we can do if
520520+ we want to preserve the ability to use [Logs] with or without
521521+ cooperative concurency.
522522+523523+ {1:ex1 Example with custom reporter and tags}
524524+525525+ This example uses a {{!Tag}tag} to attach {!Mtime} time spans in
526526+ log messages. The custom reporter uses these time spans to format
527527+ relative timings for runs of a given function. Note that as done
528528+ below the timings do include logging time.
529529+{[
530530+let stamp_tag : Mtime.span Logs.Tag.def =
531531+ Logs.Tag.def "stamp" ~doc:"Relative monotonic time stamp" Mtime.Span.pp
532532+533533+let stamp c = Logs.Tag.(empty |> add stamp_tag (Mtime_clock.count c))
534534+535535+let run () =
536536+ let rec wait n = if n = 0 then () else wait (n - 1) in
537537+ let c = Mtime_clock.counter () in
538538+ Logs.info (fun m -> m "Starting run");
539539+ let delay1, delay2, delay3 = 10_000, 20_000, 40_000 in
540540+ Logs.info (fun m -> m "Start action 1 (%d)." delay1 ~tags:(stamp c));
541541+ wait delay1;
542542+ Logs.info (fun m -> m "Start action 2 (%d)." delay2 ~tags:(stamp c));
543543+ wait delay2;
544544+ Logs.info (fun m -> m "Start action 3 (%d)." delay3 ~tags:(stamp c));
545545+ wait delay3;
546546+ Logs.info (fun m -> m "Done." ?header:None ~tags:(stamp c));
547547+ ()
548548+549549+let reporter ppf =
550550+ let report src level ~over k msgf =
551551+ let k _ = over (); k () in
552552+ let with_stamp h tags k ppf fmt =
553553+ let stamp = match tags with
554554+ | None -> None
555555+ | Some tags -> Logs.Tag.find stamp_tag tags
556556+ in
557557+ let dt = match stamp with None -> 0. | Some s -> Mtime.Span.to_us s in
558558+ Format.kfprintf k ppf ("%a[%0+04.0fus] @[" ^^ fmt ^^ "@]@.")
559559+ Logs.pp_header (level, h) dt
560560+ in
561561+ msgf @@ fun ?header ?tags fmt -> with_stamp header tags k ppf fmt
562562+ in
563563+ { Logs.report = report }
564564+565565+let main () =
566566+ Logs.set_reporter (reporter (Format.std_formatter));
567567+ Logs.set_level (Some Logs.Info);
568568+ run ();
569569+ run ();
570570+ if Logs.err_count () > 0 then 1 else 0
571571+572572+let () = if !Sys.interactive then () else main ()
573573+]}
574574+Here is the standard output of a sample run of the program:
575575+{v
576576+[INFO][+000us] Starting run
577577+[INFO][+168us] Start action 1 (10000).
578578+[INFO][+206us] Start action 2 (20000).
579579+[INFO][+243us] Start action 3 (40000).
580580+[INFO][+303us] Done.
581581+[INFO][+000us] Starting run
582582+[INFO][+012us] Start action 1 (10000).
583583+[INFO][+038us] Start action 2 (20000).
584584+[INFO][+074us] Start action 3 (40000).
585585+[INFO][+133us] Done.
586586+v}
587587+588588+ {1:ex2 Logging to multiple reporters}
589589+590590+ Logging to multiple reporters can be achieved by defining a new reporter
591591+ that simply forwards to them. The following example combines
592592+ two reporters:
593593+{[
594594+let combine r1 r2 =
595595+ let report = fun src level ~over k msgf ->
596596+ let v = r1.Logs.report src level ~over:(fun () -> ()) k msgf in
597597+ r2.Logs.report src level ~over (fun () -> v) msgf
598598+ in
599599+ { Logs.report }
600600+601601+let () =
602602+ let r1 = Logs.format_reporter () in
603603+ let r2 = Logs_fmt.reporter () in
604604+ Fmt_tty.setup_std_outputs ();
605605+ Logs.set_reporter (combine r1 r2);
606606+ Logs.err (fun m -> m "HEY HO!");
607607+ ()
608608+]}
609609+*)
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+type 'a log = ('a, unit Lwt.t) Logs.msgf -> unit Lwt.t
77+88+let kmsg k ?(src = Logs.default) level msgf =
99+ begin match level with
1010+ | Logs.Error -> Logs.incr_err_count ()
1111+ | Logs.Warning -> Logs.incr_warn_count ()
1212+ | _ -> ()
1313+ end;
1414+ match Logs.Src.level src with
1515+ | None -> k ()
1616+ | Some current_level when level > current_level -> k ()
1717+ | Some _ ->
1818+ let (ret, unblock) = Lwt.wait () in
1919+ let k () = Lwt.bind ret k in
2020+ let over () = Lwt.wakeup unblock () in
2121+ Logs.report src level ~over k msgf
2222+2323+let kunit _ = Lwt.return ()
2424+let msg ?src level msgf = kmsg kunit ?src level msgf
2525+let app ?src msgf = kmsg kunit ?src Logs.App msgf
2626+let err ?src msgf = kmsg kunit ?src Logs.Error msgf
2727+let warn ?src msgf = kmsg kunit ?src Logs.Warning msgf
2828+let info ?src msgf = kmsg kunit ?src Logs.Info msgf
2929+let debug ?src msgf = kmsg kunit ?src Logs.Debug msgf
3030+3131+let on_error ?src ?(level = Logs.Error) ?header ?tags ~pp ~use t =
3232+ Lwt.bind t @@ function
3333+ | Ok v -> Lwt.return v
3434+ | Error e ->
3535+ kmsg (fun () -> use e) ?src level @@ fun m ->
3636+ m ?header ?tags "@[%a@]" pp e
3737+3838+let on_error_msg ?src ?(level = Logs.Error) ?header ?tags ~use t =
3939+ Lwt.bind t @@ function
4040+ | Ok v -> Lwt.return v
4141+ | Error (`Msg e) ->
4242+ kmsg use ?src level @@ fun m ->
4343+ m ?header ?tags "@[%a@]" Format.pp_print_text e
4444+4545+(* Source specific functions *)
4646+4747+module type LOG = sig
4848+ val msg : Logs.level -> 'a log
4949+ val app : 'a log
5050+ val err : 'a log
5151+ val warn : 'a log
5252+ val info : 'a log
5353+ val debug : 'a log
5454+ val kmsg : ?over:(unit -> unit) -> (unit -> 'b Lwt.t) ->
5555+ Logs.level -> ('a, 'b Lwt.t) Logs.msgf -> 'b Lwt.t
5656+5757+ val on_error : ?level:Logs.level -> ?header:string -> ?tags:Logs.Tag.set ->
5858+ pp:(Format.formatter -> 'b -> unit) -> use:('b -> 'a Lwt.t) ->
5959+ ('a, 'b) result Lwt.t -> 'a Lwt.t
6060+6161+ val on_error_msg : ?level:Logs.level -> ?header:string ->
6262+ ?tags:Logs.Tag.set -> use:(unit -> 'a Lwt.t) ->
6363+ ('a, [`Msg of string]) result Lwt.t -> 'a Lwt.t
6464+end
6565+6666+let src_log src =
6767+ let module Log = struct
6868+ let msg level msgf = msg ~src level msgf
6969+ let kmsg ?over k level msgf = kmsg k ~src level msgf
7070+ let app msgf = msg Logs.App msgf
7171+ let err msgf = msg Logs.Error msgf
7272+ let warn msgf = msg Logs.Warning msgf
7373+ let info msgf = msg Logs.Info msgf
7474+ let debug msgf = msg Logs.Debug msgf
7575+ let on_error ?level ?header ?tags ~pp ~use =
7676+ on_error ~src ?level ?header ?tags ~pp ~use
7777+7878+ let on_error_msg ?level ?header ?tags ~use =
7979+ on_error_msg ~src ?level ?header ?tags ~use
8080+ end
8181+ in
8282+ (module Log : LOG)
+129
vendor/opam/logs/src/lwt/logs_lwt.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** {!Lwt} logging.
77+88+ The log functions of this module return [Lwt] threads that proceed
99+ only when the log operation is over, as defined by the current
1010+ {!Logs.reporter}.
1111+1212+ See a {{!report_ex}cooperative reporter example}. *)
1313+1414+(** {1 Log functions} *)
1515+1616+type 'a log = ('a, unit Lwt.t) Logs.msgf -> unit Lwt.t
1717+(** The type for Lwt log functions. The returned thread only proceeds
1818+ once the log operation is over. See {!Logs.log}. *)
1919+2020+val msg : ?src:Logs.src -> Logs.level -> 'a log
2121+(** See {!Logs.msg}. *)
2222+2323+val app : ?src:Logs.src -> 'a log
2424+(** See {!Logs.app}. *)
2525+2626+val err : ?src:Logs.src -> 'a log
2727+(** See {!Logs.err}. *)
2828+2929+val warn : ?src:Logs.src -> 'a log
3030+(** See {!Logs.warn}. *)
3131+3232+val info : ?src:Logs.src -> 'a log
3333+(** See {!Logs.info}. *)
3434+3535+val debug : ?src:Logs.src -> 'a log
3636+(** See {!Logs.debug}. *)
3737+3838+val kmsg : (unit -> 'b Lwt.t) -> ?src:Logs.src ->
3939+ Logs.level -> ('a, 'b Lwt.t) Logs.msgf -> 'b Lwt.t
4040+(** See {!Logs.kmsg}. *)
4141+4242+(** {2 Logging {!result} value [Error]s} *)
4343+4444+val on_error : ?src:Logs.src -> ?level:Logs.level -> ?header:string ->
4545+ ?tags:Logs.Tag.set -> pp:(Format.formatter -> 'b -> unit) ->
4646+ use:('b -> 'a Lwt.t) -> ('a, 'b) result Lwt.t -> 'a Lwt.t
4747+(** See {!Logs.on_error}. *)
4848+4949+val on_error_msg : ?src:Logs.src -> ?level:Logs.level -> ?header:string ->
5050+ ?tags:Logs.Tag.set -> use:(unit -> 'a Lwt.t) ->
5151+ ('a, [`Msg of string]) result Lwt.t -> 'a Lwt.t
5252+(** See {!Logs.on_error_msg}. *)
5353+5454+(** {1 Source specific log functions} *)
5555+5656+module type LOG = sig
5757+ val msg : Logs.level -> 'a log
5858+ (** See {!Logs.msg}. *)
5959+6060+ val app : 'a log
6161+ (** See {!Logs.app}. *)
6262+6363+ val err : 'a log
6464+ (** See {!Logs.err}. *)
6565+6666+ val warn : 'a log
6767+ (** See {!Logs.warn}. *)
6868+6969+ val info : 'a log
7070+ (** See {!Logs.info}. *)
7171+7272+ val debug : 'a log
7373+ (** See {!Logs.debug}. *)
7474+7575+ val kmsg : ?over:(unit -> unit) -> (unit -> 'b Lwt.t) ->
7676+ Logs.level -> ('a, 'b Lwt.t) Logs.msgf -> 'b Lwt.t
7777+ (** See {!Logs.kmsg}. *)
7878+7979+ (** {2 Logging {!result} value [Error]s} *)
8080+8181+ val on_error : ?level:Logs.level -> ?header:string ->
8282+ ?tags:Logs.Tag.set -> pp:(Format.formatter -> 'b -> unit) ->
8383+ use:('b -> 'a Lwt.t) -> ('a, 'b) result Lwt.t -> 'a Lwt.t
8484+ (** See {!Logs.on_error}. *)
8585+8686+ val on_error_msg : ?level:Logs.level -> ?header:string ->
8787+ ?tags:Logs.Tag.set -> use:(unit -> 'a Lwt.t) -> ('a, [`Msg of
8888+ string]) result Lwt.t -> 'a Lwt.t
8989+ (** See {!Logs.on_error_msg}. *)
9090+end
9191+9292+val src_log : Logs.src -> (module LOG)
9393+(** [src_log src] is a {{!LOG}set of logging functions} for [src]. *)
9494+9595+(** {1:report_ex Cooperative reporter example}
9696+9797+ The following reporter will play nice with [Lwt]'s runtime, it
9898+ will behave synchronously for the log functions of this module and
9999+ asynchronously for those of the {!Logs} module (see {!Logs.sync}).
100100+101101+ It reuses {!Logs_fmt.reporter} and will produce colorful output if
102102+ the standard formatters are setup to do so. For example it can be
103103+ used instead of {!Logs_fmt.reporter} in the {{!Logs_cli.ex}full
104104+ setup example}.
105105+{[
106106+let lwt_reporter () =
107107+ let buf_fmt ~like =
108108+ let b = Buffer.create 512 in
109109+ Fmt.with_buffer ~like b,
110110+ fun () -> let m = Buffer.contents b in Buffer.reset b; m
111111+ in
112112+ let app, app_flush = buf_fmt ~like:Fmt.stdout in
113113+ let dst, dst_flush = buf_fmt ~like:Fmt.stderr in
114114+ let reporter = Logs_fmt.reporter ~app ~dst () in
115115+ let report src level ~over k msgf =
116116+ let k () =
117117+ let write () = match level with
118118+ | Logs.App -> Lwt_io.write Lwt_io.stdout (app_flush ())
119119+ | _ -> Lwt_io.write Lwt_io.stderr (dst_flush ())
120120+ in
121121+ let unblock () = over (); Lwt.return_unit in
122122+ Lwt.finalize write unblock |> Lwt.ignore_result;
123123+ k ()
124124+ in
125125+ reporter.Logs.report src level ~over:(fun () -> ()) k msgf;
126126+ in
127127+ { Logs.report = report }
128128+]}
129129+*)
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+let () =
77+ Logs.set_level (Some Logs.Debug);
88+ Logs.set_reporter (Logs.format_reporter ());
99+ ()
+50
vendor/opam/logs/test/tags.ml
···11+(* This code is in the public domain. *)
22+33+(* Example with tags and custom reporter. *)
44+55+let stamp_tag : Mtime.span Logs.Tag.def =
66+ Logs.Tag.def "stamp" ~doc:"Relative monotonic time stamp" Mtime.Span.pp
77+88+let stamp c = Logs.Tag.(empty |> add stamp_tag (Mtime_clock.count c))
99+1010+let run () =
1111+ let rec wait n = if n = 0 then () else wait (n - 1) in
1212+ let c = Mtime_clock.counter () in
1313+ Logs.info (fun m -> m "Starting run");
1414+ let delay1, delay2, delay3 = 10_000, 20_000, 40_000 in
1515+ Logs.info (fun m -> m "Start action 1 (%d)." delay1 ~tags:(stamp c));
1616+ wait delay1;
1717+ Logs.info (fun m -> m "Start action 2 (%d)." delay2 ~tags:(stamp c));
1818+ wait delay2;
1919+ Logs.info (fun m -> m "Start action 3 (%d)." delay3 ~tags:(stamp c));
2020+ wait delay3;
2121+ Logs.info (fun m -> m "Done." ?header:None ~tags:(stamp c));
2222+ ()
2323+2424+let reporter ppf =
2525+ let report src level ~over k msgf =
2626+ let k _ = over (); k () in
2727+ let with_stamp h tags k ppf fmt =
2828+ let stamp = match tags with
2929+ | None -> None
3030+ | Some tags -> Logs.Tag.find stamp_tag tags
3131+ in
3232+ let dt = match stamp with
3333+ | None -> 0.
3434+ | Some s -> Mtime.Span.to_float_ns s *. 1000.
3535+ in
3636+ Format.kfprintf k ppf ("%a[%0+4.0fus] @[" ^^ fmt ^^ "@]@.")
3737+ Logs.pp_header (level, h) dt
3838+ in
3939+ msgf @@ fun ?header ?tags fmt -> with_stamp header tags k ppf fmt
4040+ in
4141+ { Logs.report = report }
4242+4343+let main () =
4444+ Logs.set_reporter (reporter (Format.std_formatter));
4545+ Logs.set_level (Some Logs.Info);
4646+ run ();
4747+ run ();
4848+ ()
4949+5050+let () = main ()
+48
vendor/opam/logs/test/test_browser.html
···11+<!DOCTYPE html>
22+<!--
33+ Copyright (c) 2015 The logs programmers. All rights reserved.
44+ Distributed under the ISC license, see license at the end of the file.
55+-->
66+<html lang="en">
77+<head>
88+ <meta charset="utf-8">
99+ <meta name="viewport" content="width=device-width,
1010+ initial-scale=1.0">
1111+ <script type="text/javascript" defer="defer" src="test_browser.js"></script>
1212+ <style type="text/css">
1313+ h1 { font-size: 2.5rem; font-weight: 300; text-transform: uppercase; }
1414+ body { background-color: black;
1515+ color: #A0A0A0;
1616+ font-size: 1rem;
1717+ line-height: 1.3125rem;
1818+ font-family: monospace;
1919+ font-weight: 300;
2020+ margin: 4em; }
2121+2222+ div { font-size: 0.8rem; margin-top:1.3125rem; }
2323+ p { margin:0rem; padding:0rem; white-space: pre; }
2424+ </style>
2525+ <title>Logs test</title>
2626+</head>
2727+<body>
2828+ <noscript>Sorry, you need to enable JavaScript to see this page.</noscript>
2929+ <h1>Logs test</h1>
3030+ See the browser console.
3131+</body>
3232+</html>
3333+3434+<!--
3535+ Copyright (c) 2015 The logs programmers
3636+3737+ Permission to use, copy, modify, and/or distribute this software for any
3838+ purpose with or without fee is hereby granted, provided that the above
3939+ copyright notice and this permission notice appear in all copies.
4040+4141+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
4242+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
4343+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
4444+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
4545+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
4646+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
4747+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4848+ -->
+21
vendor/opam/logs/test/test_browser.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+open Js_of_ocaml
77+88+let main _ =
99+ Logs.set_level @@ Some Logs.Debug;
1010+ Logs.set_reporter @@ Logs_browser.console_reporter ();
1111+ Logs.info (fun m -> m ~header:"START" ?tags:None "Starting main");
1212+ Logs.warn (fun m -> m "Hey be warned by %d." 7);
1313+ Logs.err (fun m -> m "Hey be errored.");
1414+ Logs.debug (fun m -> m "Would you mind to be debugged a bit ?");
1515+ Logs.app (fun m -> m "This is for the application console or stdout.");
1616+ Logs.app (fun m -> m ~header:"HEAD" "Idem but with a header");
1717+ Logs.err (fun m -> m "NO CARRIER");
1818+ Logs.info (fun m -> m "Ending main");
1919+ Js._false
2020+2121+let () = Js.Unsafe.set Dom_html.window "onload" (Dom_html.handler main)
+25
vendor/opam/logs/test/test_count.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+open B0_testing
77+88+let test_count =
99+ Test.test "Logs.{err,warn}_count" @@ fun () ->
1010+ let logit () =
1111+ Logs.warn (fun m -> m "Hey");
1212+ Logs.err (fun m -> m "Ho");
1313+ Logs.warn (fun m -> m "Let's go");
1414+ in
1515+ logit ();
1616+ Test.int (Logs.err_count ()) 1 ~__POS__;
1717+ Test.int (Logs.warn_count ()) 2 ~__POS__;
1818+ Logs.set_level None;
1919+ logit ();
2020+ Test.int (Logs.err_count ()) 2 ~__POS__;
2121+ Test.int (Logs.warn_count ()) 4 ~__POS__;
2222+ ()
2323+2424+let main () = Test.main @@ fun () -> Test.autorun ()
2525+let () = if !Sys.interactive then () else exit (main ())
+36
vendor/opam/logs/test/test_fmt.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+let pp_key = Format.pp_print_string
77+let pp_val = Format.pp_print_string
88+99+1010+let err_invalid_kv args =
1111+ Logs.err @@ fun m ->
1212+ args (fun k v -> m "invalid kv (%a,%a)" pp_key k pp_val v)
1313+1414+let err_no_carrier args =
1515+ Logs.err @@ fun m -> args (m "NO CARRIER")
1616+1717+let main () =
1818+ Fmt_tty.setup_std_outputs ();
1919+ Logs.set_level @@ Some Logs.Debug;
2020+ Logs.set_reporter @@ Logs_fmt.reporter ();
2121+ Logs.info (fun m -> m ~header:"START" ?tags:None "Starting main");
2222+ Logs.warn (fun m -> m "Hey be warned by %d." 7);
2323+ Logs.err (fun m -> m "Hey be errored.");
2424+ Logs.debug (fun m -> m "Would you mind to be debugged a bit ?");
2525+ Logs.app (fun m -> m "This is for the application console or stdout.");
2626+ Logs.app (fun m -> m ~header:"HEAD" "Idem but with a header");
2727+ let k = "key" in
2828+ let v = "value" in
2929+ Logs.err (fun m -> m "invalid kv (%a,%a)" pp_key k pp_val v);
3030+ Logs.err (fun m -> m "NO CARRIER");
3131+ err_invalid_kv (fun args -> args k v);
3232+ err_no_carrier (fun () -> ());
3333+ Logs.info (fun m -> m "Ending main");
3434+ exit (if (Logs.err_count () > 0) then 1 else 0)
3535+3636+let () = main ()
+33
vendor/opam/logs/test/test_formatter.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2016 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+let pp_key = Format.pp_print_string
77+let pp_val = Format.pp_print_string
88+99+let err_invalid_kv args =
1010+ Logs.err @@ fun m ->
1111+ args (fun k v -> m "invalid kv (%a,%a)" pp_key k pp_val v)
1212+1313+let err_no_carrier args =
1414+ Logs.err @@ fun m -> args (m "NO CARRIER")
1515+1616+let main () =
1717+ Logs.set_level @@ Some Logs.Debug;
1818+ Logs.set_reporter @@ Logs.format_reporter ();
1919+ Logs.info (fun m -> m ~header:"START" ?tags:None "Starting main");
2020+ Logs.warn (fun m -> m "Hey be warned by %d." 7);
2121+ Logs.err (fun m -> m "Hey be errored.");
2222+ Logs.debug (fun m -> m "Would you mind to be debugged a bit ?");
2323+ Logs.app (fun m -> m "This is for the application console or stdout.");
2424+ let k = "key" in
2525+ let v = "value" in
2626+ Logs.err (fun m -> m "invalid kv (%a,%a)" pp_key k pp_val v);
2727+ Logs.err (fun m -> m "NO CARRIER");
2828+ err_invalid_kv (fun args -> args k v);
2929+ err_no_carrier (fun () -> ());
3030+ Logs.info (fun m -> m "Ending main");
3131+ if (Logs.err_count () > 0) then 1 else 0
3232+3333+let () = if !Sys.interactive then () else exit (main ())
+62
vendor/opam/logs/test/test_lwt.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2015 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+open B0_testing
77+88+let ( >>= ) = Lwt.bind
99+1010+let lwt_reporter () =
1111+ let buf_fmt ~like =
1212+ let b = Buffer.create 512 in
1313+ Fmt.with_buffer ~like b,
1414+ fun () -> let m = Buffer.contents b in Buffer.reset b; m
1515+ in
1616+ let app, app_flush = buf_fmt ~like:Fmt.stdout in
1717+ let dst, dst_flush = buf_fmt ~like:Fmt.stderr in
1818+ let reporter = Logs_fmt.reporter ~app ~dst () in
1919+ let report src level ~over k msgf =
2020+ let k () =
2121+ let write () = match level with
2222+ | Logs.App -> Lwt_io.write Lwt_io.stdout (app_flush ())
2323+ | _ -> Lwt_io.write Lwt_io.stderr (dst_flush ())
2424+ in
2525+ let unblock () = over (); Lwt.return_unit in
2626+ Lwt.finalize write unblock |> Lwt.ignore_result;
2727+ k ()
2828+ in
2929+ reporter.Logs.report src level ~over:(fun () -> ()) k msgf;
3030+ in
3131+ { Logs.report = report }
3232+3333+let test_count () =
3434+ let logit () =
3535+ Logs_lwt.warn (fun m -> m "Hey") >>= fun () ->
3636+ Logs_lwt.err (fun m -> m "Ho") >>= fun () ->
3737+ Logs_lwt.warn (fun m -> m "Let's go")
3838+ in
3939+ Test.int (Logs.err_count ()) 1 ~__POS__;
4040+ Test.int (Logs.warn_count ()) 1 ~__POS__;
4141+ Logs.set_level None;
4242+ logit () >>= fun () ->
4343+ Test.int (Logs.err_count ()) 2 ~__POS__;
4444+ Test.int (Logs.warn_count ()) 3 ~__POS__;
4545+ Lwt.return_unit
4646+4747+let main () =
4848+ Test.main @@ fun () ->
4949+ Fmt_tty.setup_std_outputs ();
5050+ Logs.set_reporter @@ lwt_reporter ();
5151+ Lwt_main.run @@ begin
5252+ Logs.set_level (Some Logs.Debug);
5353+ Logs_lwt.info (fun m -> m ~header:"START" ?tags:None "Starting main")
5454+ >>= fun () -> Logs_lwt.warn (fun m -> m "Hey be warned by %d." 7)
5555+ >>= fun () -> Logs_lwt.err (fun m -> m "Hey be errored.")
5656+ >>= fun () -> Logs_lwt.debug (fun m -> m "Be debugged a bit ?")
5757+ >>= fun () -> Logs_lwt.app (fun m -> m "Application console or stdout.")
5858+ >>= fun () -> Logs_lwt.info (fun m -> m "Ending main")
5959+ >>= fun () -> test_count ()
6060+end
6161+6262+let () = if !Sys.interactive then () else exit (main ())
+18
vendor/opam/logs/test/test_multi.ml
···11+(* This code is in the public domain. *)
22+33+(* Example for installing multiple reporters. *)
44+55+let combine r1 r2 =
66+ let report = fun src level ~over k msgf ->
77+ let v = r1.Logs.report src level ~over:(fun () -> ()) k msgf in
88+ r2.Logs.report src level ~over (fun () -> v) msgf
99+ in
1010+ { Logs.report }
1111+1212+let () =
1313+ let r1 = Logs.format_reporter () in
1414+ let r2 = Logs_fmt.reporter () in
1515+ Fmt_tty.setup_std_outputs ();
1616+ Logs.set_reporter (combine r1 r2);
1717+ Logs.err (fun m -> m "HEY HO!");
1818+ ()
+23
vendor/opam/logs/test/test_mutex_safe.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 The logs programmers. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(* See https://github.com/dbuenzli/logs/issues/57 *)
77+88+let src = Logs.Src.create "repro case"
99+module Log = (val Logs.src_log src)
1010+1111+let setup_logs () =
1212+ Logs.set_reporter (Logs_fmt.reporter ());
1313+ Logs.set_level ~all:true (Some Logs.Debug);
1414+ Logs_threaded.enable ();
1515+ ()
1616+1717+let main () =
1818+ setup_logs ();
1919+ (try Logs.app (fun _m -> failwith "uh oh...") with Failure _ -> ());
2020+ Logs.app (fun m -> m "It works!");
2121+ 0
2222+2323+let () = if !Sys.interactive then () else exit (main ())
+14
vendor/opam/logs/test/test_threaded.ml
···11+let loop s =
22+ for _ = 0 to 10 do
33+ Logs.info (fun f -> f "%s.%s" s s)
44+ done
55+66+let () =
77+ Logs_threaded.enable ();
88+ Logs.set_level (Some Logs.Debug);
99+ Logs.set_reporter (Logs_fmt.reporter ());
1010+ let t1 = Thread.create loop "aaaa" in
1111+ let t2 = Thread.create loop "bbbb" in
1212+ loop "cccc";
1313+ Thread.join t1;
1414+ Thread.join t2
···11+(* This code is in the public domain. *)
22+33+(* Example setup for a simple command line tool with colorful output. *)
44+55+let hello msg =
66+ Logs.app (fun m -> m "%s" msg);
77+ Logs.info (fun m -> m "End-user information.");
88+ Logs.debug (fun m -> m "Developer information.");
99+ Logs.err (fun m -> m "Something bad happened.");
1010+ Logs.warn (fun m -> m "Something bad may happen in the future.");
1111+ if Logs.err_count () > 0 then 1 else 0
1212+1313+let setup_log ~style_renderer ~level =
1414+ Fmt_tty.setup_std_outputs ?style_renderer ();
1515+ Logs.set_level level;
1616+ Logs.set_reporter (Logs_fmt.reporter ())
1717+1818+(* Command line interface *)
1919+2020+open Cmdliner
2121+open Cmdliner.Term.Syntax
2222+2323+let cmd =
2424+ Cmd.make (Cmd.info "tool") @@
2525+ let env = Cmd.Env.info "TOOL_VERBOSITY" in
2626+ let+ style_renderer = Fmt_cli.style_renderer ()
2727+ and+ level = Logs_cli.level ~env ()
2828+ and+ msg =
2929+ let doc = "The message to output." in
3030+ Arg.(value & pos 0 string "Hello horrible world!" & info [] ~doc)
3131+ in
3232+ setup_log ~style_renderer ~level;
3333+ hello msg
3434+3535+3636+let main () = Cmd.eval' cmd
3737+let () = if !Sys.interactive then () else exit (main ())