Per the previous discussion on iostream-free log4cxx, this alternative API should be completely optional. Ideally included in its own header (log4cxx/loggingstream.h?) and delegating to the primary API.
Yup, I set it up entirely in a header.
A couple of issues:
1. It would be good that logging streams weren't limited to one character type, so having a template like:
template<class Elem, class Tr = char_traits<Elem>> class log4cxx::basic_logging_stream : std::basic_ostream<Elem, Tr> {
}
would be good, though there might be a log4cxx::stream and log4cxx::wstream expansions of that template.
Great minds think alike. ;-)
2. The LOG4CXX_.* macros provide context values (__FILE__ and __LINE__ currently, may be expanded to include __func__). How would you see adding that information into the logging stream?
I used a macro for instantiating the stream. It passes in the file and line number at the point of instantiation. So, the current model is you would use a new stream instance for each log event you generate.
3. What would trigger the creation of a logging event? My initial take is that it should be a call to flush() or close().
I made an enum with it's own endl equivalent. I'm trying to figure out how to use the standard iostream endl, but have hit a snag there.
4. Would a logging stream be able to create multiple logging events?
Right now no. However, I could restructure things so the "endl" is a macro, which passes in __FILE__ and __LINE__. Then I could make the flush also reset the stream and you could do multiple logging events. I don't expect much of a win from this, and I haven't come up with a way to do it which wouldn't add a bit of overhead.
5. When would the level be checked to determine if the stream is enabled. My take would be on stream creation and after calls to flush. If it were checked on each insertion operation, messages could look pretty funky if the configuration was modified while a message was being assembled.
Right now I'm doing it at stream creation. I store it in a const member variable, which allows the compiler to optimize all the checks for each operator<< into a single check. If I did multiple events per stream, I should think I'd probably have to do a check on each flush. Perhaps not though. Maybe each instantion would correspond to a check, and reuse of the stream would imply that dong a new check is not necessary.
6. Would the level of a logging stream be able to be modified? It might be convenient, however you would not be able to change the level mid-way through construction of a message since earlier parts might have been no-op'd. My take is that inserting a LevelPtr would imply a flush.
I chose to go with the level being locked. Given that creating a LoggingStream is cheap, and keeping things fixed allows the compiler to make better optimization choices, I think this is the right way to go.
--Chris
