[log] Yet more questions for Andrey: formatting severity

By default, severity is printed as integer. What's the easiest way to print the corresponding string (e.g. "info" for severity 0, "warn" for severity 1, and so on)? I tried defining operator<< for my severity enum, but attr<severity_level> doesn't work; that is, the output operator doesn't get invoked (I assume because attribute "Severity" is internally of type "int" and not of my enum type). Thanks a lot! Igor

On Sat, 2008-08-30 at 23:16 -0700, Igor Nazarenko wrote:
By default, severity is printed as integer. What's the easiest way to print the corresponding string (e.g. "info" for severity 0, "warn" for severity 1, and so on)?
I tried defining operator<< for my severity enum, but attr<severity_level> doesn't work; that is, the output operator doesn't get invoked (I assume because attribute "Severity" is internally of type "int" and not of my enum type).
Yes, the severity level is stored as an int, and therefore the attr formatter uses operator<< for ints. Right now you can either define your own formatter that will accept an int and transform it into a string, or develop your own attribute and logger to store the level as an enum (then the attr formatter should be used with explicitly specified enum type). I haven't decided yet how to solve this problem best in the library.

On Sun, 31 Aug 2008 11:07:29 +0200, Andrey Semashev <andrey.semashev@gmail.com> wrote:
On Sat, 2008-08-30 at 23:16 -0700, Igor Nazarenko wrote:
By default, severity is printed as integer. What's the easiest way to print the corresponding string (e.g. "info" for severity 0, "warn" for severity 1, and so on)?
I tried defining operator<< for my severity enum, but attr<severity_level> doesn't work; that is, the output operator doesn't get invoked (I assume because attribute "Severity" is internally of type "int" and not of my enum type).
Yes, the severity level is stored as an int, and therefore the attr formatter uses operator<< for ints. Right now you can either define your own formatter that will accept an int and transform it into a string, or develop your own attribute and logger to store the level as an enum (then the attr formatter should be used with explicitly specified enum type).
I haven't decided yet how to solve this problem best in the library.
Igor, I'm also interested in your solution (as currently I'm also writing ints to my log files). I would prefer not to define a new logger though. While I like Andrey's logging library a lot I'm not so happy about having different logger types which I need to combine then somehow if I want to use the features of all those logger types (as it is done with severity_channel_logger which combines the severity_logger and the channel_logger; if we add more loggers we get dozens of combinations). I'm not sure either if this approach fits into Andrey's design. According to the definitions at http://boost-log.sourceforge.net/libs/log/doc/html/log/defs.html a logger is a log source (which is a good definition as it is easy to understand). But then it's a bit strange if you need to define a new logger only to customize the output? Maybe the decorator pattern could be used here (see http://en.wikipedia.org/wiki/Decorator_pattern for example)? Let's say you want to convert the severity int to a string. You'll define a decorator class and chain the decorator and the logger: logger log; my_decorator deco(log); BOOST_LOG(deco) << "Test"; The decorator behaves like the logger (same interface). It processes some attributes in open_record (like converting the enumeration to a string) before it forwards the call to logger::open_record. That would make it possible to process attributes without introducing new classes like my_decorator_logger, my_decorator_severity_logger, my_decorator_channel_logger, my_decorator_severity_channel_logger etc. depending on what features you need. Of course you could also combine decorators with: logger log; my_decorator1 deco1(log); my_decorator2 deco2(deco1); BOOST_LOG(deco2) << "Test"; Boris

On Sun, 2008-08-31 at 12:56 +0200, Boris wrote:
On Sun, 31 Aug 2008 11:07:29 +0200, Andrey Semashev <andrey.semashev@gmail.com> wrote:
Yes, the severity level is stored as an int, and therefore the attr formatter uses operator<< for ints. Right now you can either define your own formatter that will accept an int and transform it into a string, or develop your own attribute and logger to store the level as an enum (then the attr formatter should be used with explicitly specified enum type).
I haven't decided yet how to solve this problem best in the library.
Igor, I'm also interested in your solution (as currently I'm also writing ints to my log files). I would prefer not to define a new logger though. While I like Andrey's logging library a lot I'm not so happy about having different logger types which I need to combine then somehow if I want to use the features of all those logger types (as it is done with severity_channel_logger which combines the severity_logger and the channel_logger; if we add more loggers we get dozens of combinations).
But would you actually need all these combinations? Most likely, you'll define a couple of loggers with most frequently used features included and use them throughout the application. Where needed, however, loggers with more specific features can be defined on a per-case basis.
I'm not sure either if this approach fits into Andrey's design. According to the definitions at http://boost-log.sourceforge.net/libs/log/doc/html/log/defs.html a logger is a log source (which is a good definition as it is easy to understand). But then it's a bit strange if you need to define a new logger only to customize the output?
Not exactly. Having defined a logger, you customize the level type, which allows to customize the output later.
Maybe the decorator pattern could be used here (see http://en.wikipedia.org/wiki/Decorator_pattern for example)? Let's say you want to convert the severity int to a string. You'll define a decorator class and chain the decorator and the logger:
While I kind of like the idea of wrapping loggers, this particular application does not seem valid to me. First, it is formatters that are intended to convert attribute values into a sink-specific format. For example, we could have both a text sink and a binary sink. The severity level is best to be put as a string into the text sink, but as a number into the binary sink. Second, in case of decorators, the attribute value has to be converted before the call to open_record, which means before the filtering takes place. This would lead to a permanent performance overhead, even if no logging is done. This is not acceptable. I'm leaning towards allowing to customize the level type for the severity logger, I just haven't figured out how.

On Sun, 31 Aug 2008 13:58:47 +0200, Andrey Semashev <andrey.semashev@gmail.com> wrote:
[...]While I kind of like the idea of wrapping loggers, this particular application does not seem valid to me. First, it is formatters that are intended to convert attribute values into a sink-specific format. For example, we could have both a text sink and a binary sink. The severity level is best to be put as a string into the text sink, but as a number into the binary sink. Second, in case of decorators, the attribute value
You are right, sounds reasonable to me. As the formatter is a function object it should be possible to create a new formatter fmt::severity. It would only need to access the attribute Severity and write a string instead of the int?
has to be converted before the call to open_record, which means before the filtering takes place. This would lead to a permanent performance overhead, even if no logging is done. This is not acceptable.
Let me talk about something different then as I agree that the formatter is a good choice for what Igor was asking. :) The reason why different loggers exist is that each logger tries to update a different attribute in open_record()? If I compare for example basic_logger and severity_logger the most important difference as far as I can tell is: m_pSeverity->set_value(args[keywords::severity | m_DefaultSeverity]); The severity attribute is set just before the log record is written in severity_logger::open_record(). Now I can create a new attribute and even add it to any logger today. However to make a logger update the attribute automatically I can't inject a line like the one above. Instead I need to create a whole new logger. What I wonder is if the logger can't be made more flexible so we don't need to create different loggers just because they update different attributes. Even if the decorator pattern doesn't fit creating a new logger from scratch only to make a logger update an attribute sounds like quite a lot of development overhead? Boris
participants (3)
-
Andrey Semashev
-
Boris
-
Igor Nazarenko