first import
This commit is contained in:
commit
e30a6b3e85
5 changed files with 293 additions and 0 deletions
39
CMakeLists.txt
Normal file
39
CMakeLists.txt
Normal 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
78
README.md
Normal 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
128
clutchlog/clutchlog.h
Normal 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
14
tests/CMakeLists.txt
Normal 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
34
tests/t-core.cpp
Normal 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();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue