Subject: Re: [boost] [Log] Pre-review questions
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2010-03-14 15:00:42


On 03/14/2010 06:29 PM, Christian Holmquist wrote:
>
> Simple task 1
> I've two source level attributes, System and Severity. I wish to create a
> log macro that takes these two arguments.

[snip]

> The above is not a complicated scenario and I should be able to quickly find
> an answer. Maybe I've just missed it..:)

Well, depending on how you use the "System" attribute, you can take
either of the following approaches:

1. Use the severity_channel_logger. The severity attribute will handle
your severity levels, and the "System" attribute will be represented as
a channel. This means that you would have to have a logger per "System".

   typedef src::severity_channel_logger<
     SeverityLevel,
     System
> my_logger_t;

   my_logger_t lg_SYSTEM_A(keywords::channel = SYSTEM_A);
   my_logger_t lg_SYSTEM_B(keywords::channel = SYSTEM_B);

   BOOST_LOG_SEV(lg_SYSTEM_A, INFO) << "Hello";

If you want to, you can define your macro like this:

   #define LOG(x, y, z) BOOST_LOG_SEV(lg_ ## x, y) << z

   LOG(SYSTEM_A, INFO, "Hello");

2. If having several loggers is not an option, but the system attribute
is needed occasionally, you can add the attribute as a tag. The
technique is described here:

http://tinyurl.com/y8a2gfv

3. If the system attribute is needed all the time, then I might suggest
to develop a logger feature, pretty much like it is described in the
docs by the link I posted, but with one minor difference. The attribute
should be added to the logger on its constructor, and only modified on
the open_record call. Altering the example at the link, it should look
something like that:

   template< typename BaseT >
   class system_feature :
     public BaseT
   {
   public:
     typedef typename BaseT::string_type string_type;
     typedef typename BaseT::attribute_set_type attribute_set_type;
     typedef typename BaseT::threading_model threading_model;
     typedef typename BaseT::record_type record_type;

     shared_ptr< attrs::mutable_constant< System > > m_pSystem;

   public:
     system_feature() :
       m_pSystem(new attrs::mutable_constant< System >(SYSTEM_A))
     {
       this->add_attribute_unlocked("System", m_pSystem);
     }
     system_feature(record_tagger_feature const& that) :
       BaseT(static_cast< BaseT const& >(that)),
       m_pSystem(new attrs::mutable_constant< System >(SYSTEM_A))
     {
       this->add_attribute_unlocked("System", m_pSystem);
     }
     template< typename ArgsT >
     system_feature(ArgsT const& args) :
       BaseT(args),
       m_pSystem(new attrs::mutable_constant<
         System
>(args[keywords::system]))
     {
       this->add_attribute_unlocked("System", m_pSystem);
     }

     typedef typename src::strictest_lock<
       boost::lock_guard< threading_model >,
       typename BaseT::open_record_lock
>::type open_record_lock;

   protected:
     template< typename ArgsT >
     record_type open_record_unlocked(ArgsT const& args)
     {
       m_pSystem->set_value(args[keywords::system]);
       return BaseT::open_record_unlocked(args);
     }
   };

> Simple task 2
> Create a custom filter without using any Lambda magic.
>
> struct Filter
> {
> System sys;
> SeverityLevel sev;
>
> bool operator()(???)
> {
> // pseudo-code, since I don't know how to write this
> return Attributes["System"] == sys&& Attributes["SeverityLevel"]>=
> sev;
> }
> };

Well, if you want to develop a filter from ground, here you go:

   struct Filter
   {
     typedef bool result_type;

     System m_sys;
     SeverityLevel m_sev;

     result_type operator() (attribute_values_view const& attrs) const
     {
       shared_ptr< logging::attribute > attr = attrs["System"];
       if (attr)
       {
         optional< System > sys = attr->get< System >();
         if (!sys)
           throw runtime_error("The System attribute has invalid type");

         if (sys.get() != m_sys)
           return false;
       }
       else
         throw runtime_error("The System attribute not found");

       attr = attrs["Severity"];
       if (attr)
       {
         optional< SeverityLevel > sev = attr->get< SeverityLevel >();
         if (!sev)
           throw runtime_error(
             "The Severity attribute has invalid type");

         if (sev.get() != m_sev)
           return false;
       }
       else
         throw runtime_error("The Severity attribute not found");

       return true;
     }
   };

But honestly, it would be much simpler if you used the tools provided by
the library.