Boost logo

Boost :

From: Ivan Dubrov (WFrag_at_[hidden])
Date: 2004-01-08 10:30:33


Here the code of simple logging facility over std::iostream's. I think
it could be useful - no inheritance, just works with every stream!

Usage:
#include "logger.hpp"

int main()
{
   using namespace utility;
   using namespace std;

   const long SOUND = 1;
   const long VIDEO = 2;

   std::cout << speak_barrier(0);
   // Show one VIDEO subsystem messages
   std::cout << speak_filter(VIDEO);
   // Show only messages with level <= 10
   std::cout << speak_barrier(5);

   cout << speak_bits(0) << speak_level(5) << "Application started." <<
endl;
   cout << speak_bits(0) << speak_level(0) << "Something wrong is
happening..." << endl;
   cout << speak_level(-5) << speak_bits(SOUND) << "Critical error in
sound subsystem!" << endl;
   cout << speak_level(-5) << speak_bits(VIDEO) "Critical error in video
subsystem!" << endl;
   // speak_bits(0) means "no bit filter"
   cout << speak_bits(0) << speak_level(5) << "Application finished." <<
endl;
     return 0;
}

Code:
#include <ostream>
#include <iterator>
#include <streambuf>
#include <locale>
#include <ios>
#include <algorithm>
#include <cassert>

namespace utility
{
   namespace impl
   {
     enum Constants
     {
       SPEAK_LEVEL = 0,
       SPEAK_BARRIER = 1,
       SPEAK_BITS = 2,
       SPEAK_FILTER = 3,
       PARAMS_COUNT = 4,
       OLD_STREAM = 4,
       REGISTERED = 5,
       PARAMS = 6,
     };

     struct LogParams
     {
       LogParams()
         : oldStream(0)
       {
         std::fill(values, values + PARAMS_COUNT, 0);
       }

       bool checkOutput()
       {
         return values[SPEAK_LEVEL] <= values[SPEAK_BARRIER] &&
              ((values[SPEAK_BITS] & values[SPEAK_FILTER]) ||

                values[SPEAK_BITS] == 0);
       }

       long values[PARAMS_COUNT];
       void* oldStream;
     };

     template<int tag>
     int allocateIndex()
     {
       static int index = std::ios_base::xalloc();
       return index;
     }

     template<typename Ch_, typename Tr_>
     inline void callback(std::ios_base::event e, std::ios_base& stream,
int arg)
     {
       void*& ptrRef = stream.pword(allocateIndex<PARAMS>());
       LogParams* params = reinterpret_cast<LogParams*>(ptrRef);
       ptrRef = 0;

       if(params)
       {
         if(e == std::ios_base::erase_event)
         {
           delete params;
         } else if(e == std::ios_base::copyfmt_event)
         {
           params = new LogParams(*params);
           if(params->oldStream) // other stream was switched off?
           {
             params->oldStream =
             static_cast<std::basic_ios<Ch_, Tr_>& >(stream).rdbuf(0);
           }
           ptrRef = params;
         }
       }
     }

     template<typename Ch_, typename Tr_>
     void setParams(std::basic_ostream<Ch_, Tr_>& out, int tag, long value)
     {
       // register callback if wasn't registered
       if(out.iword(allocateIndex<REGISTERED>()) == 0)
       {
         out.register_callback(&callback<Ch_, Tr_>, 0);
         out.iword(allocateIndex<REGISTERED>()) = 1;
       }
       LogParams* params =
        reinterpret_cast<LogParams*>(out.pword(allocateIndex<PARAMS>()));

       if(params == 0)
       {
         params = new LogParams;
         out.pword(allocateIndex<PARAMS>()) = params;
       }

       bool oldSit = params->checkOutput();
       params->values[tag] = value;
       bool newSit = params->checkOutput();

       // if situation changed
       if(newSit != oldSit)
       {
         if(newSit) // restore old stream
         {
           assert(params->oldStream != 0);
           // check if dummy stream wasn't switched to another buffer
           // (otherwise leave new buffer)
           if(out.rdbuf() == 0)
           {
             out.rdbuf(reinterpret_cast<std::basic_streambuf<Ch_,
Tr_>*>(params->oldStream));
           }
           params->oldStream = 0;
         }
         else // set dummy stream buffer
         {
           assert(params->oldStream == 0);
           params->oldStream = out.rdbuf(0);
         }
       }
     }

     /// \brief logger integral parameters
     template<int Tag_>
     struct stream_param
     {
       stream_param(long value)
         : value_(value) {}
       long value_;
     };

     /// \brief sets one of the logger parameters
     template<typename Ch_, typename Tr_, int Tag_> inline
     std::basic_ostream<Ch_, Tr_>&
     operator <<(std::basic_ostream<Ch_, Tr_>& out,
                 impl::stream_param<Tag_> param)
     {
       impl::setParams(out, Tag_, param.value_);
       return out;
     }
   }

   /// \brief defines speak level value
   typedef impl::stream_param<impl::SPEAK_LEVEL> speak_level;

   /// \brief defines speak barrier value
   typedef impl::stream_param<impl::SPEAK_BARRIER> speak_barrier;

   /// \brief defines speak bits value
   typedef impl::stream_param<impl::SPEAK_BITS> speak_bits;

   /// \brief defines speak bits filtervalue
   typedef impl::stream_param<impl::SPEAK_FILTER> speak_filter;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk