197 lines
24 KiB
HTML
197 lines
24 KiB
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
<meta name="generator" content="Doxygen 1.8.13"/>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
<title>clutchlog: Main Page</title>
|
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
<script type="text/javascript" src="dynsections.js"></script>
|
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
|
<script type="text/javascript" src="search/searchdata.js"></script>
|
|
<script type="text/javascript" src="search/search.js"></script>
|
|
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
|
</head>
|
|
<body>
|
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
<div id="titlearea">
|
|
<table cellspacing="0" cellpadding="0">
|
|
<tbody>
|
|
<tr style="height: 56px;">
|
|
<td id="projectalign" style="padding-left: 0.5em;">
|
|
<div id="projectname">clutchlog
|
|
 <span id="projectnumber">0.5.0</span>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!-- end header part -->
|
|
<!-- Generated by Doxygen 1.8.13 -->
|
|
<script type="text/javascript">
|
|
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|
</script>
|
|
<script type="text/javascript" src="menudata.js"></script>
|
|
<script type="text/javascript" src="menu.js"></script>
|
|
<script type="text/javascript">
|
|
$(function() {
|
|
initMenu('',true,false,'search.php','Search');
|
|
$(document).ready(function() { init_search(); });
|
|
});
|
|
</script>
|
|
<div id="main-nav"></div>
|
|
</div><!-- top -->
|
|
<!-- window showing the filter options -->
|
|
<div id="MSearchSelectWindow"
|
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
|
</div>
|
|
|
|
<!-- iframe showing the search results (closed by default) -->
|
|
<div id="MSearchResultsWindow">
|
|
<iframe src="javascript:void(0)" frameborder="0"
|
|
name="MSearchResults" id="MSearchResults">
|
|
</iframe>
|
|
</div>
|
|
|
|
<div class="header">
|
|
<div class="headertitle">
|
|
<div class="title">clutchlog Documentation</div> </div>
|
|
</div><!--header-->
|
|
<div class="contents">
|
|
<div class="toc"><h3>Table of Contents</h3>
|
|
<ul><li class="level1"><a href="#autotoc_md0">Features</a></li>
|
|
<li class="level1"><a href="#autotoc_md1">Example</a></li>
|
|
<li class="level1"><a href="#autotoc_md2">Rationale</a></li>
|
|
<li class="level1"><a href="#autotoc_md3">API documentation</a><ul><li class="level2"><a href="#autotoc_md4">Calls</a></li>
|
|
<li class="level2"><a href="#autotoc_md5">Location filtering</a></li>
|
|
<li class="level2"><a href="#autotoc_md6">Output Configuration</a></li>
|
|
<li class="level2"><a href="#autotoc_md7">Output style</a></li>
|
|
<li class="level2"><a href="#autotoc_md8">Disabled calls</a></li>
|
|
<li class="level2"><a href="#autotoc_md9">Low-level API</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="level1"><a href="#autotoc_md10">Log level semantics</a></li>
|
|
<li class="level1"><a href="#autotoc_md11">Limitations</a></li>
|
|
<li class="level1"><a href="#autotoc_md12">Build and tests</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="textblock"><p><b>Clutchlog is a logging system which targets versatile debugging.</b> <b>It allows to (de)clutch messages for a given: log level, source code location or call stack depth.</b></p>
|
|
<h1><a class="anchor" id="autotoc_md0"></a>
|
|
Features</h1>
|
|
<p>Clutchlog allows to select which log messages will be displayed, based on their locations:</p>
|
|
<ul>
|
|
<li><em>classical log levels</em>: each message has a given detail level and it is displayed if you ask for a at least the same one.</li>
|
|
<li><em>call stack depth</em>: you can ask to display messages within functions which are called up to a given stack depth.</li>
|
|
<li><em>source code location</em>: you can ask to display messages called from given files, functions and line number, all based on regular expressions.</li>
|
|
</ul>
|
|
<p>Additionally, Clutchlog will do its best to allow the compiler to optimize out calls, for instance debug messages in "Release" builds.</p>
|
|
<h1><a class="anchor" id="autotoc_md1"></a>
|
|
Example</h1>
|
|
<p>Adding a message is a simple as calling a macro (which is declutched in Debug build type, when <code>NDEBUG</code> is not defined): </p><div class="fragment"><div class="line">CLUTCHLOG(info, <span class="stringliteral">"matrix size: "</span> << m << <span class="stringliteral">"x"</span> << n);</div></div><!-- fragment --><p>To configure the display, you indicate the three types of locations, for example in your <code>main</code> function: </p><div class="fragment"><div class="line"><span class="keyword">auto</span>& log = <a class="code" href="classclutchlog.html#acfaceb77da01503b432644a3efaee4fa">clutchlog::logger</a>();</div><div class="line">log.depth(2); <span class="comment">// Log functions called from "main" but not below.</span></div><div class="line">log.threshold(clutchlog::level::info); <span class="comment">// Log only "info", "warning", "error" or "critical" messages.</span></div><div class="line">log.file(<span class="stringliteral">"algebra/.*"</span>); <span class="comment">// Will match any file in the "algebra" directory.</span></div><div class="line">log.func(<span class="stringliteral">"(mul|add|sub|div)"</span>); <span class="comment">// Will match "multiply", for instance.</span></div></div><!-- fragment --><p>For more detailled examples, see the "API documentation" section below and the <code>tests</code> directory.</p>
|
|
<h1><a class="anchor" id="autotoc_md2"></a>
|
|
Rationale</h1>
|
|
<p>Most of existing logging systems targets service events storage, like fast queuing of transactions in a round-robin database. Their aim is to provide a simple interface to efficiently store messages somewhere, which is appropriated when you have a well known service running and you want to be able to trace complex users interactions across its states.</p>
|
|
<p>Clutchlog, however, targets the debugging of a (typically single-run) program. While you develop your software, it's common practice to output several detailled informations on the internal states around the feature you are currently programming. However, once the feature is up and running, those detailled informations are only useful if you encounter a bug traversing this specific part.</p>
|
|
<p>While tracing a bug, it is tedious to uncomment old debugging code (and go on the build-test cycle) or to set up a full debugger session which displays all appropriate data (with ad-hoc fancy hooks).</p>
|
|
<p>To solve this problem, Clutchlog allows to disengage your debug log messages in various parts of the program, allowing for the fast tracking of a bug across the execution.</p>
|
|
<h1><a class="anchor" id="autotoc_md3"></a>
|
|
API documentation</h1>
|
|
<h2><a class="anchor" id="autotoc_md4"></a>
|
|
Calls</h2>
|
|
<p>The main entrypoint is the <code>CLUTCHLOG</code> macro, which takes the desired log level and message. The message can be anything which can be output in an <code>ostringstream</code>. </p><div class="fragment"><div class="line"><span class="comment">// Simple string:</span></div><div class="line">CLUTCHLOG(info, <span class="stringliteral">"hello world"</span>);</div><div class="line"></div><div class="line"><span class="comment">// Serialisable variable:</span></div><div class="line"><span class="keywordtype">double</span> value = 0;</div><div class="line">CLUTCHLOG(error, value);</div><div class="line"></div><div class="line"><span class="comment">// passed using inline output stream operators:</span></div><div class="line">CLUTCHLOG(debug, <span class="stringliteral">"hello "</span> << value << <span class="stringliteral">" world"</span>);</div></div><!-- fragment --><p>There is also a macro to dump the content of an iterable within a separate file: <code>CLUTCHDUMP</code>. This function takes care of incrementing a numeric suffix in the file name, if an existing file with this name exists. </p><div class="fragment"><div class="line">std::vector<int> v(10);</div><div class="line">std::generate(v.begin(), v.end(), std::rand);</div><div class="line">CLUTCHLOG(debug, vec, <span class="stringliteral">"test_{n}.dat"</span>);</div><div class="line"><span class="comment">/* Will output in cat "rand_0.dat"</span></div><div class="line"><span class="comment">* # [t-dump] Info in main (at depth 5) @ /home/nojhan/code/clutchlog/tests/t-dump.cpp:22</span></div><div class="line"><span class="comment">* 1804289383</span></div><div class="line"><span class="comment">* 846930886</span></div><div class="line"><span class="comment">* 1681692777</span></div><div class="line"><span class="comment">*/</span></div></div><!-- fragment --><p> Note that if you pass a file name without the <code>{n}</code> tag, the file will be overwritten as is.</p>
|
|
<h2><a class="anchor" id="autotoc_md5"></a>
|
|
Location filtering</h2>
|
|
<p>To configure the global behaviour of the logger, you must first get a reference on its (singleton) instance: </p><div class="fragment"><div class="line"><span class="keyword">auto</span>& log = <a class="code" href="classclutchlog.html#acfaceb77da01503b432644a3efaee4fa">clutchlog::logger</a>();</div></div><!-- fragment --><p>One can configure the location(s) at which messages should actually be logged: </p><div class="fragment"><div class="line">log.depth(3); <span class="comment">// Depth of the call stack, defaults to the maximum possible value.</span></div><div class="line">log.threshold(clutchlog::level::error); <span class="comment">// Log level, defaults to error.</span></div></div><!-- fragment --><p> Current levels are defined in an enumeration as <code><a class="el" href="classclutchlog.html#a10fd25a1b51c8c95bd6d876ce1b4b928" title="Available log levels. ">clutchlog::level</a></code>: </p><div class="fragment"><div class="line"><span class="keyword">enum</span> level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};</div></div><!-- fragment --><p>File, function and line filters are indicated using (ECMAScript) regular expressions: </p><div class="fragment"><div class="line">log.file(<span class="stringliteral">".*"</span>); <span class="comment">// File location, defaults to any.</span></div><div class="line">log.func(<span class="stringliteral">".*"</span>); <span class="comment">// Function location, defaults to any.</span></div><div class="line">log.line(<span class="stringliteral">".*"</span>); <span class="comment">// Line location, defaults to any.</span></div></div><!-- fragment --><p> A shortcut function can be used to filter all at once: </p><div class="fragment"><div class="line">log.location(file, func, line); <span class="comment">// Defaults to any, second and last parameters being optional.</span></div></div><!-- fragment --><p>Strings may be used to set up the threshold, using <code>level_of</code>: </p><div class="fragment"><div class="line">log.threshold( log.level_of(<span class="stringliteral">"XDebug"</span>) ); <span class="comment">// You have to know the exact string.</span></div></div><!-- fragment --><p> Note that the case of the log levels strings matters (see below).</p>
|
|
<h2><a class="anchor" id="autotoc_md6"></a>
|
|
Output Configuration</h2>
|
|
<p>The output stream can be configured using the <code>out</code> method: </p><div class="fragment"><div class="line">log.out(std::clog); <span class="comment">// Defaults to clog.</span></div></div><!-- fragment --><p>The format of the messages can be defined with the <code>format</code> method, passing a string with standardized tags surrounded by <code>{}</code>: </p><div class="fragment"><div class="line">log.format(<span class="stringliteral">"{msg}"</span>);</div></div><!-- fragment --><p> Available tags are:</p>
|
|
<ul>
|
|
<li><code>{msg}</code>: the logged message,</li>
|
|
<li><code>{name}</code>: the name of the current binary,</li>
|
|
<li><code>{level}</code>: the current log level (i.e. <code>Critical</code>, <code>Error</code>, <code>Warning</code>, <code>Progress</code>, <code>Note</code>, <code>Info</code>, <code>Debug</code> or <code>XDebug</code>),</li>
|
|
<li><code>{level_letter}</code>: the first letter of the current log level,</li>
|
|
<li><code>{file}</code>: the current file (absolute path),</li>
|
|
<li><code>{func}</code>: the current function,</li>
|
|
<li><code>{line}</code>: the current line number,</li>
|
|
<li><code>{depth}</code>: the current depth of the call stack,</li>
|
|
<li><code>{depth_marks}</code>: as many chevrons <code>></code> as there is calls in the stack.</li>
|
|
</ul>
|
|
<p>The default log format is <code>"[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"</code>, it can be overriden at compile time by defining the <code>CLUTCHLOG_DEFAULT_FORMAT</code> macro.</p>
|
|
<p>The default format of the comment added with the dump macro is <code>"# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}"</code>. It can be edited with the <code>format_comment</code> method. If it is set to an empty string, then no comment line is added. The default can be modified at compile time with <code>CLUTCHDUMP_DEFAULT_FORMAT</code>. By default, the separator between items in the container is a new line. To change this behaviour, you can change <code>CLUTCHDUMP_DEFAULT_SEP</code> or call the low-level <code>dump</code> method.</p>
|
|
<p>The mark used with the <code>{depth_marks}</code> tag can be configured with the <code>depth_mark</code> method, and its default with the <code>CLUTCHLOG_DEFAULT_DEPTH_MARK</code> macro: </p><div class="fragment"><div class="line">log.depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK); <span class="comment">// Defaults to ">".</span></div></div><!-- fragment --><h2><a class="anchor" id="autotoc_md7"></a>
|
|
Output style</h2>
|
|
<p>The output can be colored differently depending on the log level. </p><div class="fragment"><div class="line"><span class="comment">// Print error messages in bold red:</span></div><div class="line">log.style(clutchlog::level::error, <span class="comment">// First, the log level.</span></div><div class="line"> clutchlog::fmt::fg::red, <span class="comment">// Then the styles, in any order...</span></div><div class="line"> clutchlog::fmt::typo::bold);</div></div><!-- fragment --><p>Or, if you want to declare some semantics beforehand: </p><div class="fragment"><div class="line"><span class="comment">// Print warning messages in bold magenta:</span></div><div class="line"><span class="keyword">using</span> fmt = <a class="code" href="classclutchlog_1_1fmt.html">clutchlog::fmt</a>;</div><div class="line">fmt warn(fmt::fg::magenta, fmt::typo::bold);</div><div class="line">log.style(clutchlog::level::magenta, warn);</div></div><!-- fragment --><p>Using the <code><a class="el" href="classclutchlog_1_1fmt.html" title="Color and style formatter for ANSI terminal escape sequences. ">clutchlog::fmt</a></code> class, you can style:</p>
|
|
<ul>
|
|
<li>the foreground color, passing a <code><a class="el" href="classclutchlog_1_1fmt.html#a4662a3ec3577c6a575a2c734636ed8a0" title="Foreground color codes. ">clutchlog::fmt::fg</a></code>,</li>
|
|
<li>the background color, passing a <code><a class="el" href="classclutchlog_1_1fmt.html#a1cf3e27e4041250ffea0a6d58010da1e" title="Background color codes. ">clutchlog::fmt::bg</a></code>,</li>
|
|
<li>some typographic style, passing a <code><a class="el" href="classclutchlog_1_1fmt.html#a932f47b78fb7b10590d5613a1c4eab89" title="Typographic style codes. ">clutchlog::fmt::typo</a></code>.</li>
|
|
</ul>
|
|
<p>Any of the three arguments may be passed, in any order, if an argument is omitted, it defaults to no color/style.</p>
|
|
<p>Available colors are:</p>
|
|
<ul>
|
|
<li>black,</li>
|
|
<li>red,</li>
|
|
<li>green,</li>
|
|
<li>yellow,</li>
|
|
<li>blue,</li>
|
|
<li>magenta,</li>
|
|
<li>cyan,</li>
|
|
<li>white,</li>
|
|
<li>none.</li>
|
|
</ul>
|
|
<p>Available typographies:</p>
|
|
<ul>
|
|
<li>reset (remove any style),</li>
|
|
<li>bold,</li>
|
|
<li>underline,</li>
|
|
<li>inverse,</li>
|
|
<li>none.</li>
|
|
</ul>
|
|
<p>You may use styling within the format message template itself, to add even more colors: </p><div class="fragment"><div class="line"><span class="keyword">using</span> fmt = <a class="code" href="classclutchlog_1_1fmt.html">clutchlog::fmt</a>;</div><div class="line">std::ostringstream format;</div><div class="line">fmt discreet(fmt::fg::blue);</div><div class="line">format << <span class="stringliteral">"{level}: "</span></div><div class="line"> << discreet(<span class="stringliteral">"{file}:"</span>) <span class="comment">// Used as a function (inserts a reset at the end).</span></div><div class="line"> << fmt(fmt::fg::yellow) << <span class="stringliteral">"{line}"</span> <span class="comment">// Used as a tag (no reset inserted).</span></div><div class="line"> << fmt(fmt::typo::reset) << <span class="stringliteral">" {msg}"</span> << std::endl; <span class="comment">// This is a reset.</span></div><div class="line">log.format(format.str());</div></div><!-- fragment --><p> Note: messages at the "critical", "error" and "warning" log levels are colored by default. You may want to set their style to <code>none</code> if you want to stay in control of inserted colors in the format template.</p>
|
|
<h2><a class="anchor" id="autotoc_md8"></a>
|
|
Disabled calls</h2>
|
|
<p>By default, clutchlog is always enabled if the <code>NDEBUG</code> preprocessor variable is not defined (this variable is set by CMake in build types that differs from <code>Debug</code>).</p>
|
|
<p>You can however force clutchlog to be enabled in any build type by setting the <code>WITH_CLUTCHLOG</code> preprocessor variable.</p>
|
|
<p>When the <code>NDEBUG</code> preprocessor variable is set (e.g. in <code>Release</code> build), clutchlog will do its best to allow the compiler to optimize out any calls for log levels which are under or equal to <code>progress</code>.</p>
|
|
<p>You can change this behavior at compile time by setting the <code>CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG</code> preprocessor variable to the desired maximum log level, for example: </p><div class="fragment"><div class="line"><span class="comment">// Will always allow to log everything even in Release mode.</span></div><div class="line"><span class="preprocessor">#define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::xdebug</span></div></div><!-- fragment --><p>Note that allowing a log level does not mean that it will actually output something. If the configured log level at runtime is lower than the log level of the message, it will still not be printed.</p>
|
|
<p>This behavior intend to remove as many conditional statements as possible when not debugging, without having to use preprocessor guards around calls to clutchlog, thus saving run time at no readability cost.</p>
|
|
<h2><a class="anchor" id="autotoc_md9"></a>
|
|
Low-level API</h2>
|
|
<p>All configuration setters have a getters counterpart, with the same name but taking no parameter, for example: </p><div class="fragment"><div class="line">std::string mark = log.depth_mark();</div></div><!-- fragment --><p>To control more precisely the logging, one can use the low-level <code>log</code> method: </p><div class="fragment"><div class="line">log.log(clutchlog::level::xdebug, <span class="stringliteral">"hello world"</span>, <span class="stringliteral">"main.cpp"</span>, <span class="stringliteral">"main"</span>, 122);</div></div><!-- fragment --><p> A helper macro can helps to fill in the location with the actual one, as seen by the compiler: </p><div class="fragment"><div class="line">log.log(clutchlog::level::xdebug, <span class="stringliteral">"hello world"</span>, CLUTCHLOC);</div></div><!-- fragment --><p> A similar <code>dump</code> method exists: </p><div class="fragment"><div class="line">log.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), CLUTCHLOC, <span class="stringliteral">"dumped_{n}.dat"</span>, <span class="stringliteral">"\n"</span>);</div><div class="line">log.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), <span class="stringliteral">"main.cpp"</span>, <span class="stringliteral">"main"</span>, 122, <span class="stringliteral">"dumped.dat"</span>, <span class="stringliteral">"\n\n"</span>);</div></div><!-- fragment --><h1><a class="anchor" id="autotoc_md10"></a>
|
|
Log level semantics</h1>
|
|
<p>Log levels use a classical semantics for a human skilled in the art, in decreasing order of importance:</p>
|
|
<ul>
|
|
<li><em>Critical</em>: an error which cannot be recovered. For instance, something which will make a server stop right here.</li>
|
|
<li><em>Error</em>: an error which invalidates a function, but may still be recovered. For example, a bad user input which will make a server reset its state, but not crash.</li>
|
|
<li><em>Warning</em>: something that is strange, but is probably legit. For example a default parameter is set because the user forgot to indicate its preference.</li>
|
|
<li><em>Progress</em>: the state at which computation currently is.</li>
|
|
<li><em>Note</em>: some state worth noting to understand what's going on.</li>
|
|
<li><em>Info</em>: any information which would help ensuring that everything is going well.</li>
|
|
<li><em>Debug</em>: data which would help debugging the program if there was a bug later on.</li>
|
|
<li><em>XDebug</em>: debugging information which would be heavy to read.</li>
|
|
</ul>
|
|
<p>Note: the log levels constants are lower case (for example: <code><a class="el" href="classclutchlog.html#a10fd25a1b51c8c95bd6d876ce1b4b928" title="Available log levels. ">clutchlog::level</a>:xdebug</code>), but their string representation is not (e.g. "XDebug", this should be taken into account when using <code>level_of</code>).</p>
|
|
<h1><a class="anchor" id="autotoc_md11"></a>
|
|
Limitations</h1>
|
|
<p>Because the call stack depth and program name access are system-dependent, the features relying on the depth of the call stack and the display of the program name are only available for operating systems having the following headers: <code>execinfo.h</code>, <code>stdlib.h</code> and <code>libgen.h</code> (so far, tested with Linux).</p>
|
|
<p>Some colors/styles may not be supported by some exotic terminal emulators.</p>
|
|
<p>Clutchlog needs <code>C++-17</code> with the <code>filesystem</code> feature. You may need to indicate <code>-std=c++17 -lstdc++fs</code> to your compiler.</p>
|
|
<h1><a class="anchor" id="autotoc_md12"></a>
|
|
Build and tests</h1>
|
|
<p>To use clutchlog, just include its header in your code and either ensure that the <code>NDEBUG</code> preprocessor variable is not set, either define the <code>WITH_CLUTCHLOG</code> preprocessor variable.</p>
|
|
<p>If you're using CMake (or another modern build system), it will unset <code>NDEBUG</code> —and thus enable clutchlog— only for the "Debug" build type, which is usually what you want if you use clutchlog, anyway.</p>
|
|
<p>To build and run the tests, just use a classical CMake workflow: </p><div class="fragment"><div class="line">mkdir build</div><div class="line">cd build</div><div class="line">cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_CLUTCHLOG=ON ..</div><div class="line">make</div><div class="line">ctest</div></div><!-- fragment --><p>There's a script which tests all the build types combinations: <code>./build_all.sh</code>. </p>
|
|
</div></div><!-- contents -->
|
|
<!-- start footer part -->
|
|
<hr class="footer"/><address class="footer"><small>
|
|
Generated by  <a href="http://www.doxygen.org/index.html">
|
|
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
|
</a> 1.8.13
|
|
</small></address>
|
|
</body>
|
|
</html>
|