Something like an ostream...

  • Thread starter Jens Thoms Toerring
  • Start date
J

Jens Thoms Toerring

Hi,

I haven't programmed in C++ for some time and now coming back to
it I seem to have my "senior moments". I would like to write a kind
of logger with a twist in that the file name to use for logging will
only be known after a configuration file has been read in. Of course,
I also would like to log problems encountered while reading that con-
figuration file. So my idea was to store the stuff send to the logger
while the file name isn't yet known to a stringstream and, once the
log files name is available, write the accumulated string to that
file and switch to writing to the file for the rest of the time the
program runs.

I would, of course, like the logger to be an object one can use
the '<<' operator on, so my first idea was to derive it from
std::eek:stream. But is that still an "is-a" relationship, i.e. a
specialization of std:eek:stream or is it something that goes be-
yond that? I'm at a loss if this can be done and if possible, how.
Has someone perhaps a few helpful hints or pointers - or maybe can
tell me that this is just a crap idea and I should stop waisting
my time worrying about it?

Thanks and best regards, Jens
 
I

Ian Collins

Jens said:
Hi,

I haven't programmed in C++ for some time and now coming back to
it I seem to have my "senior moments". I would like to write a kind
of logger with a twist in that the file name to use for logging will
only be known after a configuration file has been read in. Of course,
I also would like to log problems encountered while reading that con-
figuration file. So my idea was to store the stuff send to the logger
while the file name isn't yet known to a stringstream and, once the
log files name is available, write the accumulated string to that
file and switch to writing to the file for the rest of the time the
program runs.

Or just open the file first! One of the first things I do in my generic
boilerplate code is configure logging (if used).
I would, of course, like the logger to be an object one can use
the '<<' operator on, so my first idea was to derive it from
std::eek:stream. But is that still an "is-a" relationship, i.e. a
specialization of std:eek:stream or is it something that goes be-
yond that? I'm at a loss if this can be done and if possible, how.
Has someone perhaps a few helpful hints or pointers - or maybe can
tell me that this is just a crap idea and I should stop waisting
my time worrying about it?

The unusual way to specialise output (or input) is to derive from
std::streambuf rather than ostream. You don't generally want to change
the streaming operations, just the lower level reading and writing which
is the job of a streambuf. streambuf provides a set of virtual member
functions you can use for your own derived types.
 
J

Jens Thoms Toerring

Or just open the file first! One of the first things I do in my generic
boilerplate code is configure logging (if used).

But the name of the log file is set via the configuration file,
so it can only be opened once the configuration file, at least
partially, has been read and parsed...
The unusual way to specialise output (or input) is to derive from
std::streambuf rather than ostream. You don't generally want to change
the streaming operations, just the lower level reading and writing which
is the job of a streambuf. streambuf provides a set of virtual member
functions you can use for your own derived types.

Thank you, I will have to take a good look at this (and try to
eventually grasp the inheritance relationship of all those in-
and output classes in C++;-)

Thanks and best regards, Jens
 
I

Ian Collins

Jens said:
But the name of the log file is set via the configuration file,
so it can only be opened once the configuration file, at least
partially, has been read and parsed...

Log to the console, then if you name a file, switch. The only thing you
are likely to log during startup is a catastrophic failure.
 
M

Marcel Müller

I haven't programmed in C++ for some time and now coming back to
it I seem to have my "senior moments". I would like to write a kind
of logger with a twist in that the file name to use for logging will
only be known after a configuration file has been read in. Of course,
I also would like to log problems encountered while reading that con-
figuration file. So my idea was to store the stuff send to the logger
while the file name isn't yet known to a stringstream and, once the
log files name is available, write the accumulated string to that
file and switch to writing to the file for the rest of the time the
program runs.

You can do that, but be aware that the config might be bad and you never
get the log output, not even the problems while loading the config.

We have the same scenario. There are two solutions:

1. either you choose a reasonable fallback when the configured log
target failed to initialize. I.e. you check for a directory where you
have write permissions and store your log there. $cwd, $tmp or whatever.

2. or you refuse to start with a nonzero return code, unless the
configuration is basically OK and the log open succeeded. You use stderr
for fatal error logging so far and switch to the final one as soon as
possible. Since reading the config and opening the log are the first
operations that the application should do I never had the need to buffer
the events before the log is initialized.

Although we implemented both versions I definitely prefer the second
choice. Simply because it is more reliable. It could be difficult in
case of an incident to find the place where the log has gone to. And it
is no good idea to suggest that everything is OK while the configuration
is broken. Doing an abnormal termination is one of the best choices
because it does not hide errors and usually the problem is detected
shortly. And well, if no one cares about the failed start, then the
application is not important anyway.

To come around common problems with bad log configurations we have setup
a global environment var on all servers that contains the basic log
configuration for /all/ applications, basically the target path. This
path is writable lo all local users but not remotely. The application
local configuration only specifies log file names, subdirectories or
other options. And since there are reasonable defaults for the log name
(i.e. the applications executable name) the application config for
logging might be entirely optional. This is some kind of combination of
solution #1 and #2.

You only get problems if several instances of the same application try
to write to the same log. We addressed that by using an atomic appender
that can safely write to the same file from different processes. And of
course, our logger adds some machine readable header information to each
log entry, to identify the source.

I would, of course, like the logger to be an object one can use
the '<<' operator on, so my first idea was to derive it from
std::eek:stream. But is that still an "is-a" relationship, i.e. a
specialization of std:eek:stream or is it something that goes be-
yond that?

You already got the hint with streambuf.


Marcel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,733
Latest member
LonaMonzon

Latest Threads

Top