Discussion:
Beginnings of a new logging library [long]
(too old to reply)
Hendrik Schober
2008-07-14 20:27:38 UTC
Permalink
In some way efficient logging is a hobby of mine. I've been writing
logging libraries for almost 15 years.

Logging is a very good way of finding errors in your application if
those errors only appear at a client's site on the other side of the
planet. It also helps tremendously where errors only appear at some
special timing patterns (like when you're multi-threading) which will
never occur during debugging.
But logging has very conflicting goals: It should be able to produce
a lot of information in case of error without drowning you in a sea
of useless data and, even more important, without slowing down your
application. While this combination certainly cannot be achieved, a
sophisticated logging system can give you the necessary tools and
levers to balance between these according to your needs. (But then
sophistication usually conflicts with another goal: It should be
easy to use.)
That's what makes logging so interesting a problem.

In order to achieve maximum performance while not losing important
information (which sat in some buffer when the application crashed),
IME the following must hold:
- for each log statement, the decision whether its data is used must
be the first thing done -- at least in the code generated by the
compiler
- only if the data is to be used should the data be evaluated and
forwarded
- each log statement must be treated en-bloc, the resulting string
entirely buffered in memory while it's constructed, and flushed
to the target device immediately when done
- it must be possible to enable/disable logging at compile-time
using different parameters (severity, parts of the code etc.);
if disabled, log statement should be discarded by the optimizer
- if logging is enabled at compile-time, it should be possible to
enable/disable it at run-time; when disabled at run-time, it
should be optimized to a single 'if' statement

Many people preferred the stream idiom for logging:
some_logger << "x=" << x << ", y=" << y;
I suppose this stems from the fact that, at some point, everybody
used 'std::cerr' for logging and from the general familiarity of the
idiom. Also, everybody is familiar with streaming. So recently I have
searched for ways to make the syntax for logging stream-like while
still upholding the above goals.
The problem with the stream idiom is that it isn't easy to chunk
information in a deterministic way. You just shove everything down
'operator<<' into some buffer, and when that buffer is full it will
get flushed to the target device. The only way to control flushing
is by explicitly and manually inserting flushing tokens into the
stream. For logging, this isn't acceptable, because flushing is the
default and must not be forgetten.
But given code like the above, when you are inside 'operator<<' you
cannot tell whether it is its first invocation in that line, its
last, or one in between. So you don't know whether to flush the
information given of not.
Add to this parametrization (log messages have severity and you can
decide which severities you want to log), the ability to group code
in hierarchies so you can turn logging on/off for sub-hierarchies,
and the desire to be very flexible in formatting and outputting the
data.
I've used templates to solve this puzzle.

Over the weekend, I finally went to sourceforge and created a project
so you can go and have a look at it. But beware! That's rather rough
code, there's no documentation at all, and so far I've only compiled
it using VC9. If all this doesn't scare you away, have a look at
http://sourceforge.net/projects/templog/
(There's a cpp file with a small test application. If you debug
through it, this might help you to understand what's going on.)
I'd very much appreciate if you would find the time to have a look
at this lib and tell me what you think. (I'm very interested in what
other compilers have to say about the code.)

TIA,

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Ed Mulroy [TeamB]
2008-07-14 21:33:29 UTC
Permalink
I would like to acquaint you to a new development for source code, spaces.
Unlike tabs, they do not assume that the width of your screen is measured in
meters.

. Ed
Hendrik Schober
2008-07-14 21:41:41 UTC
Permalink
Post by Ed Mulroy [TeamB]
I would like to acquaint you to a new development for source code, spaces.
Unlike tabs, they do not assume that the width of your screen is measured in
meters.
I'm using a tab width of two. But then, I don't use Turbo C
as an editor anymore, which is limited to 80 chars. :)
Seriously: Mostly, if something exceeds 80 chars, it's
boring, uninteresting, boiler-plate implementation details
normal users shouldn't have to look at anyway.
Post by Ed Mulroy [TeamB]
. Ed
Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Ed Mulroy [TeamB]
2008-07-14 22:05:25 UTC
Permalink
I also use a tab width of 2. That means when I press the Tab key, it
inserts two spaces and not '\t' so the source is viewable with a normal
editor without special settings. I also like that spaces are officially
legal in source code.

. Ed
Post by Hendrik Schober
I'm using a tab width of two. But then, I don't use Turbo C
as an editor anymore, which is limited to 80 chars. :)
Seriously: Mostly, if something exceeds 80 chars, it's
boring, uninteresting, boiler-plate implementation details
normal users shouldn't have to look at anyway.
Hendrik Schober
2008-07-15 08:25:30 UTC
Permalink
Post by Ed Mulroy [TeamB]
I also use a tab width of 2. That means when I press the Tab key, it
inserts two spaces and not '\t' so the source is viewable with a normal
editor without special settings.
I use tabs so that the source is viewable using your preferred
tab width using any source editor.
But hey, there's numerous amounts of coding standards regarding
this. I've worked in places where they have one, and in places
where they have others. No need to get excited over this, I
adopt to whatever is the standard for the current project.
In my own code, however, I use my own coding guide. And that is
that tabs are to be preferred at the beginning of the line, so
that everyone can have their own tab width.
Post by Ed Mulroy [TeamB]
I also like that spaces are officially
legal in source code.
Good. So I'm using an officially legal facility. :)



However, I'm much more interested in your opinion regarding
what the code does, rather than how it is formatted.
Post by Ed Mulroy [TeamB]
. Ed
Schobi
Alex Bakaev [TeamB]
2008-07-16 01:21:19 UTC
Permalink
Post by Hendrik Schober
Good. So I'm using an officially legal facility. :)
But I think you use too many spaces (in addition to tabs)

typedef logger< Logger_, MinSeverity_, audience_list<Aud1_,Aud2_,Aud3_>
Post by Hendrik Schober
logger_type;
typedef Logger_ forward_logger_type;
Hendrik Schober
2008-07-28 21:37:26 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Hendrik Schober
Good. So I'm using an officially legal facility. :)
But I think you use too many spaces (in addition to tabs)
Oh well. I like the way I format my code. :)
And as long as it's only mine...
Post by Alex Bakaev [TeamB]
[...]
Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Alex Bakaev [TeamB]
2008-07-28 23:48:16 UTC
Permalink
Post by Hendrik Schober
And as long as it's only mine...
Not an more! :)
Hendrik Schober
2008-07-29 08:12:39 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Hendrik Schober
And as long as it's only mine...
Not an more! :)
What? You want to join? :)

Schobi
Alex Bakaev [TeamB]
2008-07-29 18:14:04 UTC
Permalink
Post by Hendrik Schober
What? You want to join? :)
No - it's just out there now :)
Alex Bakaev [TeamB]
2008-07-14 22:50:51 UTC
Permalink
Post by Ed Mulroy [TeamB]
I would like to acquaint you to a new development for source code, spaces.
Unlike tabs, they do not assume that the width of your screen is measured in
meters.
The world is going to end. Ed and I agree on something <g>
Larry Griffiths
2008-07-15 00:02:33 UTC
Permalink
LOL, and I have parsing code that reads our untits.

I do not normally see any tabs in BDS2007 editor but they show up in my
parsing program and produce unintended results if I dont program for them.

We also prefer to have the BDS2007 editor eliminate the tabs and fill them
in with spaces.

We have older units that still have tabs in them though.

Larry.
Post by Alex Bakaev [TeamB]
Post by Ed Mulroy [TeamB]
I would like to acquaint you to a new development for source code,
spaces. Unlike tabs, they do not assume that the width of your screen is
measured in meters.
The world is going to end. Ed and I agree on something <g>
Thomas Maeder [TeamB]
2008-07-15 15:27:50 UTC
Permalink
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^

Is that something only guys have? :-)
Chris Uzdavinis (TeamB)
2008-07-15 15:38:20 UTC
Permalink
Post by Thomas Maeder [TeamB]
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^
Is that something only guys have? :-)
ROTFL.
--
Chris (TeamB);
Mark
2008-07-15 16:27:18 UTC
Permalink
This newsgroup is about the C++ programming language and its
implementation in some Borland/CodeGear/Embarcadero products. Your
comment is not.

Please direct your browser at http://www.teamb.com/newsgroups and
read the newsgroup descriptions and guidelines. This will help you
find the appropriate newsgroup for your comment.

Sound familiar ; ))
Post by Thomas Maeder [TeamB]
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^
Is that something only guys have? :-)
Larry Griffiths
2008-07-16 00:27:29 UTC
Permalink
Sorry Mark!

Maybe you could keep me abreast of what newsgroup that should be posted in.
( pun intended ).

Larry.
Post by Mark
This newsgroup is about the C++ programming language and its
implementation in some Borland/CodeGear/Embarcadero products. Your
comment is not.
Please direct your browser at http://www.teamb.com/newsgroups and
read the newsgroup descriptions and guidelines. This will help you
find the appropriate newsgroup for your comment.
Sound familiar ; ))
Post by Thomas Maeder [TeamB]
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^
Is that something only guys have? :-)
Larry Griffiths
2008-07-16 00:25:02 UTC
Permalink
LOL, I finally see it. I meant units.

Larry.
Post by Thomas Maeder [TeamB]
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^
Is that something only guys have? :-)
Larry Griffiths
2008-07-16 20:20:38 UTC
Permalink
Thank goodness this little offshoot in this thread has stopped.

I was afraid it would turn into a "tit for tat" thing.

Larry.
Post by Larry Griffiths
LOL, I finally see it. I meant units.
Larry.
Post by Thomas Maeder [TeamB]
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^
Is that something only guys have? :-)
Larry Griffiths
2008-07-18 21:07:49 UTC
Permalink
You better keep an eye on Bob Gonder, Thomas.

He used "__declspec(naked)" in the nativeapi newsgroup. hehe

Larry.
Post by Thomas Maeder [TeamB]
Post by Larry Griffiths
LOL, and I have parsing code that reads our untits.
^^^^^^
Is that something only guys have? :-)
Ed Mulroy [TeamB]
2008-07-18 22:38:07 UTC
Permalink
ROFL!!!!

. Ed
Post by Larry Griffiths
You better keep an eye on Bob Gonder, Thomas.
He used "__declspec(naked)" in the nativeapi newsgroup. hehe
Duane Hebert
2008-07-15 13:34:52 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Ed Mulroy [TeamB]
I would like to acquaint you to a new development for source code,
spaces. Unlike tabs, they do not assume that the width of your screen is
measured in meters.
The world is going to end. Ed and I agree on something <g>
Our standard requires using spaces for tabs so we're with Ed
as well.
Stew
2008-07-15 08:02:27 UTC
Permalink
Post by Hendrik Schober
Over the weekend, I finally went to sourceforge and created a project
so you can go and have a look at it. But beware! That's rather rough
code, there's no documentation at all, and so far I've only compiled
it using VC9. If all this doesn't scare you away, have a look at
http://sourceforge.net/projects/templog/
(There's a cpp file with a small test application. If you debug
through it, this might help you to understand what's going on.)
I'd very much appreciate if you would find the time to have a look
at this lib and tell me what you think. (I'm very interested in what
other compilers have to say about the code.)
CB2007 can't fails to compile logging.h

[BCC32 Error] logging.h(193): E2299 Cannot generate template
specialization from 'templog::log_forwarder<Logger_>'
[BCC32 Error] logging.h(203): F1004 Internal compiler error at 0x57d4420
with base 0x5750000

Stewart
Hendrik Schober
2008-07-15 08:27:35 UTC
Permalink
Post by Stew
Post by Hendrik Schober
Over the weekend, I finally went to sourceforge and created a project
so you can go and have a look at it. But beware! That's rather rough
code, there's no documentation at all, and so far I've only compiled
it using VC9. If all this doesn't scare you away, have a look at
http://sourceforge.net/projects/templog/
(There's a cpp file with a small test application. If you debug
through it, this might help you to understand what's going on.)
I'd very much appreciate if you would find the time to have a look
at this lib and tell me what you think. (I'm very interested in what
other compilers have to say about the code.)
CB2007 can't fails to compile logging.h
[BCC32 Error] logging.h(193): E2299 Cannot generate template
specialization from 'templog::log_forwarder<Logger_>'
[BCC32 Error] logging.h(203): F1004 Internal compiler error at 0x57d4420
with base 0x5750000
I haven't worked with BCC for a very long time, but from
what I read here I feared that would be the case. I do
believe the code to be legal, though.

Thanks for the feedback.
Post by Stew
Stewart
Schobi
Hendrik Schober
2008-07-15 21:49:26 UTC
Permalink
Post by Hendrik Schober
[...]
Post by Stew
CB2007 can't fails to compile logging.h
[BCC32 Error] logging.h(193): E2299 Cannot generate template
specialization from 'templog::log_forwarder<Logger_>'
[BCC32 Error] logging.h(203): F1004 Internal compiler error at 0x57d4420
with base 0x5750000
I haven't worked with BCC for a very long time, but from
what I read here I feared that would be the case. I do
believe the code to be legal, though.
You'd think that, after all this years, I would know
better... <sigh>
Meanwhile the code was ran through GCC and it found a
lot of missing 'template' keywords. I somewhat doubt
that this would stop BCC from tripping over its own
feet, but it might be worth a try.
Post by Hendrik Schober
[...]
Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Alex Bakaev [TeamB]
2008-07-16 21:14:24 UTC
Permalink
Post by Hendrik Schober
You'd think that, after all this years, I would know
better... <sigh>
Meanwhile the code was ran through GCC and it found a
lot of missing 'template' keywords. I somewhat doubt
that this would stop BCC from tripping over its own
feet, but it might be worth a try.
Here is what Comeau gives:

"ComeauTest.c", line 298: error: expression must be a modifiable lvalue
{ TEMPLOG_SOURCE_ASSIGN(rhs); return *this; }

Not sure what the issue is...
Hendrik Schober
2008-07-28 21:44:02 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Hendrik Schober
You'd think that, after all this years, I would know
better... <sigh>
Meanwhile the code was ran through GCC and it found a
lot of missing 'template' keywords. I somewhat doubt
that this would stop BCC from tripping over its own
feet, but it might be worth a try.
Thanks!
Post by Alex Bakaev [TeamB]
"ComeauTest.c", line 298: error: expression must be a modifiable lvalue
{ TEMPLOG_SOURCE_ASSIGN(rhs); return *this; }
Not sure what the issue is...
Neither do I. Interestingly, I put that operator in only
because VC told me it wouldn't be able to generate one for
that class.
OTOH I wonder that como didn't bark at all teh missing
'typename' and 'template' keywords. Do you run it in some
compatibility mode? (I've long since suspected that GCC
sometimes complains about these being missing where there
shouldn't be any, but in the release you tested some where
definitly missing. I would have assumed that como wouldn't
let me get away with these.)

Anyway, I have finally managed uploaded a new release where
I hopefully added all the missing 'typename' and 'template'
keywords. I'd be very interested in Comeau's findings...

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Alex Bakaev [TeamB]
2008-07-28 23:46:33 UTC
Permalink
Post by Hendrik Schober
OTOH I wonder that como didn't bark at all teh missing
'typename' and 'template' keywords. Do you run it in some
compatibility mode? (I've long since suspected that GCC
sometimes complains about these being missing where there
shouldn't be any, but in the release you tested some where
definitly missing. I would have assumed that como wouldn't
let me get away with these.)
VC is definitely lenient with missing template <>.
Post by Hendrik Schober
Anyway, I have finally managed uploaded a new release where
I hopefully added all the missing 'typename' and 'template'
keywords. I'd be very interested in Comeau's findings...
I simply used the online version with whatever defaults it comes with.
Hendrik Schober
2008-07-29 09:31:03 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Hendrik Schober
OTOH I wonder that como didn't bark at all teh missing
'typename' and 'template' keywords. Do you run it in some
compatibility mode? (I've long since suspected that GCC
sometimes complains about these being missing where there
shouldn't be any, but in the release you tested some where
definitly missing. I would have assumed that como wouldn't
let me get away with these.)
VC is definitely lenient with missing template <>.
IIRC, it was cases of 'X::template Y<Z>' where 'template'
was missing. (And of course 'typename X::Y'.)
Post by Alex Bakaev [TeamB]
Post by Hendrik Schober
Anyway, I have finally managed uploaded a new release where
I hopefully added all the missing 'typename' and 'template'
keywords. I'd be very interested in Comeau's findings...
I simply used the online version with whatever defaults it comes with.
Oh. I should create a preprocessed file and run it through that.
(Or I finally download and install the beta version. That would
take more time, though, which I don't have ATM...)

Schobi
Alex Bakaev [TeamB]
2008-07-30 23:05:38 UTC
Permalink
Post by Hendrik Schober
Neither do I. Interestingly, I put that operator in only
I think the problem is that the line_data_ is declared as const:

const unsigned long line_data_;
Alex Bakaev [TeamB]
2008-07-30 23:28:21 UTC
Permalink
Post by Alex Bakaev [TeamB]
const unsigned long line_data_;
Of course, the file_data suffers from the same problem.
Hendrik Schober
2008-08-01 16:55:26 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Alex Bakaev [TeamB]
const unsigned long line_data_;
Of course, the file_data suffers from the same problem.
Doh! I should have seen this.
During the last decade I have learned to believe VC
if it complains it can't create an assigment op. (The
problem is, when it barks that at me, I usually don't
need one. So I don't find that warning very helpful.)
Therefor I didn't doubt that the compiler ws right,
but I still didn't take the time to look at this.

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Alex Bakaev [TeamB]
2008-08-01 17:19:33 UTC
Permalink
Post by Hendrik Schober
but I still didn't take the time to look at this.
:)
Hendrik Schober
2008-08-04 19:35:11 UTC
Permalink
Post by Hendrik Schober
but I still didn't take the time to look at this.
:)
For the last few months, I have been juggling three
jobs. Being a father of four, this doesn't leave very
much room for anything else.

Schobi
(by now almost back to only two jobs)
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Alex Bakaev [TeamB]
2008-08-04 20:37:27 UTC
Permalink
Post by Hendrik Schober
For the last few months, I have been juggling three
jobs. Being a father of four, this doesn't leave very
much room for anything else.
Schobi
(by now almost back to only two jobs)
Well, I hope you do not suffer from exhaustion! Having only one (now 8
y.o.), I can't possibly imagine what four are like <g>
Hendrik Schober
2008-08-06 08:10:32 UTC
Permalink
Post by Alex Bakaev [TeamB]
Post by Hendrik Schober
For the last few months, I have been juggling three
jobs. Being a father of four, this doesn't leave very
much room for anything else.
Schobi
(by now almost back to only two jobs)
Well, I hope you do not suffer from exhaustion! Having only one (now 8
y.o.), I can't possibly imagine what four are like <g>
Actually, four are easier than two. :)
Three jobs, however, are harder than two.

Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Alex Bakaev [TeamB]
2008-08-06 17:00:03 UTC
Permalink
Post by Hendrik Schober
Actually, four are easier than two. :)
Three jobs, however, are harder than two.
As long as nobody claims that two are easier than one! :)

(I think there is a conspiracy among those with more than one child.
They desperately want to exact revenge on those with a single child :) )

f-u to non-tech.

.a

Sergiy Kanilo
2008-07-16 04:20:55 UTC
Permalink
Post by Hendrik Schober
some_logger << "x=" << x << ", y=" << y;
[...]
Post by Hendrik Schober
The problem with the stream idiom is that it isn't easy to chunk
information in a deterministic way. You just shove everything down
'operator<<' into some buffer, and when that buffer is full it will
get flushed to the target device. The only way to control flushing
is by explicitly and manually inserting flushing tokens into the
stream. For logging, this isn't acceptable, because flushing is the
default and must not be forgetten.
But given code like the above, when you are inside 'operator<<' you
cannot tell whether it is its first invocation in that line, its
last, or one in between. So you don't know whether to flush the
information given of not.
it is not too hard to find the start and end of the sequence,
here's basic idea I use in my logging

class StreamLink;
class Stream
{
public:
virtual std::ostream& actualStream() =0;
virtual addLineHeader() =0;
virtual flushData() =0;
template<typename T>
StreamLink operator<<( T const& object )
{
return StreamLink( *this ) << object;
}
};

class StreamLink
{
public:
StreamLink( Stream& stream ):ptr_( &stream )
{
stream.addLineHeader();
}
StreamLink( StreamLink const& other ):ptr_( other.ptr_ )
{
other.ptr_ =0;
}
~StreamLink()
{
if( ptr_ != 0 )
{
ptr_->flushData();
}
}
template<typename T>
StreamLink operator<<( T const& object )
{
ptr_->actualStream() << object;
return *this;
}
private:
mutable Stream* ptr_;
};

Cheers,
Serge
Hendrik Schober
2008-07-28 22:06:00 UTC
Permalink
Post by Sergiy Kanilo
Post by Hendrik Schober
some_logger << "x=" << x << ", y=" << y;
[...]
Post by Hendrik Schober
The problem with the stream idiom is that it isn't easy to chunk
information in a deterministic way. You just shove everything down
'operator<<' into some buffer, and when that buffer is full it will
get flushed to the target device. The only way to control flushing
is by explicitly and manually inserting flushing tokens into the
stream. For logging, this isn't acceptable, because flushing is the
default and must not be forgetten.
But given code like the above, when you are inside 'operator<<' you
cannot tell whether it is its first invocation in that line, its
last, or one in between. So you don't know whether to flush the
information given of not.
it is not too hard to find the start and end of the sequence,
here's basic idea I use in my logging
[Code snipped]
Yes, but you're doing this at run-time, while I was talking
about compile-time.
Here's (a slightly simplified version of) what I do:

template< class ParamList, typename T >
inline
proxy< tuple<const T*,ParamList> >
operator<<( const proxy<ParamList>& lfwd, const T& p )
{
typedef tuple<const T*,ParamList> > tuple_t;
return proxy<tuple_t>( tuple_t(&p,lfwd.parameters) );
}

At the end, when all stream arguments are strung together, I
have the classical recursive struct that passes as a list in
template-meta land:

struct {
const T4* head;
struct {
const T3* head;
struct {
const T2* head;
struct {
const T1* head;
nil tail;
} tail;
} tail;
} tail;
};

Currently I see no way to find out which is the last call to
'operator<<' and neither do I see a way to find out which is
the first dtor called. Nor do I see how to get at the list
from the last (innermost) dtor. But then I only build the list
backwards because it's easier to do and it doesn't matter when
recursivly processing the items in it. If I could find out
which dtor is the first one called, I think I could, from it,
walk the whole list if I built the list forward and have that
one be the first (outermost) item.
<thinks>
I'll have to ponder this when I have more time. There might be
a way to avoid the macro.
Post by Sergiy Kanilo
Cheers,
Serge
Schobi
--
***@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner
Loading...