
Mojmir Svoboda wrote:
When the logging system initializes, it reads config info (from a file or registry data) to enable/disable particular string tags. I usually
could you show me perhaps some of your config files? just for inspiration...
In a product using a separate config file specifically for logging, the file contents might look like this: ---8<--- error warn assets config --->8--- The code splits on whitespace, adding the string tags to a map. Again, map lookup occurs only the /first/ time control reaches a particular log message. When I'm reading a more generic config file (or registry subtree), the above can go into a string-valued config variable instead. For a developer debugging session, it might look like this: ---8<--- * events memory (long list of other tags I explicitly want to suppress) --->8--- where the tag '*' means: enable all log messages except those explicitly named. This sets a flag inverting the sense of map lookup success/failure.
how do you force reload of config? on unix i'd use a signal, but to be honest, have no big clue about windows...
Heh -- since I've mostly used this with consumer products, I haven't had to confront that. You exit the program, edit the config file and start it up again. Of course that's inadequate for a general-purpose logging library. I think I'd investigate the Windows functionality that allows a program to register interest in a change to a particular file.
i planned to add another run-time filtering facility; for example you could define your facilities like that:
namespace flog {
unsigned const bit_all = bin<11111111>::value; unsigned const bit_trace = bin<00000001>::value; unsigned const bit_hedumps = bin<00000010>::value; unsigned const bit_dataflow = bin<00000100>::value; ... unsigned const bit_synchro = bin<10000000>::value;
/**@class default_filters * @brief sequence of default filters used for text formatting */ typedef runtime_flt
rt_context; typedef runtime_flt rt_level; typedef mpl::vector ,line, I, msg>::type default_filters; } // namespace flog
.. and then somthing like:
LOG(l, bit_debug, 7, "will enable trace..."); runtime_set(l, identity
(), bit_hexdump | bit_trace); { ENTRY(l, 7, "void foo(T) [with T = long int]"); } i'd really like to know your opinion on that.
I once worked on a very large product whose error codes were #defined in a central header file, e.g. #define ERROR_FILENOTFOUND 1001 ...many, many others... Every .cpp file in the system #included that file. Any change to that file forced a lengthy full rebuild on every developer. What happened was that developers quietly rebelled, hard-coding new decimal values into error-message-emitting function calls. Naturally, since those decimal values were no longer centrally registered, duplicates cropped up in different subsystems. Moreover, a typo in a hard-coded number (e.g. transposing two digits) could and did get released to the world before anyone noticed. In C++ source code, having a single, central source of truth for such things can actually be counterproductive. I much prefer a decentralized approach. An early incarnation of the log mechanism I've been describing used single-character tags: easy to code, more recognizable than decimal constants, cheap to store and compare. Scales /very/ poorly. I've come to prefer string tags, and have used that approach in several different products now. While theoretically possible, collisions are rare. Typos are readily spotted.