|
Boost Users : |
From: Nat Goodspeed (nat_at_[hidden])
Date: 2008-06-16 10:29:59
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<context, and_op > rt_context;
> typedef runtime_flt<level, std::less_equal> rt_level;
> typedef mpl::vector<rt_context ,I, rt_level ,I, time ,I,
> file,chr<':'>,line, I, msg>::type default_filters;
>
> } // namespace flog
>
> ..
> and then somthing like:
>
> LOG(l, bit_debug, 7, "will enable trace...");
> runtime_set(l, identity<rt_context>(), 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.
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net