first import

This commit is contained in:
Johann Dreo 2020-08-23 11:11:15 +02:00
commit e30a6b3e85
5 changed files with 293 additions and 0 deletions

39
CMakeLists.txt Normal file
View file

@ -0,0 +1,39 @@
######################################################################################
# Project settings
######################################################################################
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project("clutchlog")
enable_language(CXX) # C++
set(CMAKE_CXX_STANDARD 17)
## Current version
set(VERSION_MAJOR 0 CACHE STRING "Major version number" )
set(VERSION_MINOR 1 CACHE STRING "Minor version number" )
set(VERSION_PATCH 0 CACHE STRING "Patch version number" )
mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH)
######################################################################################
# Configurable user settings
######################################################################################
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
# put binaries in the build directory
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# Dump used compiler flags.
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
######################################################################################
# Start building
######################################################################################
enable_testing()
add_subdirectory(tests)

78
README.md Normal file
View file

@ -0,0 +1,78 @@
Clutchlog is a logging system whith targets versatile debugging.
It allows to (de)clutch messages either for a given: log level, source code location or call stack depth.
Features
========
Clutchlog allows to select which log messages will be displayed, based on their locations:
- classical log levels: each message has a given detail level and it is displayed if you ask for a at least the same one
(current ones: quiet, error, warning, info, debug, xdebug).
- call stack depth: you can ask to display messages within functions which are called up to a given stack depth.
- source code location: you can ask to display messages called from given files, functions and line number, all based on
regular expressions.
Appart from those, Clutchlog have classical logging system features: output selection, default to unbuffered mode, etc.
Of course, Clutchlog is disabled by default if `NDEBUG` is not defined.
Example
=======
Adding a message is a simple as calling a macro (which is declutched in Debug build type):
```cpp
CLUTCHLOG(info, "matrix size: " << m << "x" << n);
```
To configure the display, you indicate the three types of locations, for example in your `main` function:
```cpp
auto& log = clutchlog::logger();
log.depth(2); // Log functions called from "main" but not below.
log.threshold(clutchlog::level::info); // Log "info", "warning", "error" or "quiet" messages.
log.file("algebra/.*"); // Will match any file in the "algebra" directory.
log.func("(mul|add|sub|div)"); // Will match "multiply", for instance.
```
For more detailled examples, see the `tests` directory.
Rationale
=========
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.
Clutchlog, however, targets the debugging of a (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.
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).
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.
Limitations
===========
Call stack depth is only implemented for Linux.
Build and tests
===============
To build and run the tests, just use a classical CMake workflow:
```sh
mkdir build
cd build
cmake ..
make
ctest
```

128
clutchlog/clutchlog.h Normal file
View file

@ -0,0 +1,128 @@
#ifndef __CLUTCHLOG_H__
#define __CLUTCHLOG_H__
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <string>
#include <limits>
#include <sstream>
#include <regex>
// #ifdef __unix__
#include <execinfo.h>
#include <stdlib.h>
#include <libgen.h>
// #endif
// #ifdef WITH_THROWN_ASSERTS
// #undef assert
// #define assert( what ) { if(!(what)){CLUTCHLOG_RAISE(aion::Assert, "Failed assert: `" << #what << "`");} }
// #else
#include <cassert>
// #endif
#ifndef WITH_CLUTCHLOG
#ifndef NDEBUG
#define WITH_CLUTCHLOG
#endif
#endif
class clutchlog
{
public:
static clutchlog& logger()
{
static clutchlog instance;
return instance;
}
enum level {quiet, error, warning, info, debug, xdebug};
public:
clutchlog(clutchlog const&) = delete;
void operator=(clutchlog const&) = delete;
private:
clutchlog() :
_out(&std::clog),
_depth(std::numeric_limits<size_t>::max()),
_level(level::error),
_in_file(".*"),
_in_func(".*"),
_in_line(".*")
{}
protected:
// system, main, log
const size_t _strip_calls = 3;
std::ostream* _out;
size_t _depth;
level _level;
std::regex _in_file;
std::regex _in_func;
std::regex _in_line;
public:
void out(std::ostream& out) {_out = &out;}
std::ostream& out() {return *_out;}
void depth(size_t d) {_depth = d;}
size_t depth() const {return _depth;}
void threshold(level l) {_level = l;}
level threshold() const {return _level;}
void file(std::string file) {_in_file = file;}
void func(std::string func) {_in_func = func;}
void line(std::string line) {_in_line = line;}
void location(std::string in_file, std::string in_function=".*", std::string in_line=".*")
{
file(in_file);
func(in_function);
line(in_line);
}
void log(std::string what, level log_level, std::string file, std::string func, size_t line, bool newline)
{
const size_t max_buffer = 1024;
size_t stack_depth;
void *buffer[max_buffer];
stack_depth = backtrace(buffer, max_buffer);
if(log_level <= _level and stack_depth <= _depth + _strip_calls) {
std::ostringstream sline; sline << line;
if( std::regex_search(file, _in_file)
and std::regex_search(func, _in_func)
and std::regex_search(sline.str(), _in_line)) {
*_out << "[" << basename(getenv("_")) << "] ";
for(size_t i = _strip_calls; i < stack_depth; ++i) {
*_out << ">";
}
if(stack_depth > _strip_calls) {
*_out << " ";
}
*_out << what;
*_out << "\t\t\t\t\t" << file << ":" << line << " (" << func << ")";
if(newline) {
*_out << std::endl;
}
} // regex location
} // log level and stack depth
}
};
#ifdef WITH_CLUTCHLOG
#define CLUTCHLOG( LEVEL, WHAT ) { \
auto& logger = clutchlog::logger(); \
std::ostringstream msg ; msg << WHAT; \
logger.log(msg.str(), clutchlog::level::LEVEL, __FILE__, __FUNCTION__, __LINE__, true); \
}
#else
#define CLUTCHLOG ( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
#endif
#endif // __CLUTCHLOG_H__

14
tests/CMakeLists.txt Normal file
View file

@ -0,0 +1,14 @@
function(add_simple_test tname)
add_executable(${tname} ${tname}.cpp)
add_test(NAME ${tname} COMMAND ${tname})
endfunction()
file(GLOB sources "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
foreach(filename ${sources})
# File name without directory or longest extension
get_filename_component(name ${filename} NAME_WE)
add_simple_test(${name})
endforeach()

34
tests/t-core.cpp Normal file
View file

@ -0,0 +1,34 @@
#include "../clutchlog/clutchlog.h"
void g()
{
CLUTCHLOG(info, "!");
}
void f()
{
CLUTCHLOG(warning, "world");
g();
}
int main(const int argc, char* argv[])
{
#ifdef WITH_CLUTCHLOG
auto& log = clutchlog::logger();
log.out(std::clog);
size_t below = 2;
if(argc >= 2) { below = atoi(argv[1]); }
log.depth(below);
log.threshold(clutchlog::level::warning);
log.file("core");
log.func("(main|f)");
#endif
CLUTCHLOG(error, "hello " << argc);
f();
}