linol/logs/Logs/index.html
2024-05-08 15:15:46 +00:00

113 lines
37 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Logs (logs.Logs)</title><meta charset="utf-8"/><link rel="stylesheet" href="../../_odoc-theme/odoc.css"/><meta name="generator" content="odoc 2.4.2"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><script src="../../highlight.pack.js"></script><script>hljs.initHighlightingOnLoad();</script></head><body class="odoc"><nav class="odoc-nav"><a href="../index.html">Up</a> <a href="../index.html">logs</a> &#x00BB; Logs</nav><header class="odoc-preamble"><h1>Module <code><span>Logs</span></code></h1><p>Logging.</p><p><code>Logs</code> provides a basic logging infrastructure. <a href="#func" title="func">Logging</a> is performed on <a href="#srcs" title="srcs">sources</a> whose reporting <a href="#type-level" title="level">level</a> can be set independently. Log message report is decoupled from logging and handled by a <a href="#reporters" title="reporters">reporter</a>.</p><p>See the <a href="#basics" title="basics">basics</a>, a few <a href="#usage" title="usage">usage conventions</a> to respect and a note on <a href="#sync" title="sync">synchronous logging</a>.</p><p><em>v0.7.0 - <a href="https://erratique.ch/software/logs">homepage</a></em></p></header><nav class="odoc-toc"><ul><li><a href="#levels">Reporting levels</a></li><li><a href="#srcs">Log sources</a></li><li><a href="#func">Log functions</a><ul><li><a href="#result">Logging <code>result</code> value <code>Error</code>s</a></li></ul></li><li><a href="#srcfunc">Source specific log functions</a></li><li><a href="#reporters">Reporters</a></li><li><a href="#monitoring">Logs monitoring</a></li><li><a href="#basics">Basics</a><ul><li><a href="#logging">Logging</a></li><li><a href="#setupreporter">Reporter setup</a></li></ul></li><li><a href="#usage">Usage conventions</a></li><li><a href="#sync">Note on synchronous logging</a></li><li><a href="#ex1">Example with custom reporter and tags</a></li><li><a href="#ex2">Logging to multiple reporters</a></li></ul></nav><div class="odoc-content"><h2 id="levels"><a href="#levels" class="anchor"></a>Reporting levels</h2><div class="odoc-spec"><div class="spec type anchored" id="type-level"><a href="#type-level" class="anchor"></a><code><span><span class="keyword">type</span> level</span><span> = </span></code><ol><li id="type-level.App" class="def variant constructor anchored"><a href="#type-level.App" class="anchor"></a><code><span>| </span><span><span class="constructor">App</span></span></code></li><li id="type-level.Error" class="def variant constructor anchored"><a href="#type-level.Error" class="anchor"></a><code><span>| </span><span><span class="constructor">Error</span></span></code></li><li id="type-level.Warning" class="def variant constructor anchored"><a href="#type-level.Warning" class="anchor"></a><code><span>| </span><span><span class="constructor">Warning</span></span></code></li><li id="type-level.Info" class="def variant constructor anchored"><a href="#type-level.Info" class="anchor"></a><code><span>| </span><span><span class="constructor">Info</span></span></code></li><li id="type-level.Debug" class="def variant constructor anchored"><a href="#type-level.Debug" class="anchor"></a><code><span>| </span><span><span class="constructor">Debug</span></span></code></li></ol></div><div class="spec-doc"><p>The type for reporting levels. For level semantics see the <a href="#usage" title="usage">usage conventions</a>.</p><p>Log <a href="#srcs" title="srcs">sources</a> have an optional <a href="Src/index.html#val-level" title="Src.level">reporting level</a>. If the level is <code>Some l</code> then any message whose level is smaller or equal to <code>l</code> is reported. If the level is <code>None</code> no message is ever reported.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-level"><a href="#val-level" class="anchor"></a><code><span><span class="keyword">val</span> level : <span>unit <span class="arrow">&#45;&gt;</span></span> <span><a href="#type-level">level</a> option</span></span></code></div><div class="spec-doc"><p><code>level ()</code> is the reporting level given to <a href="Src/index.html#val-create" title="Src.create">new sources</a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set_level"><a href="#val-set_level" class="anchor"></a><code><span><span class="keyword">val</span> set_level : <span><span class="optlabel">?all</span>:bool <span class="arrow">&#45;&gt;</span></span> <span><span><a href="#type-level">level</a> option</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>set_level ?all l</code> sets the reporting level given to <a href="Src/index.html#val-create" title="Src.create">new sources</a>. If <code>all</code> is <code>true</code> (default), also sets the reporting level of all <a href="Src/index.html#val-list" title="Src.list">existing sources</a>. Use <a href="Src/index.html#val-set_level"><code>Src.set_level</code></a> to only affect a specific source. Only applications should use this function directly see <a href="#usage" title="usage">usage conventions</a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pp_level"><a href="#val-pp_level" class="anchor"></a><code><span><span class="keyword">val</span> pp_level : <span><a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="#type-level">level</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>pp_level ppf l</code> prints an unspecified representation of <code>l</code> on <code>ppf</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-level_to_string"><a href="#val-level_to_string" class="anchor"></a><code><span><span class="keyword">val</span> level_to_string : <span><span><a href="#type-level">level</a> option</span> <span class="arrow">&#45;&gt;</span></span> string</span></code></div><div class="spec-doc"><p><code>level_to_string l</code> converts <code>l</code> to an US-ASCII string that can be parsed back by <a href="#val-level_of_string"><code>level_of_string</code></a> and by the <code>LEVEL</code> option argument of <a href="../Logs_cli/index.html#val-level"><code>Logs_cli.level</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-level_of_string"><a href="#val-level_of_string" class="anchor"></a><code><span><span class="keyword">val</span> level_of_string : <span>string <span class="arrow">&#45;&gt;</span></span> <span><span>(<span><a href="#type-level">level</a> option</span>, <span>[ <span>`Msg of string</span> ]</span>)</span> <a href="../../ocaml/Stdlib/index.html#type-result">result</a></span></span></code></div><div class="spec-doc"><p><code>level_of_string s</code> parses the representation of <a href="#val-level_to_string"><code>level_to_string</code></a> from <code>s</code>.</p></div></div><h2 id="srcs"><a href="#srcs" class="anchor"></a>Log sources</h2><div class="odoc-spec"><div class="spec type anchored" id="type-src"><a href="#type-src" class="anchor"></a><code><span><span class="keyword">type</span> src</span></code></div><div class="spec-doc"><p>The type for log sources. A source defines a named unit of logging whose reporting level can be set independently.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-default"><a href="#val-default" class="anchor"></a><code><span><span class="keyword">val</span> default : <a href="#type-src">src</a></span></code></div><div class="spec-doc"><p><code>default</code> is a logging source that is reserved for use by applications. See <a href="#usage" title="usage">usage conventions</a>.</p></div></div><div class="odoc-spec"><div class="spec module anchored" id="module-Src"><a href="#module-Src" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Src/index.html">Src</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Sources.</p></div></div><h2 id="func"><a href="#func" class="anchor"></a>Log functions</h2><div class="odoc-spec"><div class="spec module anchored" id="module-Tag"><a href="#module-Tag" class="anchor"></a><code><span><span class="keyword">module</span> <a href="Tag/index.html">Tag</a></span><span> : <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>Message tags.</p></div></div><div class="odoc-spec"><div class="spec type anchored" id="type-msgf"><a href="#type-msgf" class="anchor"></a><code><span><span class="keyword">type</span> <span>('a, 'b) msgf</span></span><span> =
<span><span>(<span><span class="optlabel">?header</span>:string <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?tags</span>:<a href="Tag/index.html#type-set">Tag.set</a> <span class="arrow">&#45;&gt;</span></span>
<span><span><span>(<span class="type-var">'a</span>, <a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a>, unit, <span class="type-var">'b</span>)</span> <a href="../../ocaml/Stdlib/index.html#type-format4">format4</a></span> <span class="arrow">&#45;&gt;</span></span>
<span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span>
<span class="type-var">'b</span></span></code></div><div class="spec-doc"><p>The type for client specified message formatting functions.</p><p>Message formatting functions are called with a message construction function whenever a message needs to be reported. The message formatting function must call the given message construction function with a format string and its arguments to define the message contents, see the <a href="#logging" title="logging">basics</a> for examples. The optional arguments of the message construction function are:</p><ul><li><code>header</code>, an optional printable message header. Default to <code>None</code>.</li><li><code>tags</code>, a set of tags to attach to the message. Defaults <a href="Tag/index.html#val-empty"><code>Tag.empty</code></a>.</li></ul></div></div><div class="odoc-spec"><div class="spec type anchored" id="type-log"><a href="#type-log" class="anchor"></a><code><span><span class="keyword">type</span> <span>'a log</span></span><span> = <span><span><span>(<span class="type-var">'a</span>, unit)</span> <a href="#type-msgf">msgf</a></span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p>The type for log functions. See the <a href="#logging" title="logging">basics</a> to understand how to use log functions.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-msg"><a href="#val-msg" class="anchor"></a><code><span><span class="keyword">val</span> msg : <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="#type-level">level</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-log">log</a></span></span></code></div><div class="spec-doc"><p><code>msg ?src l (fun m -&gt; m fmt ...)</code> logs with level <code>l</code> on the source <code>src</code> (defaults to <a href="#val-default"><code>default</code></a>) a message formatted with <code>fmt</code>. For the semantics of levels see the <a href="#usage" title="usage">the usage conventions</a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-app"><a href="#val-app" class="anchor"></a><code><span><span class="keyword">val</span> app : <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-log">log</a></span></span></code></div><div class="spec-doc"><p><code>app</code> is <code>msg App</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-err"><a href="#val-err" class="anchor"></a><code><span><span class="keyword">val</span> err : <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-log">log</a></span></span></code></div><div class="spec-doc"><p><code>err</code> is <code>msg Error</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-warn"><a href="#val-warn" class="anchor"></a><code><span><span class="keyword">val</span> warn : <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-log">log</a></span></span></code></div><div class="spec-doc"><p><code>warn</code> is <code>msg Warning</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-info"><a href="#val-info" class="anchor"></a><code><span><span class="keyword">val</span> info : <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-log">log</a></span></span></code></div><div class="spec-doc"><p><code>info</code> is <code>msg Info</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-debug"><a href="#val-debug" class="anchor"></a><code><span><span class="keyword">val</span> debug : <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'a</span> <a href="#type-log">log</a></span></span></code></div><div class="spec-doc"><p><code>debug</code> is <code>msg Debug</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-kmsg"><a href="#val-kmsg" class="anchor"></a><code><span><span class="keyword">val</span> kmsg : <span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span>)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span><a href="#type-level">level</a> <span class="arrow">&#45;&gt;</span></span> <span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-msgf">msgf</a></span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span></span></code></div><div class="spec-doc"><p><code>kmsg k</code> is like <a href="#val-msg"><code>msg</code></a> but calls <code>k</code> for returning.</p></div></div><h3 id="result"><a href="#result" class="anchor"></a>Logging <code>result</code> value <code>Error</code>s</h3><div class="odoc-spec"><div class="spec value anchored" id="val-on_error"><a href="#val-on_error" class="anchor"></a><code><span><span class="keyword">val</span> on_error :
<span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?level</span>:<a href="#type-level">level</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?header</span>:string <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?tags</span>:<a href="Tag/index.html#type-set">Tag.set</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">pp</span>:<span>(<span><a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a> <span class="arrow">&#45;&gt;</span></span> <span><span class="type-var">'b</span> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">use</span>:<span>(<span><span class="type-var">'b</span> <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="../../ocaml/Stdlib/index.html#type-result">result</a></span> <span class="arrow">&#45;&gt;</span></span>
<span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>on_error ~level ~pp ~use r</code> is:</p><ul><li><code>v</code> if <code>r = Ok v</code></li><li><code>use e</code> if <code>r = Error e</code>. As a side effect <code>msg</code> is logged with <code>pp</code> on level <code>level</code> (defaults to <a href="#type-level.Error"><code>Logs.level.Error</code></a>).</li></ul></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-on_error_msg"><a href="#val-on_error_msg" class="anchor"></a><code><span><span class="keyword">val</span> on_error_msg :
<span><span class="optlabel">?src</span>:<a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?level</span>:<a href="#type-level">level</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?header</span>:string <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?tags</span>:<a href="Tag/index.html#type-set">Tag.set</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">use</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'a</span>)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span><span>(<span class="type-var">'a</span>, <span>[ <span>`Msg of string</span> ]</span>)</span> <a href="../../ocaml/Stdlib/index.html#type-result">result</a></span> <span class="arrow">&#45;&gt;</span></span>
<span class="type-var">'a</span></span></code></div><div class="spec-doc"><p><code>on_error_msg</code> is like <a href="#val-on_error"><code>on_error</code></a> but uses <code>Format.pp_print_text</code> to format the message.</p></div></div><h2 id="srcfunc"><a href="#srcfunc" class="anchor"></a>Source specific log functions</h2><div class="odoc-spec"><div class="spec module-type anchored" id="module-type-LOG"><a href="#module-type-LOG" class="anchor"></a><code><span><span class="keyword">module</span> <span class="keyword">type</span> <a href="module-type-LOG/index.html">LOG</a></span><span> = <span class="keyword">sig</span> ... <span class="keyword">end</span></span></code></div><div class="spec-doc"><p>The type for source specific logging functions.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-src_log"><a href="#val-src_log" class="anchor"></a><code><span><span class="keyword">val</span> src_log : <span><a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span> <span>(<span class="keyword">module</span> <a href="module-type-LOG/index.html">LOG</a>)</span></span></code></div><div class="spec-doc"><p><code>src_log src</code> is a <a href="module-type-LOG/index.html" title="LOG">set of logging functions</a> for <code>src</code>.</p></div></div><h2 id="reporters"><a href="#reporters" class="anchor"></a>Reporters</h2><div class="odoc-spec"><div class="spec type anchored" id="type-reporter"><a href="#type-reporter" class="anchor"></a><code><span><span class="keyword">type</span> reporter</span><span> = </span><span>{</span></code><ol><li id="type-reporter.report" class="def record field anchored"><a href="#type-reporter.report" class="anchor"></a><code><span>report : 'a 'b. <span><a href="#type-src">src</a> <span class="arrow">&#45;&gt;</span></span>
<span><a href="#type-level">level</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="label">over</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span>(<span>unit <span class="arrow">&#45;&gt;</span></span> <span class="type-var">'b</span>)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span><span>(<span class="type-var">'a</span>, <span class="type-var">'b</span>)</span> <a href="#type-msgf">msgf</a></span> <span class="arrow">&#45;&gt;</span></span>
<span class="type-var">'b</span>;</span></code></li></ol><code><span>}</span></code></div><div class="spec-doc"><p>The type for reporters.</p><p>A reporter formats and handles log messages that get reported. Whenever a <a href="#func" title="func">log function</a> gets called on a source with a level equal or smaller to the <a href="Src/index.html#val-level" title="Src.level">source's reporting level</a>, the <a href="#val-reporter" title="reporter">current reporter</a>'s field <code>r.report</code> gets called as <code>r.report src level ~over k msgf</code> where:</p><ul><li><code>src</code> is the logging source.</li><li><code>level</code> is the reporting level.</li><li><code>over</code> must be called by the reporter once the logging operation is over from the reporter's perspective. This may happen before or after <code>k</code> is called.</li><li><code>k</code> is the function to invoke to return.</li><li><code>msgf</code> is the <a href="#type-msgf" title="msgf">message formatting function</a> to call.</li></ul><p>See an <a href="#ex1" title="ex1">example</a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-nop_reporter"><a href="#val-nop_reporter" class="anchor"></a><code><span><span class="keyword">val</span> nop_reporter : <a href="#type-reporter">reporter</a></span></code></div><div class="spec-doc"><p><code>nop_reporter</code> is the initial reporter returned by <a href="#val-reporter"><code>reporter</code></a>, it does nothing if a log message gets reported.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-format_reporter"><a href="#val-format_reporter" class="anchor"></a><code><span><span class="keyword">val</span> format_reporter :
<span><span class="optlabel">?pp_header</span>:<span>(<span><a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a> <span class="arrow">&#45;&gt;</span></span> <span><span>(<a href="#type-level">level</a> * <span>string option</span>)</span> <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?app</span>:<a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a> <span class="arrow">&#45;&gt;</span></span>
<span><span class="optlabel">?dst</span>:<a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a> <span class="arrow">&#45;&gt;</span></span>
<span>unit <span class="arrow">&#45;&gt;</span></span>
<a href="#type-reporter">reporter</a></span></code></div><div class="spec-doc"><p><code>format_reporter ~pp_header ~app ~dst ()</code> is a reporter that reports <a href="#type-level.App"><code>App</code></a> level messages on <code>app</code> (defauts to <code>Format.std_formatter</code>) and all other level on <code>dst</code> (defaults to <code>Format.err_formatter</code>).</p><p><code>pp_header</code> determines how message headers are rendered. The default prefixes the program name and renders the header with <a href="#val-pp_header"><code>pp_header</code></a>. Use <a href="../Logs_fmt/index.html#reporter"><code>reporter</code></a> if you want colored headers rendering.</p><p>The reporter does not process or render information about message sources or tags.</p><p><b>Important.</b> This is a synchronous reporter it considers the log operation to be over once the message was formatted and before calling the continuation (see the <a href="#sync" title="sync">note on synchronous logging</a>). In particular if the formatters are backed by channels, it will block until the message has been formatted on the channel before proceeding which may not be suitable in a cooperative concurrency setting like <a href="../../lwt/Lwt/index.html"><code>Lwt</code></a>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-reporter"><a href="#val-reporter" class="anchor"></a><code><span><span class="keyword">val</span> reporter : <span>unit <span class="arrow">&#45;&gt;</span></span> <a href="#type-reporter">reporter</a></span></code></div><div class="spec-doc"><p><code>reporter ()</code> is the current repporter.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set_reporter"><a href="#val-set_reporter" class="anchor"></a><code><span><span class="keyword">val</span> set_reporter : <span><a href="#type-reporter">reporter</a> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>set_reporter r</code> sets the current reporter to <code>r</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-set_reporter_mutex"><a href="#val-set_reporter_mutex" class="anchor"></a><code><span><span class="keyword">val</span> set_reporter_mutex : <span><span class="label">lock</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> <span><span class="label">unlock</span>:<span>(<span>unit <span class="arrow">&#45;&gt;</span></span> unit)</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>set_reporter_mutex ~lock ~unlock</code> sets the mutex primitives used to access the reporter. <code>lock</code> is called before invoking the reporter and <code>unlock</code> after it returns. Initially both <code>lock</code> and <code>unlock</code> are <code>fun () -&gt; ()</code>.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-pp_header"><a href="#val-pp_header" class="anchor"></a><code><span><span class="keyword">val</span> pp_header : <span><a href="../../ocaml/Stdlib/Format/index.html#type-formatter">Stdlib.Format.formatter</a> <span class="arrow">&#45;&gt;</span></span> <span><span>(<a href="#type-level">level</a> * <span>string option</span>)</span> <span class="arrow">&#45;&gt;</span></span> unit</span></code></div><div class="spec-doc"><p><code>pp_header ppf (l, h)</code> prints an unspecified representation of log header <code>h</code> for level <code>l</code>.</p></div></div><h2 id="monitoring"><a href="#monitoring" class="anchor"></a>Logs monitoring</h2><div class="odoc-spec"><div class="spec value anchored" id="val-err_count"><a href="#val-err_count" class="anchor"></a><code><span><span class="keyword">val</span> err_count : <span>unit <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p><code>err_count ()</code> is the number of messages logged with level <code>Error</code> across all sources.</p></div></div><div class="odoc-spec"><div class="spec value anchored" id="val-warn_count"><a href="#val-warn_count" class="anchor"></a><code><span><span class="keyword">val</span> warn_count : <span>unit <span class="arrow">&#45;&gt;</span></span> int</span></code></div><div class="spec-doc"><p><code>warn_count ()</code> is the number of messages logged with level <code>Warning</code> across all sources.</p></div></div><h2 id="basics"><a href="#basics" class="anchor"></a>Basics</h2><h3 id="logging"><a href="#logging" class="anchor"></a>Logging</h3><p>In order to minimize the overhead whenever a log message is not reported, message formatting only occurs on actual message report via the <a href="#type-msgf" title="msgf">message formatting function</a> you provide to log functions. This leads to the following logging structure:</p><pre class="language-ocaml"><code>let k, v = ... in
Logs.err (fun m -&gt; m &quot;invalid kv (%a,%a)&quot; pp_key k pp_val v);
Logs.err (fun m -&gt; m &quot;NO CARRIER&quot;);</code></pre><p>The pattern is quite simple: it is as if you were formatting with a <code>printf</code>-like function except you get this function in the <code>m</code> argument of the function you give to the logging function.</p><p>If you want to abstract a repeated log report it is better to keep the message formatting function structure for the arguments of the messages. Here's how the above examples can be abstracted and invoked:</p><pre class="language-ocaml"><code>let err_invalid_kv args =
Logs.err @@ fun m -&gt;
args (fun k v -&gt; m &quot;invalid kv (%a,%a)&quot; pp_key k pp_val v)
let err_no_carrier args =
Logs.err @@ fun m -&gt; args (m &quot;NO CARRIER&quot;)
let () =
err_invalid_kv (fun args -&gt; args &quot;key&quot; &quot;value&quot;);
err_no_carrier (fun () -&gt; ());
()</code></pre><p>Note that log messages are formatted and hit the reporter only if they have not been filtered out by the current <a href="Src/index.html#val-level" title="Src.level">reporting level</a> of the source you log on. See also the log source and reporting level <a href="#usage" title="usage">usage conventions</a>.</p><h3 id="setupreporter"><a href="#setupreporter" class="anchor"></a>Reporter setup</h3><p>If you are writing an application you must remember to <a href="#val-set_reporter" title="set_reporter">set</a> the reporter before any logging operation takes place otherwise no messages will be reported. For example if you are using the <a href="../Logs_fmt/index.html" title="Logs_fmt">formatter reporter</a>, logging can be setup as follows:</p><pre class="language-ocaml"><code>let main () =
Logs.set_reporter (Logs_fmt.reporter ());
...
exit (if Logs.err_count () &gt; 0 then 1 else 0);
()</code></pre><p>If you have logging code that is performed in the toplevel initialization code of modules (not a good idea) or you depend on (bad) libraries that do so, you must call and link the reporter install code before these initialization bits are being executed otherwise you will miss these messages.</p><p>In multi-threaded programs you likely want to ensure mutual exclusion on reporter access. This can be done by invoking <a href="#val-set_reporter_mutex"><code>Logs.set_reporter_mutex</code></a> with suitable mutual exclusion primitives. If you use OCaml <code>Thread</code>s simply calling <a href="../Logs_threaded/index.html#val-enable"><code>Logs_threaded.enable</code></a> with handle that for you.</p><p>If you need to use multiple reporters in your program see this <a href="#ex2" title="ex2">sample code</a>.</p><p>The documentation of <a href="../Logs_cli/index.html"><code>Logs_cli</code></a> module has a <a href="../Logs_cli/index.html#ex" title="ex">full setup example</a> that includes command line options to control color and log reporting level.</p><p>If you are writing a library you should neither install reporters, nor set the reporting level of sources, nor log on the <a href="#val-default"><code>default</code></a> source or at the <code>App</code> level; follow the <a href="#usage" title="usage">the usage conventions</a>. A library should simply log on another existing source or define its own source like in the example below:</p><pre class="language-ocaml"><code>let src = Logs.Src.create &quot;mylib.network&quot; ~doc:&quot;logs mylib's network events&quot;
module Log = (val Logs.src_log src : Logs.LOG)</code></pre><p>The <code>Log</code> module defines logging functions that are specific to the source <code>src</code>.</p><h2 id="usage"><a href="#usage" class="anchor"></a>Usage conventions</h2><p>A library should never log on the <a href="#val-default"><code>default</code></a> source or at the <code>App</code> level these are reserved for use by the application. It should either create a source for itself or log on the source defined by one of its dependencies. It should also never set the reporting level of the sources it deals with or install reporters since control over this must be left to the application.</p><p>The semantics of <a href="#type-level" title="level">reporting levels</a> should be understood as follows:</p><ul><li><code>App</code>, this level can be used for the standard output or console of an application. It should never be used by libraries.</li><li><code>Error</code>, error condition that prevent the program from running normally.</li><li><code>Warning</code>, suspicious condition that does not prevent the program from running normally but may eventually lead to an error condition.</li><li><code>Info</code>, condition that allows the program <em>user</em> to get a better understanding of what the program is doing.</li><li><code>Debug</code>, condition that allows the program <em>developer</em> to get a better undersanding of what the program is doing.</li></ul><h2 id="sync"><a href="#sync" class="anchor"></a>Note on synchronous logging</h2><p>In synchronous logging, a client call to a log function proceeds only once the reporter has finished the report operation. In <code>Logs</code> this depends both on the reporter and the log functions that the client uses.</p><p>Whenever the client uses a log function that results in a report, it gives the reporter a continuation that defines the result type of the log function and a callback to be called whenever the log operation is over from the reporter's perspective (see <a href="#type-reporter"><code>reporter</code></a>). The typical use of the callback is to unblock the continuation given to the reporter. This is used by <a href="../Logs_lwt/index.html"><code>Logs_lwt</code></a>'s log functions to make sure that the threads they return proceed only once the report is over. In the functions of <a href="#"><code>Logs</code></a> however the callback does nothing as there is no way to block the polymorphic continuation.</p><p>Now considering reporters, at the extreme we have:</p><ul><li>A completely asynchronous reporter. This reporter formats the message in memory and immediately invoke the callback followed by the continuation. This provides no guarantee of persistency in case a crash occurs. All log functions behave asynchronously and return as soon as possible.</li><li>A completely synchronous reporter. This reporter formats the message, persist it, invoke the client callback followed by the continuation. All log functions behave synchronously. An example of such a reporter is <a href="../Logs_fmt/index.html#reporter"><code>reporter</code></a> with formatters baked by channels: when formatting returns the message has been written on the channel.</li></ul><p>However a purely synchronous reporter like <a href="../Logs_fmt/index.html#reporter"><code>reporter</code></a> acting on channels does not play well with <code>Lwt</code>'s cooperative runtime system. It is possible to reuse <a href="../Logs_fmt/index.html#reporter"><code>reporter</code></a> to define a cooperative reporter, see <a href="../Logs_lwt/index.html#report_ex" title="report_ex">this example</a>. However while this reporter makes <a href="../Logs_lwt/index.html"><code>Logs_lwt</code></a>'s log functions synchronous, those of <a href="#"><code>Logs</code></a> behave asynchronously. For now it seems it that this is unfortunately the best we can do if we want to preserve the ability to use <code>Logs</code> with or without cooperative concurency.</p><h2 id="ex1"><a href="#ex1" class="anchor"></a>Example with custom reporter and tags</h2><p>This example uses a <a href="Tag/index.html" title="Tag">tag</a> to attach <code>Mtime</code> time spans in log messages. The custom reporter uses these time spans to format relative timings for runs of a given function. Note that as done below the timings do include logging time.</p><pre class="language-ocaml"><code>let stamp_tag : Mtime.span Logs.Tag.def =
Logs.Tag.def &quot;stamp&quot; ~doc:&quot;Relative monotonic time stamp&quot; Mtime.Span.pp
let stamp c = Logs.Tag.(empty |&gt; add stamp_tag (Mtime_clock.count c))
let run () =
let rec wait n = if n = 0 then () else wait (n - 1) in
let c = Mtime_clock.counter () in
Logs.info (fun m -&gt; m &quot;Starting run&quot;);
let delay1, delay2, delay3 = 10_000, 20_000, 40_000 in
Logs.info (fun m -&gt; m &quot;Start action 1 (%d).&quot; delay1 ~tags:(stamp c));
wait delay1;
Logs.info (fun m -&gt; m &quot;Start action 2 (%d).&quot; delay2 ~tags:(stamp c));
wait delay2;
Logs.info (fun m -&gt; m &quot;Start action 3 (%d).&quot; delay3 ~tags:(stamp c));
wait delay3;
Logs.info (fun m -&gt; m &quot;Done.&quot; ?header:None ~tags:(stamp c));
()
let reporter ppf =
let report src level ~over k msgf =
let k _ = over (); k () in
let with_stamp h tags k ppf fmt =
let stamp = match tags with
| None -&gt; None
| Some tags -&gt; Logs.Tag.find stamp_tag tags
in
let dt = match stamp with None -&gt; 0. | Some s -&gt; Mtime.Span.to_us s in
Format.kfprintf k ppf (&quot;%a[%0+04.0fus] @[&quot; ^^ fmt ^^ &quot;@]@.&quot;)
Logs.pp_header (level, h) dt
in
msgf @@ fun ?header ?tags fmt -&gt; with_stamp header tags k ppf fmt
in
{ Logs.report = report }
let main () =
Logs.set_reporter (reporter (Format.std_formatter));
Logs.set_level (Some Logs.Info);
run ();
run ();
()
let () = main ()</code></pre><p>Here is the standard output of a sample run of the program:</p><pre>[INFO][+000us] Starting run
[INFO][+168us] Start action 1 (10000).
[INFO][+206us] Start action 2 (20000).
[INFO][+243us] Start action 3 (40000).
[INFO][+303us] Done.
[INFO][+000us] Starting run
[INFO][+012us] Start action 1 (10000).
[INFO][+038us] Start action 2 (20000).
[INFO][+074us] Start action 3 (40000).
[INFO][+133us] Done.</pre><h2 id="ex2"><a href="#ex2" class="anchor"></a>Logging to multiple reporters</h2><p>Logging to multiple reporters can be achieved by defining a new reporter that simply forwards to them. The following example combines two reporters:</p><pre class="language-ocaml"><code>let combine r1 r2 =
let report = fun src level ~over k msgf -&gt;
let v = r1.Logs.report src level ~over:(fun () -&gt; ()) k msgf in
r2.Logs.report src level ~over (fun () -&gt; v) msgf
in
{ Logs.report }
let () =
let r1 = Logs.format_reporter () in
let r2 = Logs_fmt.reporter () in
Fmt_tty.setup_std_outputs ();
Logs.set_reporter (combine r1 r2);
Logs.err (fun m -&gt; m &quot;HEY HO!&quot;);
()</code></pre></div></body></html>