diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a910a6..49ac6fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,17 +5,13 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) -project("clutchlog") +project("clutchlog" + VERSION 0.5.0 + DESCRIPTION "A logging system which targets versatile debugging") enable_language(CXX) # C++ set(CMAKE_CXX_STANDARD 17) -## Current version -set(VERSION_MAJOR 0 CACHE STRING "Major version number" ) -set(VERSION_MINOR 3 CACHE STRING "Minor version number" ) -set(VERSION_PATCH 0 CACHE STRING "Patch version number" ) -mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH) - set(CMAKE_CXX_STANDARD_LIBRARIES -lstdc++fs) ###################################################################################### @@ -35,10 +31,30 @@ if(WITH_CLUTCHLOG) add_definitions(-DWITH_CLUTCHLOG) endif() +# Do not build documentation by default. +option(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" OFF) + ###################################################################################### # Start building ###################################################################################### +# Doxygen (iff documentation is asked). +if(BUILD_DOCUMENTATION) + find_package(Doxygen REQUIRED) + + set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in) + set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) + + configure_file(${doxyfile_in} ${doxyfile} @ONLY) + + # ALL allows to build the docs together with any other target. + add_custom_target( doc ALL + COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_OUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM ) +endif() + enable_testing() add_subdirectory(tests) diff --git a/README.md b/README.md index b17ab76..939f1e4 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ To configure the display, you indicate the three types of locations, for example ```cpp auto& log = clutchlog::logger(); log.depth(2); // Log functions called from "main" but not below. - log.threshold(clutchlog::level::info); // Log only "info", "warning", "error" or "quiet" messages. + log.threshold(clutchlog::level::info); // Log only "info", "warning", "error" or "critical" messages. log.file("algebra/.*"); // Will match any file in the "algebra" directory. log.func("(mul|add|sub|div)"); // Will match "multiply", for instance. ``` @@ -109,7 +109,7 @@ log.threshold(clutchlog::level::error); // Log level, defaults to error. ``` Current levels are defined in an enumeration as `clutchlog::level`: ```cpp -enum level {quiet=0, error=1, warning=2, progress=3, info=4, debug=5, xdebug=6}; +enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7}; ``` File, function and line filters are indicated using (ECMAScript) regular expressions: @@ -146,7 +146,7 @@ Available tags are: - `{msg}`: the logged message, - `{name}`: the name of the current binary, -- `{level}`: the current log level (i.e. `Quiet`, `Error`, `Warning`, `Progress`, `Info`, `Debug` or `XDebug`), +- `{level}`: the current log level (i.e. `Critical`, `Error`, `Warning`, `Progress`, `Note`, `Info`, `Debug` or `XDebug`), - `{level_letter}`: the first letter of the current log level, - `{file}`: the current file (absolute path), - `{func}`: the current function, @@ -232,7 +232,7 @@ format << "{level}: " << fmt(fmt::typo::reset) << " {msg}" << std::endl; // This is a reset. log.format(format.str()); ``` -Note: messages at the "quiet", "error" and "warning" log levels are colored by default. +Note: messages at the "critical", "error" and "warning" log levels are colored by default. You may want to set their style to `none` if you want to stay in control of inserted colors in the format template. diff --git a/clutchlog/clutchlog.h b/clutchlog/clutchlog.h index 37e69ba..252168f 100644 --- a/clutchlog/clutchlog.h +++ b/clutchlog/clutchlog.h @@ -115,11 +115,15 @@ **********************************************************************/ #ifdef WITH_CLUTCHLOG -//! Singleton class. +/** Single class that holds everything. + * + * This is a Singleton class. + */ class clutchlog { public: - /** High-level API @{ */ + /** @name High-level API + * @{ */ /** Get the logger instance. * @@ -136,9 +140,10 @@ class clutchlog //! Available log levels. enum level {critical=0, error=1, warning=2, progress=3, note=4, info=5, debug=6, xdebug=7}; - /** }@ High-level API */ + /** @} */ - /** Formating API @{ */ + /** @name Formating API + * @{ */ /** Color and style formatter for ANSI terminal escape sequences. * @@ -184,7 +189,8 @@ class clutchlog //! Empty constructor, only useful for a no-op formatter. fmt() : fore(fg::none), back(bg::none), style(typo::none) { } - /** All combination of constructors with different parameters orders. @{ */ + /** @name All combination of constructors with different parameters orders. + * @{ */ fmt( fg f, bg b = bg::none, typo s = typo::none) : fore(f), back(b), style(s) { } fmt( fg f, typo s , bg b = bg::none) : fore(f), back(b), style(s) { } fmt( bg b, fg f = fg::none, typo s = typo::none) : fore(f), back(b), style(s) { } @@ -251,9 +257,10 @@ class clutchlog } }; // fmt class - /** @} Formating API */ + /** @} */ - /** Internal details @{ */ + /** @name Internal details + * @{ */ public: clutchlog(clutchlog const&) = delete; @@ -318,6 +325,7 @@ class clutchlog std::regex _in_func; std::regex _in_line; + //! Structure holding a location matching. struct scope_t { bool matches; // everything is compatible level stage; // current log level @@ -335,7 +343,6 @@ class clutchlog {} }; - //! Gather information on the current location of the call. scope_t locate( const level& stage, @@ -383,36 +390,53 @@ class clutchlog return scope; } - /** }@ Internal details */ + /** @}*/ public: - /** Configuration accessors @{ */ + /** @name Configuration accessors + * @{ */ + //! Set the template string. void format(const std::string& format) {_format_log = format;} + //! Get the template string. std::string format() const {return _format_log;} + //! Set the template string for dumps. void format_comment(const std::string& format) {_format_dump = format;} + //! Get the template string for dumps. std::string format_comment() const {return _format_dump;} + //! Set the output stream on which to print. void out(std::ostream& out) {_out = &out;} + //! Get the output stream on which to print. std::ostream& out() {return *_out;} #if CLUTCHLOG_HAVE_UNIX_SYSINFO == 1 + //! Set the stack depth above which logs are not printed. void depth(size_t d) {_depth = d;} + //! Get the stack depth above which logs are not printed. size_t depth() const {return _depth;} + //! Set the string mark with which stack depth is indicated. void depth_mark(std::string mark) {_depth_mark = mark;} + //! Get the string mark with which stack depth is indicated. std::string depth_mark() const {return _depth_mark;} #endif + //! Set the log level below which logs are not printed. void threshold(level l) {_stage = l;} + //! Get the log level below which logs are not printed. level threshold() const {return _stage;} + //! Set the regular expression filtering the file location. void file(std::string file) {_in_file = file;} + //! Set the regular expression filtering the function location. void func(std::string func) {_in_func = func;} + //! Set the regular expression filtering the line location. void line(std::string line) {_in_line = line;} + //! Set the regular expressions filtering the location. void location( const std::string& in_file, const std::string& in_function=".*", @@ -424,11 +448,21 @@ class clutchlog line(in_line); } + /** Set the style (color and typo) of the given log level. + * + * This version accept style arguments as if they were passed to `clutchlog::fmt`. + */ template void style(level stage, FMT... styles) { this->style(stage,fmt(styles...)); } + //! Set the style (color and typo) of the given log level, passing a `fmt` instance. void style(level stage, fmt style) { _level_fmt.at(stage) = style; } + //! Get the configured fmt instance of the given log level. fmt style(level stage) const { return _level_fmt.at(stage); } + /** Return the log level tag corresponding to the given pre-configured name. + * + * @note This is case sensitive, see the pre-configured `_level_word`. + */ level level_of(const std::string name) { const auto ilevel = _word_level.find(name); @@ -439,12 +473,20 @@ class clutchlog } } - /** }@ Configuration */ + /** @} */ public: - /** Low-level API @{ */ + /** @name Low-level API + * @{ */ + /** Replace `mark` by `tag` in `form`. + * + * @code + * log.replace("{greet} {world}", "\\{greet\\}", "hello"); + * // returns "hello {world}" + * @endcode + */ std::string replace( const std::string& form, const std::string& mark, @@ -509,6 +551,7 @@ class clutchlog return std::regex_replace(form, re, tag); } + //! Replace `mark` by `tag` in `form`, converting tag to its string representation first. std::string replace( const std::string& form, const std::string& mark, @@ -519,6 +562,7 @@ class clutchlog return replace(form, mark, stag.str()); } + //! Substitute all tags in the format string with the corresponding information and apply the style corresponding to the log level. std::string format( std::string format, const std::string& what, @@ -558,6 +602,7 @@ class clutchlog return _level_fmt.at(stage)(format); } + //! Print a log message IF the location matches the given one. void log( const level& stage, const std::string& what, @@ -581,6 +626,7 @@ class clutchlog } // if scopes.matches } + //! Dump a serializable container after a comment line with log information. template void dump( const level& stage, @@ -633,11 +679,16 @@ class clutchlog } // if scopes.matches } - /** }@ Low-level API */ + /** @} */ }; #else // not WITH_CLUTCHLOG + +/********************************************************************** + * Fake implementation + **********************************************************************/ + // Equivalent class with empty methods, will be optimized out // while allowing to actually have calls implemented without WITH_CLUTCHLOG guards. #pragma GCC diagnostic push diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in new file mode 100644 index 0000000..2b308ea --- /dev/null +++ b/docs/Doxyfile.in @@ -0,0 +1,18 @@ +PROJECT_NAME = "@CMAKE_PROJECT_NAME@" +PROJECT_NUMBER = @PROJECT_VERSION@ +STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ \ + @PROJECT_BINARY_DIR@ +INPUT = @PROJECT_SOURCE_DIR@/README.md \ + @doxy_main_page@ \ + @PROJECT_SOURCE_DIR@ \ + @PROJECT_SOURCE_DIR@/doc/main.dox \ + @PROJECT_BINARY_DIR@ +FILE_PATTERNS = *.h \ + *.cpp \ + *.hpp +RECURSIVE = YES +USE_MDFILE_AS_MAINPAGE = @PROJECT_SOURCE_DIR@/README.md +JAVADOC_AUTOBRIEF = YES +EXAMPLE_PATH = @PROJECT_SOURCE_DIR@/tests +IMAGE_PATH = @PROJECT_BINARY_DIR@/html +AUTOLINK_SUPPORT = YES