clean-up refactoring and more detailed doc
This commit is contained in:
parent
4de679228e
commit
7ef6459c35
2 changed files with 215 additions and 101 deletions
96
README.md
96
README.md
|
|
@ -12,7 +12,8 @@ Clutchlog allows to select which log messages will be displayed, based on their
|
||||||
- source code location: you can ask to display messages called from given files, functions and line number, all based on
|
- source code location: you can ask to display messages called from given files, functions and line number, all based on
|
||||||
regular expressions.
|
regular expressions.
|
||||||
|
|
||||||
Appart from those, Clutchlog have classical logging system features: output selection, default to unbuffered mode, etc.
|
Appart from those, Clutchlog have classical logging system features: output selection and formatting,
|
||||||
|
default to unbuffered mode, etc.
|
||||||
|
|
||||||
Of course, Clutchlog is disabled by default if `NDEBUG` is not defined.
|
Of course, Clutchlog is disabled by default if `NDEBUG` is not defined.
|
||||||
|
|
||||||
|
|
@ -29,12 +30,12 @@ To configure the display, you indicate the three types of locations, for example
|
||||||
```cpp
|
```cpp
|
||||||
auto& log = clutchlog::logger();
|
auto& log = clutchlog::logger();
|
||||||
log.depth(2); // Log functions called from "main" but not below.
|
log.depth(2); // Log functions called from "main" but not below.
|
||||||
log.threshold(clutchlog::level::info); // Log "info", "warning", "error" or "quiet" messages.
|
log.threshold(clutchlog::level::info); // Log only "info", "warning", "error" or "quiet" messages.
|
||||||
log.file("algebra/.*"); // Will match any file in the "algebra" directory.
|
log.file("algebra/.*"); // Will match any file in the "algebra" directory.
|
||||||
log.func("(mul|add|sub|div)"); // Will match "multiply", for instance.
|
log.func("(mul|add|sub|div)"); // Will match "multiply", for instance.
|
||||||
```
|
```
|
||||||
|
|
||||||
For more detailled examples, see the `tests` directory.
|
For more detailled examples, see the "API documentation" section below and the `tests` directory.
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
|
@ -45,7 +46,7 @@ database.
|
||||||
Their aim is to provide a simple interface to efficiently store messages somewhere, which is appropriated when you have
|
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.
|
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.
|
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
|
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.
|
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
|
However, once the feature is up and running, those detailled informations are only useful if you encounter a bug
|
||||||
|
|
@ -58,10 +59,95 @@ To solve this problem, Clutchlog allows to disengage your debug log messages in
|
||||||
allowing for the fast tracking of a bug across the execution.
|
allowing for the fast tracking of a bug across the execution.
|
||||||
|
|
||||||
|
|
||||||
|
API documentation
|
||||||
|
=================
|
||||||
|
|
||||||
|
The main entrypoint is the `CLUTCHLOG` macro, which takes the desired log level and message.
|
||||||
|
The message can be anything which can be output in an `ostringstream`.
|
||||||
|
```cpp
|
||||||
|
// Simple string:
|
||||||
|
CLUTCHLOG(info, "hello world");
|
||||||
|
|
||||||
|
// Serialisable variable:
|
||||||
|
double value = 0;
|
||||||
|
CLUTCHLOG(error, value);
|
||||||
|
|
||||||
|
// passed using inline output stream operators:
|
||||||
|
CLUTCHLOG(debug, "hello " << value << " world");
|
||||||
|
```
|
||||||
|
|
||||||
|
To configure the global behaviour of the logger, you must first get a reference on its instance:
|
||||||
|
```cpp
|
||||||
|
auto& log = clutchlog::logger();
|
||||||
|
```
|
||||||
|
|
||||||
|
The format of the messages can be defined with the `format` method, passing a string with standardized tags surrounded by `{}`:
|
||||||
|
```cpp
|
||||||
|
log.format("{msg}");
|
||||||
|
```
|
||||||
|
Available tags are:
|
||||||
|
|
||||||
|
- `{msg}`: the logged message,
|
||||||
|
- `{name}`: the name of the current binary,
|
||||||
|
- `{level}`: the current log level (i.e. `Quiet`, `Error`, `Warning`, `Info`, `Debug` or `XDebug`),
|
||||||
|
- `{level_letter}`: the first letter of the current log level,
|
||||||
|
- `{file}`: the current file (absolute path),
|
||||||
|
- `{func}`: the current function,
|
||||||
|
- `{line}`: the current line number,
|
||||||
|
- `{depth}`: the current depth of the call stack,
|
||||||
|
- `{depth_marks}`: as many chevrons `>` as there is calls in the stack.
|
||||||
|
|
||||||
|
The default format is `"[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"`,
|
||||||
|
it can be overriden at compile time by defining the `CLUTCHLOG_DEFAULT_FORMAT` macro.
|
||||||
|
|
||||||
|
The output stream can be configured using the `out` method:
|
||||||
|
```cpp
|
||||||
|
log.out(std::clog); // Defaults to clog.
|
||||||
|
```
|
||||||
|
|
||||||
|
One can configure the location(s) at which messages should actually be logged:
|
||||||
|
```cpp
|
||||||
|
log.depth(3); // Depth of the call stack, defaults to the maximum possible value.
|
||||||
|
log.threshold(clutchlog::level::error); // Log level, defaults to error.
|
||||||
|
```
|
||||||
|
File, function and line are indicated using regular expression:
|
||||||
|
```cpp
|
||||||
|
log.file(".*"); // File location, defaults to any.
|
||||||
|
log.func(".*"); // Function location, defaults to any.
|
||||||
|
log.line(".*"); // Line location, defaults to any.
|
||||||
|
```
|
||||||
|
A shortcut function can be used to indicates file, function and line regular expression at once:
|
||||||
|
```cpp
|
||||||
|
log.location(file, func, line); // Defaults to any, second and last parameters being optional.
|
||||||
|
```
|
||||||
|
|
||||||
|
The mark used with the `{depth_marks}` tag can be configured with the `depth_mark` method,
|
||||||
|
and its default with the `CLUTCHLOG_DEFAULT_DEPTH_MARK` macro:
|
||||||
|
```cpp
|
||||||
|
log.depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK); // Defaults to ">".
|
||||||
|
```
|
||||||
|
|
||||||
|
All configuration setters have a getters counterpart, with the same name but taking no parameter,
|
||||||
|
for example:
|
||||||
|
```cpp
|
||||||
|
std::string mark = log.depth_mark();
|
||||||
|
```
|
||||||
|
|
||||||
|
To control more precisely the logging, one can use the low-level `log` method:
|
||||||
|
```cpp
|
||||||
|
log.log(clutchlog::level::xdebug, "hello world", "main.cpp", "main", 122);
|
||||||
|
```
|
||||||
|
A helper macro can helps to fill in the location with the actual one, as seen by the compiler:
|
||||||
|
```cpp
|
||||||
|
log.log(clutchlog::level::xdebug, "hello world", CLUTCHLOC);
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Limitations
|
Limitations
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Call stack depth is only implemented for Linux.
|
Because the call stack depth and binary name access are system-dependent,
|
||||||
|
Clutchlog is only implemented for Linux at the moment.
|
||||||
|
|
||||||
|
|
||||||
Build and tests
|
Build and tests
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
#ifndef __CLUTCHLOG_H__
|
#ifndef __CLUTCHLOG_H__
|
||||||
#define __CLUTCHLOG_H__
|
#define __CLUTCHLOG_H__
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <sstream>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|
@ -16,54 +17,74 @@
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef WITH_THROWN_ASSERTS
|
/**********************************************************************
|
||||||
// #undef assert
|
* Enable by default in Debug builds.
|
||||||
// #define assert( what ) { if(!(what)){CLUTCHLOG_RAISE(aion::Assert, "Failed assert: `" << #what << "`");} }
|
**********************************************************************/
|
||||||
// #else
|
|
||||||
#include <cassert>
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
#ifndef WITH_CLUTCHLOG
|
#ifndef WITH_CLUTCHLOG
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define WITH_CLUTCHLOG
|
#define WITH_CLUTCHLOG
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Macros definitions
|
||||||
|
**********************************************************************/
|
||||||
#ifdef WITH_CLUTCHLOG
|
#ifdef WITH_CLUTCHLOG
|
||||||
|
|
||||||
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
#ifndef CLUTCHLOG_DEFAULT_FORMAT
|
||||||
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
|
//! Default format of the messages.
|
||||||
|
#define CLUTCHLOG_DEFAULT_FORMAT "[{name}] {level_letter}:{depth_marks} {msg}\t\t\t\t\t{func} @ {file}:{line}\n"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLUTCHLOG_DEFAULT_DEPTH_MARK
|
||||||
|
#define CLUTCHLOG_DEFAULT_DEPTH_MARK ">"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Handy shortcuts to location.
|
||||||
#define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
|
#define CLUTCHLOC __FILE__, __FUNCTION__, __LINE__
|
||||||
|
|
||||||
|
//! Log a message at the given level.
|
||||||
#define CLUTCHLOG( LEVEL, WHAT ) { \
|
#define CLUTCHLOG( LEVEL, WHAT ) { \
|
||||||
auto& logger = clutchlog::logger(); \
|
auto& logger = clutchlog::logger(); \
|
||||||
std::ostringstream msg ; msg << WHAT; \
|
std::ostringstream msg ; msg << WHAT; \
|
||||||
logger.log(msg.str(), clutchlog::level::LEVEL, CLUTCHLOC); \
|
logger.log(clutchlog::level::LEVEL, msg.str(), CLUTCHLOC); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Dump the given container.
|
||||||
#define CLUTCHDUMP( LEVEL, CONTAINER ) { \
|
#define CLUTCHDUMP( LEVEL, CONTAINER ) { \
|
||||||
auto& logger = clutchlog::logger(); \
|
auto& logger = clutchlog::logger(); \
|
||||||
logger.dump(std::begin(CONTAINER), std::end(CONTAINER), clutchlog::level::LEVEL, CLUTCHLOC, "\n"); \
|
logger.dump(clutchlog::level::LEVEL, std::begin(CONTAINER), std::end(CONTAINER), CLUTCHLOC, "\n"); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
// Disabled macros can still be used in Release builds.
|
||||||
#define CLUTCHLOG ( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
|
#define CLUTCHLOG ( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
|
||||||
#define CLUTCHDUMP ( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
|
#define CLUTCHDUMP ( LEVEL, WHAT ) { do {/*nothing*/} while(false); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* Implementation
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
//! Singleton class.
|
||||||
class clutchlog
|
class clutchlog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** High-level API @{ */
|
/** High-level API @{ */
|
||||||
|
|
||||||
|
/** Get the logger instance.
|
||||||
|
*
|
||||||
|
* @code
|
||||||
|
* auto& log = clutchlog::logger();
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
static clutchlog& logger()
|
static clutchlog& logger()
|
||||||
{
|
{
|
||||||
static clutchlog instance;
|
static clutchlog instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Available log levels.
|
||||||
enum level {quiet=0, error=1, warning=2, info=3, debug=4, xdebug=5};
|
enum level {quiet=0, error=1, warning=2, info=3, debug=4, xdebug=5};
|
||||||
|
|
||||||
/** }@ High-level API */
|
/** }@ High-level API */
|
||||||
|
|
@ -78,13 +99,13 @@ class clutchlog
|
||||||
clutchlog() :
|
clutchlog() :
|
||||||
// system, main, log
|
// system, main, log
|
||||||
_strip_calls(3),
|
_strip_calls(3),
|
||||||
_level_letters({
|
_level_words({
|
||||||
{level::quiet,"Q"},
|
{level::quiet,"Quiet"},
|
||||||
{level::error,"E"},
|
{level::error,"Error"},
|
||||||
{level::warning,"W"},
|
{level::warning,"Warning"},
|
||||||
{level::info,"I"},
|
{level::info,"Info"},
|
||||||
{level::debug,"D"},
|
{level::debug,"Debug"},
|
||||||
{level::xdebug,"X"}
|
{level::xdebug,"XDebug"}
|
||||||
}),
|
}),
|
||||||
_format(CLUTCHLOG_DEFAULT_FORMAT),
|
_format(CLUTCHLOG_DEFAULT_FORMAT),
|
||||||
_out(&std::clog),
|
_out(&std::clog),
|
||||||
|
|
@ -93,15 +114,12 @@ class clutchlog
|
||||||
_in_file(".*"),
|
_in_file(".*"),
|
||||||
_in_func(".*"),
|
_in_func(".*"),
|
||||||
_in_line(".*"),
|
_in_line(".*"),
|
||||||
_show_name(true),
|
_depth_mark(CLUTCHLOG_DEFAULT_DEPTH_MARK)
|
||||||
_show_depth(true),
|
|
||||||
_show_location(true),
|
|
||||||
_show_level(true)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const size_t _strip_calls;
|
const size_t _strip_calls;
|
||||||
const std::map<level,std::string> _level_letters;
|
const std::map<level,std::string> _level_words;
|
||||||
std::string _format;
|
std::string _format;
|
||||||
std::ostream* _out;
|
std::ostream* _out;
|
||||||
size_t _depth;
|
size_t _depth;
|
||||||
|
|
@ -109,10 +127,7 @@ class clutchlog
|
||||||
std::regex _in_file;
|
std::regex _in_file;
|
||||||
std::regex _in_func;
|
std::regex _in_func;
|
||||||
std::regex _in_line;
|
std::regex _in_line;
|
||||||
bool _show_name;
|
std::string _depth_mark;
|
||||||
bool _show_depth;
|
|
||||||
bool _show_location;
|
|
||||||
bool _show_level;
|
|
||||||
|
|
||||||
struct scope_t {
|
struct scope_t {
|
||||||
bool matches; // everything is compatible
|
bool matches; // everything is compatible
|
||||||
|
|
@ -121,6 +136,7 @@ class clutchlog
|
||||||
bool there; // location is compatible
|
bool there; // location is compatible
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Gather information on the current location of the call.
|
||||||
scope_t locate(
|
scope_t locate(
|
||||||
const level& stage,
|
const level& stage,
|
||||||
const std::string& file,
|
const std::string& file,
|
||||||
|
|
@ -165,6 +181,9 @@ class clutchlog
|
||||||
void depth(size_t d) {_depth = d;}
|
void depth(size_t d) {_depth = d;}
|
||||||
size_t depth() const {return _depth;}
|
size_t depth() const {return _depth;}
|
||||||
|
|
||||||
|
void depth_mark(std::string mark) {_depth_mark = mark;}
|
||||||
|
std::string depth_mark() const {return _depth_mark;}
|
||||||
|
|
||||||
void threshold(level l) {_stage = l;}
|
void threshold(level l) {_stage = l;}
|
||||||
level threshold() const {return _stage;}
|
level threshold() const {return _stage;}
|
||||||
|
|
||||||
|
|
@ -195,59 +214,61 @@ class clutchlog
|
||||||
const std::string& tag
|
const std::string& tag
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
std::regex re;
|
// Useless debug code, unless something fancy would be done with name tags.
|
||||||
try {
|
// std::regex re;
|
||||||
re = std::regex(mark);
|
// try {
|
||||||
|
// re = std::regex(mark);
|
||||||
} catch(const std::regex_error& e) {
|
//
|
||||||
std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
|
// } catch(const std::regex_error& e) {
|
||||||
switch(e.code()) {
|
// std::cerr << "ERROR with a regular expression \"" << mark << "\": ";
|
||||||
case std::regex_constants::error_collate:
|
// switch(e.code()) {
|
||||||
std::cerr << "the expression contains an invalid collating element name";
|
// case std::regex_constants::error_collate:
|
||||||
break;
|
// std::cerr << "the expression contains an invalid collating element name";
|
||||||
case std::regex_constants::error_ctype:
|
// break;
|
||||||
std::cerr << "the expression contains an invalid character class name";
|
// case std::regex_constants::error_ctype:
|
||||||
break;
|
// std::cerr << "the expression contains an invalid character class name";
|
||||||
case std::regex_constants::error_escape:
|
// break;
|
||||||
std::cerr << "the expression contains an invalid escaped character or a trailing escape";
|
// case std::regex_constants::error_escape:
|
||||||
break;
|
// std::cerr << "the expression contains an invalid escaped character or a trailing escape";
|
||||||
case std::regex_constants::error_backref:
|
// break;
|
||||||
std::cerr << "the expression contains an invalid back reference";
|
// case std::regex_constants::error_backref:
|
||||||
break;
|
// std::cerr << "the expression contains an invalid back reference";
|
||||||
case std::regex_constants::error_brack:
|
// break;
|
||||||
std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
|
// case std::regex_constants::error_brack:
|
||||||
break;
|
// std::cerr << "the expression contains mismatched square brackets ('[' and ']')";
|
||||||
case std::regex_constants::error_paren:
|
// break;
|
||||||
std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
|
// case std::regex_constants::error_paren:
|
||||||
break;
|
// std::cerr << "the expression contains mismatched parentheses ('(' and ')')";
|
||||||
case std::regex_constants::error_brace:
|
// break;
|
||||||
std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
|
// case std::regex_constants::error_brace:
|
||||||
break;
|
// std::cerr << "the expression contains mismatched curly braces ('{' and '}')";
|
||||||
case std::regex_constants::error_badbrace:
|
// break;
|
||||||
std::cerr << "the expression contains an invalid range in a {} expression";
|
// case std::regex_constants::error_badbrace:
|
||||||
break;
|
// std::cerr << "the expression contains an invalid range in a {} expression";
|
||||||
case std::regex_constants::error_range:
|
// break;
|
||||||
std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
|
// case std::regex_constants::error_range:
|
||||||
break;
|
// std::cerr << "the expression contains an invalid character range (e.g. [b-a])";
|
||||||
case std::regex_constants::error_space:
|
// break;
|
||||||
std::cerr << "there was not enough memory to convert the expression into a finite state machine";
|
// case std::regex_constants::error_space:
|
||||||
break;
|
// std::cerr << "there was not enough memory to convert the expression into a finite state machine";
|
||||||
case std::regex_constants::error_badrepeat:
|
// break;
|
||||||
std::cerr << "one of *?+{ was not preceded by a valid regular expression";
|
// case std::regex_constants::error_badrepeat:
|
||||||
break;
|
// std::cerr << "one of *?+{ was not preceded by a valid regular expression";
|
||||||
case std::regex_constants::error_complexity:
|
// break;
|
||||||
std::cerr << "the complexity of an attempted match exceeded a predefined level";
|
// case std::regex_constants::error_complexity:
|
||||||
break;
|
// std::cerr << "the complexity of an attempted match exceeded a predefined level";
|
||||||
case std::regex_constants::error_stack:
|
// break;
|
||||||
std::cerr << "there was not enough memory to perform a match";
|
// case std::regex_constants::error_stack:
|
||||||
break;
|
// std::cerr << "there was not enough memory to perform a match";
|
||||||
default:
|
// break;
|
||||||
std::cerr << "unknown error";
|
// default:
|
||||||
}
|
// std::cerr << "unknown error";
|
||||||
std::cerr << std::endl;
|
// }
|
||||||
throw;
|
// std::cerr << std::endl;
|
||||||
} // catch
|
// throw;
|
||||||
|
// } // catch
|
||||||
|
|
||||||
|
std::regex re(mark);
|
||||||
return std::regex_replace(form, re, tag);
|
return std::regex_replace(form, re, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,19 +276,24 @@ class clutchlog
|
||||||
std::string format,
|
std::string format,
|
||||||
const std::string& what,
|
const std::string& what,
|
||||||
const std::string& name,
|
const std::string& name,
|
||||||
const std::string& stage,
|
const level& stage,
|
||||||
const std::string& file,
|
const std::string& file,
|
||||||
const std::string& func,
|
const std::string& func,
|
||||||
const std::string& line,
|
const size_t line,
|
||||||
const size_t depth
|
const size_t depth
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
format = replace(format, "\\{msg\\}", what);
|
format = replace(format, "\\{msg\\}", what);
|
||||||
format = replace(format, "\\{name\\}", name);
|
format = replace(format, "\\{name\\}", name);
|
||||||
format = replace(format, "\\{level\\}", stage);
|
|
||||||
format = replace(format, "\\{file\\}", file);
|
format = replace(format, "\\{file\\}", file);
|
||||||
format = replace(format, "\\{func\\}", func);
|
format = replace(format, "\\{func\\}", func);
|
||||||
format = replace(format, "\\{line\\}", line);
|
format = replace(format, "\\{level\\}", _level_words.at(stage));
|
||||||
|
|
||||||
|
std::ostringstream sline; sline << line;
|
||||||
|
format = replace(format, "\\{line\\}", sline.str());
|
||||||
|
|
||||||
|
std::string letter(1, _level_words.at(stage).at(0));
|
||||||
|
format = replace(format, "\\{level_letter\\}", letter);
|
||||||
|
|
||||||
std::ostringstream sdepth; sdepth << depth;
|
std::ostringstream sdepth; sdepth << depth;
|
||||||
format = replace(format, "\\{depth\\}", sdepth.str());
|
format = replace(format, "\\{depth\\}", sdepth.str());
|
||||||
|
|
@ -281,39 +307,41 @@ class clutchlog
|
||||||
}
|
}
|
||||||
|
|
||||||
void log(
|
void log(
|
||||||
|
const level& stage,
|
||||||
const std::string& what,
|
const std::string& what,
|
||||||
const level& stage, const std::string& file, const std::string& func, size_t line
|
const std::string& file, const std::string& func, size_t line
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
scope_t scope = locate(stage, file, func, line);
|
scope_t scope = locate(stage, file, func, line);
|
||||||
|
|
||||||
if(scope.matches) {
|
if(scope.matches) {
|
||||||
std::ostringstream sline; sline << line;
|
|
||||||
*_out << format(_format, what, basename(getenv("_")),
|
*_out << format(_format, what, basename(getenv("_")),
|
||||||
_level_letters.at(stage), file, func,
|
stage, file, func,
|
||||||
sline.str(), scope.depth );
|
line, scope.depth );
|
||||||
|
_out->flush();
|
||||||
} // if scopes.matches
|
} // if scopes.matches
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class In>
|
template<class In>
|
||||||
void dump(
|
void dump(
|
||||||
|
const level& stage,
|
||||||
const In container_begin, const In container_end,
|
const In container_begin, const In container_end,
|
||||||
const level& stage, const std::string& file, const std::string& func, size_t line,
|
const std::string& file, const std::string& func, size_t line,
|
||||||
const std::string sep="\n"
|
const std::string sep="\n"
|
||||||
) const
|
) const
|
||||||
// FIXME use a file name as input
|
// FIXME use a file name template as input
|
||||||
{
|
{
|
||||||
scope_t scope = locate(stage, file, func, line);
|
scope_t scope = locate(stage, file, func, line);
|
||||||
|
|
||||||
if(scope.matches) {
|
if(scope.matches) {
|
||||||
std::ostringstream sline; sline << line;
|
*_out << "#" // FIXME add a _format_dump parameter?
|
||||||
*_out << "#"
|
|
||||||
<< format(_format, "", basename(getenv("_")),
|
<< format(_format, "", basename(getenv("_")),
|
||||||
_level_letters.at(stage), file, func,
|
stage, file, func,
|
||||||
sline.str(), scope.depth );
|
line, scope.depth );
|
||||||
|
|
||||||
std::copy(container_begin, container_end,
|
std::copy(container_begin, container_end,
|
||||||
std::ostream_iterator<typename In::value_type>(*_out, sep.c_str()));
|
std::ostream_iterator<typename In::value_type>(*_out, sep.c_str()));
|
||||||
|
// No flush
|
||||||
} // if scopes.matches
|
} // if scopes.matches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue