{"id":16615183,"url":"https://github.com/nojhan/clutchlog","last_synced_at":"2025-03-21T14:31:24.501Z","repository":{"id":48535325,"uuid":"289645477","full_name":"nojhan/clutchlog","owner":"nojhan","description":"C++ \"spatial\" logging system which targets versatile, (de)clutchable, _debugging_, in a single header.","archived":false,"fork":false,"pushed_at":"2024-10-01T07:49:10.000Z","size":4981,"stargazers_count":14,"open_issues_count":3,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-18T02:11:26.717Z","etag":null,"topics":["cpp","cpp-library","debugging","logging","logging-library","spatial-logging"],"latest_commit_sha":null,"homepage":"https://nojhan.github.io/clutchlog/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nojhan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-23T08:25:23.000Z","updated_at":"2024-10-01T07:49:13.000Z","dependencies_parsed_at":"2024-09-10T15:58:35.915Z","dependency_job_id":"b9874176-d95b-4b41-952b-3160c9aea21d","html_url":"https://github.com/nojhan/clutchlog","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nojhan%2Fclutchlog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nojhan%2Fclutchlog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nojhan%2Fclutchlog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nojhan%2Fclutchlog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nojhan","download_url":"https://codeload.github.com/nojhan/clutchlog/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244815179,"owners_count":20514910,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp-library","debugging","logging","logging-library","spatial-logging"],"created_at":"2024-10-12T02:08:50.172Z","updated_at":"2025-03-21T14:31:23.865Z","avatar_url":"https://github.com/nojhan.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"Clutchlog — versatile (de)clutchable spatial logging\n====================================================\n\n**Clutchlog is a *spatial* logging system that targets versatile *debugging*.**\n**It allows to (de)clutch messages for a given: log level, source code location or call stack depth.**\n\n- [Project page on Github](https://github.com/nojhan/clutchlog)\n- [Documentation](https://nojhan.github.io/clutchlog/)\n\n\u003cp align=\"center\"\u003e\n    \u003cimg\n        alt\"Clutchlog logo\"\n        src=\"https://raw.githubusercontent.com/nojhan/clutchlog/master/docs/clutchlog_logo.svg\"\n        width=\"400\"\n    /\u003e\n\u003c/p\u003e\n\n[TOC]\n\nFeatures\n--------\n\nClutchlog allows to select which log messages will be displayed, based on their locations:\n\n- **Classical log levels**: each message has a given detail level and it is displayed if you ask for a at least the same\n  one.\n- **Call stack depth**: you can ask to display messages within functions that are called up to a given stack depth.\n- **Source code location**: you can ask to display messages called from given files, functions and line number, all based on\n  regular expressions.\n\nAdditionally, Clutchlog will do its best to allow the compiler to optimize out calls,\nfor instance debug messages in \"Release\" builds.\n\nAdditional features:\n\n- **Templated log format**, to easily design your own format.\n- **Powerful Styling**. Clutchlog comes with many options to color its output, for example by using colors with a semantic meaning, so that visually parse the logs is easy.\n- **Macro to dump the content of a container in a file** with automatic naming (yes, it is useful for fast debugging).\n- **Generic clutching wrapper**, to wrap any function call. Useful to (de)clutch *asserts* for example.\n\n\nExample\n-------\n\nAdding a message is a simple as calling a macro (which is declutched in Debug build type, when `NDEBUG` is not defined):\n```cpp\nCLUTCHLOG(info, \"matrix size: \" \u003c\u003c m \u003c\u003c \"x\" \u003c\u003c n);\n```\n\nTo configure the display, you indicate the three types of locations, for example in your `main` function:\n```cpp\n    auto\u0026 log = clutchlog::logger();\n    log.depth(2);                          // Log functions called from \"main\" but not below.\n    log.threshold(\"Info\"); // Log only \"info\", \"warning\", \"error\" or \"critical\" messages.\n    log.file(\"algebra/.*\");                // Will match any file in the \"algebra\" directory.\n    log.func(\"(mul|add|sub|div)\");         // Will match \"multiply\", for instance.\n```\n\nExample of a real-life log session (as seen in the [frictionlesser](https://github.com/jdreo/frictionlesser) software):\n\n![A log screen capture with full details, showing colored messages and location.](https://raw.githubusercontent.com/nojhan/clutchlog/master/demo.png)\n\nDemo showing fancy styling:\n\n![A log screen capture showing fancy coloring of text lines.](https://raw.githubusercontent.com/nojhan/clutchlog/master/demo-extra.png)\n\nFor more detailled examples, see the \"Usage\" sections below and the `tests` directory.\n\n\nRationale\n---------\n\nMost of existing logging systems targets service events storage, like fast queuing of transactions in a round-robin\ndatabase.\nTheir aim is to provide a simple interface to efficiently store messages somewhere, which is appropriated when you have\na well known service running and you want to be able to trace complex users interactions across its states.\n\nClutchlog, however, targets the *debugging* of a (typically single-run) program.\nWhile you develop your software, it's common practice to output several detailled informations on the internal states\naround the feature you are currently programming.\nHowever, once the feature is up and running, those detailled informations are only useful if you encounter a bug\ntraversing this specific part.\n\nWhile tracing a bug, it is tedious to uncomment old debugging code (and go on the build-test cycle)\nor to set up a full debugger session that displays all appropriate data (with ad-hoc fancy hooks).\n\nTo solve this problem, Clutchlog allows to disengage *at runtime* your debug log messages in various parts of the program,\nallowing for the fast tracking of a bug across the execution.\n\n\nBasic Usage\n===========\n\n\nCalls\n-----\n\nThe main entrypoint is the `CLUTCHLOG` macro, which takes the desired log level and message.\nThe message can be anything that can be output in an `ostringstream`.\n```cpp\n// Simple string:\nCLUTCHLOG(info, \"hello world\");\n\n// Serialisable variable:\ndouble value = 0;\nCLUTCHLOG(error, value);\n\n// passed using inline output stream operators:\nCLUTCHLOG(debug, \"hello \" \u003c\u003c value \u003c\u003c \" world\");\n```\n\nThere is also a macro to dump the content of an iterable within a separate file: `CLUTCHDUMP`.\nThis function takes care of incrementing a numeric suffix in the file name,\nif an existing file with this name exists.\n```cpp\nstd::vector\u003cint\u003e v(10);\nstd::generate(v.begin(), v.end(), std::rand);\nCLUTCHDUMP(debug, vec, \"test_{n}.dat\");\n/* Will output in cat \"rand_0.dat\"\n* # [t-dump] Info in main (at depth 5) @ /home/nojhan/code/clutchlog/tests/t-dump.cpp:22\n* 1804289383\n* 846930886\n* 1681692777\n*/\n```\nNote that if you pass a file name without the `{n}` tag, the file will be overwritten as is.\n\n\nLog level semantics\n-------------------\n\nLog levels use a classical semantics for a human skilled in the art, in decreasing order of importance:\n\n- *Critical*: an error that cannot be recovered. For instance, something which will make a server stop right here.\n- *Error*: an error that invalidates a function, but may still be recovered. For example, a bad user input that will make a server reset its state, but not crash.\n- *Warning*: something that is strange, but is probably legit. For example a default parameter is set because the user forgot to indicate its preference.\n- *Progress*: the state at which computation currently is.\n- *Note*: some state worth noting to understand what's going on.\n- *Info*: any information that would help ensuring that everything is going well.\n- *Debug*: data that would help debugging the program if there was a bug later on.\n- *XDebug*: debugging information that would be heavy to read.\n\nNote: the log levels constants are lower case (for example: `clutchlog::level::xdebug`), but their string representation is not (e.g. \"XDebug\", this should be taken into account when using `clutchlog::threshold` or `clutchlog::level_of`).\n\n\nLocation filtering\n------------------\n\nTo configure the global behaviour of the logger, you must first get a reference on its (singleton) instance:\n```cpp\nauto\u0026 log = clutchlog::logger();\n```\n\nOne can configure the location(s) at which messages should actually be logged:\n```cpp\nlog.depth(3); // Depth of the call stack, defaults to the maximum possible value.\nlog.threshold(clutchlog::level::error); // Log level, defaults to error.\n```\nCurrent levels are defined in an enumeration as `clutchlog::level`:\n```cpp\nenum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7};\n```\n\nFile, function and line filters are indicated using (ECMAScript) regular expressions:\n```cpp\nlog.file(\".*\"); // File location, defaults to any.\nlog.func(\".*\"); // Function location, defaults to any.\nlog.line(\".*\"); // Line location, defaults to any.\n```\nA shortcut function can be used to filter all at once:\n```cpp\nlog.location(file, func, line); // Defaults to any, second and last parameters being optional.\n```\n\nStrings may be used to set up the threshold:\n```cpp\nlog.threshold(\"Error\"); // You have to know the exact —case sensitive— string.\n```\nNote that the case of the log levels strings matters (see below).\n\n\nOutput Configuration\n--------------------\n\nThe output stream can be configured using the `clutchlog::out` method:\n```cpp\nlog.out(std::clog); // Defaults to clog.\n```\n\nThe format of the messages can be defined with the `clutchlog::format` method, passing a string with standardized tags surrounded by `{}`:\n```cpp\nlog.format(\"{msg}\");\n```\nAvailable tags are:\n\n- `{msg}`: the logged message,\n- `{level}`: the current log level (i.e. `Critical`, `Error`, `Warning`, `Progress`, `Note`, `Info`, `Debug` or `XDebug`),\n- `{level_letter}`: the first letter of the current log level,\n- `{level_short}`: the current log level, printed in only four letters,\n- `{file}`: the current file name,\n- `{func}`: the current function,\n- `{line}`: the current line number,\n- `{level_fmt}`: the style of the current level (i.e. configured with `clutchlog::style`),\n- `{filehash_fmt}`: a style for file names, which is value-dependant (see `clutchlog::filehash_styles`),\n- `{funchash_fmt}`: a style for function names, which is value-dependant (see `clutchlog::funchash_styles`).\n\nSome tags are only available on POSIX operating systems as of now:\n- `{name}`: the name of the current binary,\n- `{depth}`: the current depth of the call stack,\n- `{depth_marks}`: as many chevrons `\u003e` as there is calls in the stack,\n- `{depth_fmt}`: a style depending on the current depth value (see `clutchlog::depth_styles`),\n- `{hfill}`: Inserts a sequence of characters that will stretch to fill the space available\n  in the current terminal, between the rightmost and leftmost part of the log message.\n\n\n### Log Format\n\nThe default log format is `\"[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\\n\"`,\nit can be overriden at compile time by defining the `CLUTCHLOG_DEFAULT_FORMAT` macro.\n\nBy default, and if `CLUTCHLOG_DEFAULT_FORMAT` is not defined,\nclutchlog will not put the location-related tags in the message formats\n(i.e. `{name}`, `{func}`, and `{line}`) when not in Debug builds.\n\n\nOutput Styling\n--------------\n\nOutput lines can be styled differently depending on their content.\n\nFor example, output lines can be colored differently depending on the log level.\n```cpp\n// Print error messages in bold red:\nlog.style(level::error, // First, the log level.\n    fmt::fg::red,       // Then the styles, in any order...\n    fmt::typo::bold);\n```\n\nOr, if you want to declare some semantics beforehand:\n```cpp\n// Print warning messages in bold magenta:\nusing fmt = clutchlog::fmt;\nfmt warn(fmt::fg::magenta, fmt::typo::bold);\nlog.style(level::warning, warn);\n```\n\nNote: this inserts a style marker at the very beginning of the line.\nIf you add other styles later on the line, they will take precedence.\n\nColors can be specified in several different ways.\nThe ANSI color mode will be automatically detected,\ndepending on the types of arguments passed to styling functions:\n- named tags from `clutchlog::fmt::fg` or `clutchlog::fmt::bg` will encode a 16-colors mode,\n- integers will encode a 256-colors mode,\n- numeric triplets or web hex strings will encode a 16 million (\"true\") colors mode,\n- `clutchlog::fg::none` and `clutchlog::bg::none` can be passed in all modes.\n\nFor example, all the following lines encode\na bright red foreground for the critical level\n(see the \"Colors\" section below):\n```cpp\n    log.style(level:critical,\n        fmt::fg::red); // 16-colors mode.\n    log.style(level:critical,\n        255); // 256-colors mode.\n    log.style(level:critical,\n        255,0,0); // 16M-colors mode.\n    log.style(level:critical,\n        \"#ff0000\"); // 16M-colors mode again.\n```\n\nYou may use styling within the format message template itself, to add even more colors:\n```cpp\nusing fmt = clutchlog::fmt;\nstd::ostringstream format;\nfmt discreet(fmt::fg::blue);\nformat \u003c\u003c \"{level}: \"\n    \u003c\u003c discreet(\"{file}:\") // Used as a function (inserts a reset at the end).\n    \u003c\u003c fmt(fmt::fg::yellow) \u003c\u003c \"{line}\" // Used as a tag (no reset inserted).\n    \u003c\u003c fmt(fmt::typo::reset) \u003c\u003c \" {msg}\" \u003c\u003c std::endl; // This is a reset.\nlog.format(format.str());\n```\nNote: messages at the \"critical\", \"error\" and \"warning\" log levels are colored by default.\nYou may want to set their style to `none` if you want to stay in control of inserted colors in the format template.\n\nThe horizontal filling line (the `{hfill}` tag) can be configured separately with `clutchlog::hfill_style`,\nfor example:\n```cpp\n    log.hfill_style(fmt::fg::black);\n```\nNote: this will actually reset any styling after the hfill,\ndisabling any style you would have set for the whole message using `clutchlog::format`\nfor the remaining of the message.\n\n\n### Typographic Style\n\nAvailable typographies:\n\n- reset (remove any style),\n- bold,\n- underline,\n- inverse,\n- none.\n\nTypographic styles are always passed with the named tag\n(see `clutchlog::fmt::typo`), whatever the color mode.\n\n\n### Colors\n\n#### 16-colors mode\n\nUsing the `clutchlog::fmt` class, you can style:\n\n- the foreground color, passing a `clutchlog::fmt::fg`,\n- the background color, passing a `clutchlog::fmt::bg`.\n\nIn 16-colors mode, any of the arguments may be passed, in any order,\nif an argument is omitted, it defaults to no color/style.\n\nAvailable colors are:\n\n- black,\n- red,\n- green,\n- yellow,\n- blue,\n- magenta,\n- cyan,\n- white,\n- bright_black,\n- bright_red,\n- bright_green,\n- bright_yellow,\n- bright_blue,\n- bright_magenta,\n- bright_cyan,\n- bright_white,\n- none.\n\nNote: some terminals allow the user to configure the actual encoding of\nthose colors. You may thus notice some difference with the expected rendering\nof the same colors encoded in the other modes. Use the other color modes if you\nwant to fully control the actual color rendering.\n\n\n#### 256-colors mode\n\nFor 256-colors mode, colors are expected to be passed as integers in [-1,255]\nor the `fg::none` and `bg::none` tags.\n\nIn 256-colors mode, if you want to only encode the background color,\nyou cannot just omit the foreground color,\nyou have to bass a `fg::none` tag as first argument.\n\n```cpp\nlog.style(level::info, fg::none, 52); // No color over dark red.\nlog.style(level::info, fg::none, 52, typo::bold); // No color over bold dark red.\n```\n\n\n#### 16 million colors mode (RGB)\n\nFor 16M-colors mode, colors can be encoded as:\n- three integer arguments,\n- a \"web color\" hexadecimal triplet string, starting with a leading number sign (e.g. \"#0055ff\").\n- the `fg::none` and `bg::none` tags.\n\nIn 16M-colors mode, if you want to only encode the background color,\nyou cannot just omit the foreground color,\nyou have to pass a `fg::none` tag as first argument.\n\n```cpp\nlog.style(level::info, fg::none, 100,0,0); // No color over dark red.\nlog.style(level::info, fg::none, 100,0,0, typo::bold); // No color over bold dark red.\n```\n\n\n### Value-dependant Format Tags\n\nSome tags can be used to change the style of (part of) the output line,\n\n*depending on its content*.\nThe `{filehash_fmt}` and `{funchash_fmt}` will introduce a styling sequence\nwhich depends on the current file name, and function name respectively.\nThe chosen style is chosen at random among the candidate ones,\nbut will always be the same for each value.\n\nThe set of candidate styles can be configured with `clutchlog::filehash_styles`\nand `clutchlog::funchash_styles`, which both take a vector of `clutchlog::fmt`\nobjects as argument:\n```cpp\n// Either one or the other color for filenames:\nlog.filehash_styles( { fmt(fg::red),   fmt(fg::yellow) } );\n// This would fix the function name style to a single one:\nlog.funchash_styles( { fmt(typo::bold) } );\n// Works with any `fmt` constructor\n// (here, shades of blues in 256-colors mode):\nlog.funchash_styles( { fmt(33), fmt(27), fmt(39), fmt(45) } );\n```\n\nThe same idea applies to `{depth_fmt}`.\nHowever, if `clutchlog::depth_styles` is configured,\nthen the styles are chosen *in order*.\nThat is, a depth of 1 would lead to the first style being chosen.\nIf the current depth of the stack is larger than the number of configured\nstyles, then the last one is used.\nFor example:\n```cpp\n// Increasingly darker depth level colors (using the 256-colors mode).\nlog.depth_styles({ fmt(255), fmt(250), fmt(245), fmt(240), fmt(235) });\n```\n\nIf `clutchlog::depth_styles` is set, the `{depth_marks}` template tag will render\nwith each mark having each own style corresponding to its depth.\nNote: a depth of zero showing no mark, the first style in the list is never applied to marks.\n\n\nAdvanced Usage\n==============\n\nMore Output Configuration\n-------------------------\n\n### Dump Format\n\nThe default format of the first line of comment added with the dump macro is\n`\"# [{name}] {level} in {func} (at depth {depth}) @ {file}:{line}\"`.\nIt can be edited with the `format_comment` method.\nIf it is set to an empty string, then no comment line is added.\nThe default can be modified at compile time with `CLUTCHDUMP_DEFAULT_FORMAT`.\n\nBy default, the separator between items in the container is a new line.\nTo change this behaviour, you can change `CLUTCHDUMP_DEFAULT_SEP` or\ncall the low-level `dump` method.\n\nBy default, and if `CLUTCHDUMP_DEFAULT_FORMAT` is not defined,\nclutchlog will not put the location-related tags in the message formats\n(i.e. `{file}` and `{line}`) when not in Debug builds.\n\n\n### Stack Depth Mark\n\nThe mark used with the `{depth_marks}` tag can be configured with the `clutchlog::depth_mark` method,\nand its default with the `CLUTCHLOG_DEFAULT_DEPTH_MARK` macro:\n```cpp\nlog.depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK); // Defaults to \"\u003e\".\n```\n\n### Horizontal Filling\n\nThe character used with the `{hfill}` tag can be configured wth the `clutchlog::hfill_mark` method,\nand its default with the `CLUTCHLOG_DEFAULT_HFILL_MARK` macro:\n```cpp\nlog.hfill_mark(CLUTCHLOG_DEFAULT_HFILL_MARK); // Defaults to '.'.\n```\n\nClutchlog measures the width of the *standard error* channel.\nIf it is redirected, it may be measured as very large (or very small).\nThus, the `clutchlog::hfill_min` `clutchlog::hfill_max` accessors allow\nto set a minimum and a maximum width (in number of characters).\n```cpp\nlog.hfill_max(CLUTCHLOG_DEFAULT_HFILL_MAX); // Defaults to 300.\nlog.hfill_min(CLUTCHLOG_DEFAULT_HFILL_MIN); // Defaults to 150.\n```\nNote: clutchlog will use the measured width, unless\nit goes out of `[clutchlog::hfill_min,clutchlog::hfill_max]`,\nin which case it will be caped to those bounds.\n\n\n### Stack Depth\n\nBy default, clutchlog removes 5 levels of the calls stack, so that your `main`\nentrypoint corresponds to a depth of zero.\nYou can change this behaviour by defining the `CLUTCHLOG_STRIP_CALLS` macro,\nor calling `clutchlog::strip_calls`.\n```cpp\nlog.strip_calls(CLUTCHLOG_STRIP_CALLS); // Defaults to 5.\n```\n\n\n### Filename\n\nBy default, the `{file}` template tag is rendered as the absolute path\n(which is usualy handy if your terminal detects paths\nand allows to run a command on click).\n\nYou can change this behavior to display shorter names, using `clutchlog::filename`,\nand passing one of the following the shortening method:\n- `clutchlog::filename::base`: the file name itself,\n- `clutchlog::filename::dir`: the name of the single last directory containing the file,\n- `clutchlog::filename::dirbase`: the last directory and the file names,\n- `clutchlog::filename::stem`: the file name without its extension,\n- `clutchlog::filename::dirstem`: the last directory and the file without extension.\n- `clutchlog::filename::path`: the absolute path (the default).\n\nExample:\n```cpp\nlog.filename(clutchlog::filename::path)    // /home/nojhan/code/clutchlog/tests/t-filename.cpp\nlog.filename(clutchlog::filename::base)    // t-filename.cpp\nlog.filename(clutchlog::filename::dir)     // tests\nlog.filename(clutchlog::filename::dirbase) // tests/t-filename.cpp\nlog.filename(clutchlog::filename::stem)    // t-filename\nlog.filename(clutchlog::filename::dirstem) // tests/t-filename\n```\n\n\nDisabled calls\n--------------\n\nBy default, clutchlog is always enabled if the `NDEBUG` preprocessor variable is not defined\n(this variable is set by CMake in build types that differs from `Debug`).\n\nYou can however force clutchlog to be enabled in any build type\nby setting the `WITH_CLUTCHLOG` preprocessor variable.\n\nWhen the `NDEBUG` preprocessor variable is set (e.g. in `Release` build),\nclutchlog will do its best to allow the compiler to optimize out any calls\nfor log levels that are under `progress`.\n\nYou can change this behavior at compile time by setting the\n`CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG` preprocessor variable\nto the desired maximum log level, for example:\n```cpp\n// Will always allow to log everything even in Release mode.\n#define CLUTCHLOG_DEFAULT_DEPTH_BUILT_NODEBUG clutchlog::level::xdebug\n```\n\nNote that allowing a log level does not mean that it will actually output something.\nIf the configured log level at runtime is lower than the log level of the message,\nit will still not be printed.\n\nThis behavior intend to remove as many conditional statements as possible\nwhen not debugging, without having to use preprocessor guards around\ncalls to clutchlog, thus saving run time at no readability cost.\n\n\nLow-level API\n-------------\n\nAll configuration setters have a getters counterpart, with the same name but taking no parameter,\nfor example:\n```cpp\nstd::string mark = log.depth_mark();\n```\n\nTo control more precisely the logging, one can use the low-level `clutchlog::log` method:\n```cpp\nlog.log(clutchlog::level::xdebug, \"hello world\", \"main.cpp\", \"main\", 122);\n```\nA helper macro can helps to fill in the location with the actual one, as seen by the compiler:\n```cpp\nlog.log(clutchlog::level::xdebug, \"hello world\", CLUTCHLOC);\n```\nA similar `dump` method exists:\n```cpp\nlog.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), CLUTCHLOC, \"dumped_{n}.dat\", \"\\n\");\nlog.dump(clutchlog::level::xdebug, cont.begin(), cont.end(), \"main.cpp\", \"main\", 122, \"dumped.dat\", \"\\n\\n\");\n```\n\nYou can access the identifier of log levels with `clutchlog::level_of`:\n```cpp\nlog.threshold( log.level_of(\"XDebug\") ); // You have to know the exact string.\n```\n\n\n(De)clutch any function call\n----------------------------\n\nThe `CLUTHFUNC` macro allows to wrap any function within the current logger.\n\nFor instance, this can be useful if you want to (de)clutch calls to `assert`s.\nTo do that, just declare your own macro:\n```cpp\n#define ASSERT(...) { CLUTCHFUNC(error, assert, __VA_ARGS__) }\n```\nThus, any call like `ASSERT(x \u003e 3);` will be declutchable\nwith the same configuration than a call to `CLUTCHLOG`.\n\n\n(De)clutch any code section\n---------------------------\n\nThe `CLUTCHCODE` macro allows to wrap any code within the current logger.\n\nFor instance:\n```cpp\nCLUTCHCODE(info,\n    std::clog \u003c\u003c \"We are clutched!\\n\";\n);\n```\n\n\nManually Increase Stack Depth\n-----------------------------\n\nYou may want to manually increase the stack depth for a given logging call,\nfor instance to subdivise a single function in sections.\nTo do so, you can use the `CLUTCHLOGD` macro, which take an additional argument,\nin the form of the number of additional (fake) stack depths you want:\n```cpp\nCLUTCHLOG( debug, \"Call\"); // Regular macro.\nCLUTCHLOGD(debug, \"Sub call\", 1); // Adds an additional (fake) stack depth.\nCLUTCHLOGD(debug, \"Sub sub!\", 2); // Adds two additional (fake) stack depths.\n```\nThat way, the depth will be rendered to the actual depth, plus the additional\ndepth delta. Note that the displayed function will stay the same. Any filtering\non the stack depth will take into account the fake depth and not the real one.\n\n\nExamples\n========\n\nHere what you would do to setup clutchlog with the default configuration:\n```cpp\n    auto\u0026 log = clutchlog::logger();\n    log.out(std::clog);\n    // Location filtering.\n    log.depth(std::numeric_limits\u003csize_t\u003e::max());\n    log.threshold(\"Error\");\n    log.file(\".*\");\n    log.func(\".*\");\n    log.line(\".*\");\n    // Colors of the 3 firsts levels.\n    log.style(clutchlog::level::critical, clutchlog::fmt(\n            clutchlog::fmt::fg::red,\n            clutchlog::fmt::typo::underline);\n    log.style(clutchlog::level::error, clutchlog::fmt(\n            clutchlog::fmt::fg::red,\n            clutchlog::fmt::typo::bold);\n    log.style(clutchlog::level::warning, clutchlog::fmt(\n            clutchlog::fmt::fg::magenta,\n            clutchlog::fmt::typo::bold);\n    // Assuming you are on a POSIX system.\n    log.format(\"[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\\n\");\n    log.depth_mark(\"\u003e\");\n    log.strip_calls(5);\n    log.hfill_char('.');\n    log.hfill_max(300);\n    log.hfill_style(clutchlog::fmt::fg::none);\n```\n\nAnd here are all the functions you may call to log something:\n```cpp\n    // Basic message.\n    CLUTCHLOG(debug, \"x = \" \u003c\u003c x);\n\n    // Any code section.\n    CLUTCHCODE(xdebug,\n        if(x \u003c 0) std::cerr \u003c\u003c \"WTF?\" \u003c\u003c std::endl;\n    );\n\n    // Container to a file.\n    CLUTCHDUMP(note, my_vector, \"my_vector.dat\");\n\n    // Container to a numbered file.\n    CLUTCHDUMP(note, my_list, \"my_list_{n}.dat\");\n\n    // Function call.\n    CLUTCHFUNC(warning, my_check, x, y); // Calls: my_check(x,y);\n\n    // Declutchable asserts.\n    #define ASSERT(...) { CLUTCHFUNC(critical, assert, __VA_ARGS__) }\n    ASSERT(x\u003e0);\n```\n\nHere what you would do to setup clutchlog with the default configuration\nusing 16M-colors mode:\n```cpp\n    auto\u0026 log = clutchlog::logger();\n    log.out(std::clog);\n    // Location filtering.\n    log.depth(std::numeric_limits\u003csize_t\u003e::max());\n    log.threshold(\"Error\");\n    log.file(\".*\");\n    log.func(\".*\");\n    log.line(\".*\");\n    // Colors of the 3 firsts levels.\n    log.style(clutchlog::level::critical, clutchlog::fmt(\n            \"#ff0000\",\n            clutchlog::fmt::typo::underline);\n    log.style(clutchlog::level::error, clutchlog::fmt(\n            \"#ff0000\",\n            clutchlog::fmt::typo::bold);\n    log.style(clutchlog::level::warning, clutchlog::fmt(\n            \"#ff00ff\",\n            clutchlog::fmt::typo::bold);\n    // Assuming you are on a POSIX system.\n    log.format(\"[{name}] {level_letter}:{depth_marks} {msg} {hfill} {func} @ {file}:{line}\\n\");\n    log.depth_mark(\"\u003e\");\n    log.strip_calls(5);\n    log.hfill_char('.');\n    log.hfill_max(300);\n    log.hfill_style(clutchlog::fmt::fg::none);\n```\n\n\nLimitations\n===========\n\n### System-dependent stack depth\n\nBecause access to the call stack depth and program name are system-dependent,\nthe features relying on the depth of the call stack and the display of the program name\nare only available for operating systems having the following headers:\n`execinfo.h`, `stdlib.h` and `libgen.h` (so far, tested with Linux).\n\nClutchlog sets the `CLUTCHLOG_HAVE_UNIX_SYSINFO` to 1 if the headers are\navailable, and to 0 if they are not.\nYou can make portable code using something like:\n```cpp\n#if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1\n    log.depth( x );\n#endif \n```\n\n\n### System-dependent horizontal fill\n\nBecause access to the current terminal width is system-dependent,\nthe `{hfill}` format tag feature is only available for operating systems having the following headers:\n`sys/ioctl.h`, `stdio.h` and `unistd.h` (so far, tested with Linux).\n\nClutchlog sets the `CLUTCHLOG_HAVE_UNIX_SYSIOCTL` to 1 if the headers are\navailable, and to 0 if they are not.\nYou can make portable code using something like:\n```cpp\n#if CLUTCHLOG_HAVE_UNIX_SYSIOCTL == 1\n    log.hfill_mark( '_' );\n#endif \n```\n\nIf you use unicode characters in your template, the horizontal width will not be\ncomputed properly, resulting in incorrectly right-aligned lines.\nSolving this would require the use of third-party libraries, making portability\nmore difficult.\n\n\n### Dependencies\n\nSome colors/styles may not be supported by some exotic terminal emulators.\n\nClutchlog needs `C++-17` with the `filesystem` feature.\nYou may need to indicate `-std=c++17 -lstdc++fs` to some compilers.\n\n\n### Variable names within the CLUTCHLOG macro\n\nCalling the `CLUTCHLOG` macro with a message using a variable named `clutchlog__msg` will end in\nan error.\n\n\n### Features\n\nWhat Clutchlog do not provide at the moment (but may in a near future):\n\n- Super fast log writing.\n- Thread safety.\n\nWhat Clutchlog will most certainly never provide:\n\n- Round-robin log managers.\n- Duplicated messages management.\n- External output systems (only allow output stream, you can still do the proxy yourself).\n- External error handlers (not my job, come on).\n- Automatic argument parser (please, use a dedicated lib).\n- Signal handling (WTF would you do that, anyway?).\n\n\nBuild and tests\n===============\n\nTo use clutchlog, just include its header in your code\nand either ensure that the `NDEBUG` preprocessor variable is not set,\neither define the `WITH_CLUTCHLOG` preprocessor variable.\n\nIf you're using CMake (or another modern build system),\nit will unset `NDEBUG` —and thus enable clutchlog—\nonly for the \"Debug\" build type,\nwhich is usually what you want if you use clutchlog, anyway.\n\nTo build and run the tests, just use a classical CMake workflow:\n```sh\nmkdir build\ncd build\ncmake -DCMAKE_BUILD_TYPE=Debug -DWITH_CLUTCHLOG=ON ..\nmake\nctest\n```\n\nThere's a script that tests all the build types combinations: `./build_all.sh`.\n\n\nUsage as a Git submodule\n========================\n\nIf you are using Git and CMake, it is easy to include Clutchlog as a dependency.\n\nFirst, add Clutchlog as a submodule of your repository:\n```sh\ngit submodule add git@github.com:nojhan/clutchlog.git external/\ngit commit -m \"Add clutchlog as a submodule dependency\"\n```\n\nThen, in your `CMakeLists.txt` file, add:\n```cmake\ninclude_directories(external/clutchlog)\n```\n\nAnd that's it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnojhan%2Fclutchlog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnojhan%2Fclutchlog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnojhan%2Fclutchlog/lists"}