liborigin2 13/09/2010
/builddir/build/BUILD/liborigin2-20101029/logging.hpp
Go to the documentation of this file.
00001 //  Boost general library logging.hpp header file  ---------------------------//
00002 
00003 //  (C) Copyright Jean-Daniel Michaud 2007. Permission to copy, use, modify, 
00004 //  sell and distribute this software is granted provided this copyright notice 
00005 //  appears in all copies. This software is provided "as is" without express or 
00006 //  implied warranty, and with no claim as to its suitability for any purpose.
00007 
00008 //  See http://www.boost.org/LICENSE_1_0.txt for licensing.
00009 //  See http://code.google.com/p/loglite/ for library home page.
00010 
00011 #ifndef BOOST_LOGGING_HPP
00012 #define BOOST_LOGGING_HPP
00013 
00014 #include <list>
00015 #include <stack>
00016 #include <string>
00017 #include <ostream>
00018 #include <sstream>
00019 #include <stdio.h>
00020 #include <algorithm>
00021 #include <exception>
00022 #include <boost/shared_ptr.hpp>
00023 #include <boost/tuple/tuple.hpp>
00024 #ifndef BOOST_CONFIG_HPP
00025 #  include <boost/config.hpp>
00026 #endif
00027 #if defined(BOOST_HAS_THREADS)
00028 #  include <boost/thread/thread.hpp>
00029 #  include <boost/thread/condition.hpp>
00030 #endif // BOOST_HAS_THREADS
00031 #include <boost/date_time/gregorian/gregorian.hpp>
00032 #include <boost/date_time/posix_time/posix_time.hpp>
00033 #include <boost/format.hpp>
00034 
00035 #ifndef BOOST_NO_CODE_GENERATION_FOR_LOG
00036 #define BOOST_LOG_INIT( format )                                               \
00037 {                                                                              \
00038   boost::logging::logger *l = boost::logging::logger::get_instance();          \
00039   assert(l);                                                                   \
00040   l->add_format(format);                                                       \
00041 }
00042 
00043 #define BOOST_LOG_ADD_OUTPUT_STREAM( sink )                                    \
00044 {                                                                              \
00045   boost::logging::logger *l = boost::logging::logger::get_instance();          \
00046   assert(l);                                                                   \
00047   l->add_sink(sink);                                                           \
00048 }
00049 
00050 #define BOOST_LOG(level, qualifier, _trace)                                    \
00051 {                                                                              \
00052   boost::logging::logger *l = boost::logging::logger::get_instance();          \
00053   assert(l);                                                                   \
00054   if (l->get_global_max_log_level() >= level)                                  \
00055   {                                                                            \
00056     if (l->m_string_stream.str() != "")                                        \
00057       l->m_string_stack.push(l->m_string_stream.str());                        \
00058                                                                                \
00059     l->m_string_stream.str("");                                                \
00060     l->m_string_stream << _trace;                                              \
00061     l->trace(level, qualifier, l->m_string_stream.str(), __FILE__, __LINE__);  \
00062     if (!l->m_string_stack.empty())                                            \
00063     {                                                                          \
00064       l->m_string_stream.str(l->m_string_stack.top());                         \
00065       l->m_string_stack.pop();                                                 \
00066     }                                                                          \
00067   }                                                                            \
00068 }
00069 
00070 #define BOOST_LOG_( level, _trace )                                            \
00071   { BOOST_LOG(level, boost::logging::log, _trace) }
00072 
00073 #define BOOST_LOG_UNFORMATTED(level, qualifier, _trace)                        \
00074 {                                                                              \
00075   boost::logging::logger *l = boost::logging::logger::get_instance();          \
00076   assert(l);                                                                   \
00077   if (l->get_global_max_log_level() >= level)                                  \
00078   {                                                                            \
00079     if (l->m_string_stream.str() != "")                                        \
00080       l->m_string_stack.push(l->m_string_stream.str());                        \
00081                                                                                \
00082     l->m_string_stream.str("");                                                \
00083     l->m_string_stream << _trace;                                              \
00084     l->unformatted_trace(level, qualifier,                                     \
00085                          l->m_string_stream.str(), __FILE__, __LINE__);        \
00086     if (!l->m_string_stack.empty())                                            \
00087     {                                                                          \
00088       l->m_string_stream.str(l->m_string_stack.top());                         \
00089       l->m_string_stack.pop();                                                 \
00090     }                                                                          \
00091   }                                                                            \
00092 }
00093 
00094 #define BOOST_LOG_FINALIZE()                                                   \
00095 {                                                                              \
00096     boost::logging::logger *l = boost::logging::logger::get_instance();        \
00097     assert(l);                                                                 \
00098     l->clear();                                                                \
00099 }
00100 #else // !BOOST_NO_CODE_GENERATION_FOR_LOG
00101 #define BOOST_LOG_INIT( format )
00102 #define BOOST_LOG_ADD_OUTPUT_STREAM( sink )
00103 #define BOOST_LOG(level, qualifier, _trace)
00104 #define BOOST_LOG_( level, _trace )
00105 #define BOOST_LOG_UNFORMATTED(level, qualifier, _trace)
00106 #endif // BOOST_NO_CODE_GENERATION_FOR_LOG
00107 
00108 #define BOOST_MAX_LINE_STR_SIZE 20 // log(2^64)
00109 #define BOOST_LEVEL_UP_LIMIT    999
00110 
00111 namespace boost {
00112 
00113   namespace logging {
00114 
00115 //  Logging forward declarations ---------------------------------------------//
00116     class log_element;
00117     class level_element;
00118     class qualifier;
00119     class trace_element;
00120     class format;
00121     class sink;
00122     class logger;
00123     
00124 //  Logging typedefs declarations --------------------------------------------//
00125     typedef enum { LEVEL = 0, QUALIFIER, TRACE, FILENAME, LINE }   param_e;
00126     typedef enum { SINK = 0, FORMAT }                   sink_format_assoc_e;
00127     typedef std::list<boost::shared_ptr<log_element> >  element_list_t;
00128     typedef std::list<boost::shared_ptr<std::ostream> > stream_list_t;
00129     typedef unsigned short                              level_t;
00130     typedef tuple<level_t, 
00131                   const qualifier *,
00132                   std::string, 
00133                   std::string, 
00134                   unsigned int>                         log_param_t;
00135     typedef std::list<format>                           format_list_t;
00136     typedef tuple<sink, format&>                        sink_format_assoc_t;
00137     typedef std::list<sink_format_assoc_t>             sink_format_assoc_list_t;
00138     typedef std::list<qualifier *>                      qualifier_list_t;
00139 
00140 //  Used for shared_ptr() on statically allocated log_element ----------------//
00141     struct null_deleter
00142     { void operator()(void const *) const {} };
00143 
00144 //  Qualifier class declaration ----------------------------------------------//
00145     class qualifier
00146     {
00147     public:
00148       qualifier() {}
00149       inline std::string to_string() const { return m_identifier; }
00150       virtual bool operator==(const qualifier &q) { return false; }
00151     protected:
00152       std::string m_identifier;
00153     };
00154 
00155     class log_qualifier : public qualifier 
00156     {
00157     public:
00158       log_qualifier() { m_identifier = "log"; }
00159       bool operator==(const qualifier &q) 
00160       { return (dynamic_cast<const log_qualifier *>(&q) != NULL); }
00161     };
00162 
00163     class notice_qualifier : public qualifier
00164     {
00165     public:
00166       notice_qualifier() { m_identifier = "notice"; }
00167       bool operator==(const qualifier &q) 
00168       { return (dynamic_cast<const notice_qualifier *>(&q) != NULL); }
00169     };
00170 
00171     class warning_qualifier : public qualifier
00172     {
00173     public:
00174       warning_qualifier() { m_identifier = "warning"; }
00175       bool operator==(const qualifier &q) 
00176       { return (dynamic_cast<const warning_qualifier *>(&q) != NULL); }
00177     };
00178 
00179     class error_qualifier : public qualifier
00180     {
00181     public:
00182       error_qualifier() { m_identifier = "error"; }
00183       bool operator==(const qualifier &q) 
00184       { return (dynamic_cast<const error_qualifier *>(&q) != NULL); }
00185     };
00186 
00187 //  Element classes declaration  ---------------------------------------------//
00188     class log_element
00189     {
00190     public:
00191       virtual std::string to_string() { assert(0); return ""; };
00192 
00193       virtual std::string visit(format &f, const log_param_t &log_param);
00194     };
00195     
00196     class level_element : public log_element
00197     {
00198     public:
00199       std::string to_string(level_t l) 
00200       { 
00201         return str(boost::format("%i") % l);
00202       };
00203 
00204       std::string visit(format &f, const log_param_t &log_param);
00205     };
00206     
00207     class filename_element : public log_element
00208     {
00209     public:
00210       std::string to_string(const std::string &f) { return f; }
00211       std::string visit(format &f, const log_param_t &log_param);
00212     };
00213     
00214     class line_element : public log_element
00215     {
00216     public:
00217       std::string to_string(unsigned int l) 
00218       {
00219         return str(boost::format("%i") % l);
00220       }
00221       std::string visit(format &f, const log_param_t &log_param);
00222     };
00223     
00224     class date_element : public log_element
00225     {
00226     public:
00227       std::string to_string()
00228       {
00229         boost::gregorian::date d(boost::gregorian::day_clock::local_day());
00230         return boost::gregorian::to_iso_extended_string(d);
00231       }
00232     };
00233     
00234     class time_element : public log_element
00235     {
00236     public:
00237       std::string to_string() 
00238       { 
00239         boost::posix_time::ptime 
00240           t(boost::posix_time::microsec_clock::local_time());
00241         return boost::posix_time::to_simple_string(t); 
00242       };
00243     };
00244     
00245     class trace_element : public log_element
00246     {
00247     public:
00248       std::string to_string(const std::string& s) { return s; };
00249 
00250       std::string visit(format &f, const log_param_t &log_param);
00251     };
00252 
00253     class eol_element : public log_element
00254     {
00255     public:
00256       std::string to_string() { return "\n"; };
00257     };
00258 
00259     class literal_element : public log_element
00260     {
00261     public:
00262       explicit literal_element(const std::string &l) : m_literal(l) {}
00263       std::string to_string() { return m_literal; };
00264     private:
00265       std::string m_literal;
00266     };
00267 
00268     class qualifier_element : public log_element
00269     {
00270     public:
00271       qualifier_element(const qualifier &lq) 
00272       {
00273         m_qualifier_identifier = lq.to_string();
00274       }
00275       std::string to_string() { return m_qualifier_identifier; };
00276     private:
00277       std::string m_qualifier_identifier;
00278     };
00279 
00280 //  Format class declatation -------------------------------------------------//
00281     class format
00282     {
00283     public:
00284       format(log_element &e)
00285         : m_identifier("unnamed") 
00286       {
00287         boost::shared_ptr<boost::logging::log_element> p(&e, null_deleter());
00288         m_element_list.push_back(p);
00289       }
00290 
00291       format(log_element &e, const std::string &identifier) 
00292         : m_identifier(identifier) 
00293       {
00294         boost::shared_ptr<boost::logging::log_element> p(&e, null_deleter());
00295         m_element_list.push_back(p);
00296       }
00297 
00298       format(element_list_t e) 
00299         : m_element_list(e), m_identifier("unnamed") {}
00300 
00301       format(element_list_t e, const std::string &identifier) 
00302         : m_element_list(e), m_identifier(identifier) {}
00303 
00304       std::string produce_trace(const log_param_t &log_param)
00305       {
00306         element_list_t::iterator e_it = m_element_list.begin();
00307         std::stringstream str_stream;
00308         for (; e_it != m_element_list.end(); ++e_it)
00309         {
00310       str_stream << (*e_it)->visit(*this, log_param);
00311         }
00312 
00313         return str_stream.str();
00314       }
00315 
00316       // Visitors for the log elements
00317       std::string accept(log_element &e)
00318       {
00319           return e.to_string();
00320       }
00321       std::string accept(level_element &e, level_t l)
00322       {
00323           return e.to_string(l);
00324       }
00325       std::string accept(trace_element &e, const std::string& s)
00326       {
00327         return e.to_string(s);
00328       }
00329       std::string accept(filename_element &e, const std::string& s)
00330       {
00331         return e.to_string(s);
00332       }
00333       std::string accept(line_element &e, unsigned int l)
00334       {
00335         return e.to_string(l);
00336       }
00337 
00338     private:
00339       element_list_t    m_element_list;
00340       std::string       m_identifier;
00341     };
00342 
00343 //  Sink class declaration ---------------------------------------------------//
00344     class sink
00345     {
00346     public:
00347       sink(std::ostream *s, level_t max_log_level = 1)
00348       {
00349         if (s)
00350           if (*s == std::cout || *s == std::cerr || *s == std::clog)
00351             m_output_stream.reset(s, null_deleter());
00352           else
00353             m_output_stream.reset(s);
00354 
00355         set_max_log_level(max_log_level);
00356       }
00357 
00358       void set_max_log_level(level_t max_log_level)
00359       { 
00360         m_max_log_level = ((BOOST_LEVEL_UP_LIMIT < max_log_level) 
00361           ? BOOST_LEVEL_UP_LIMIT : max_log_level);
00362       }
00363 
00364       inline level_t get_max_log_level() const { return m_max_log_level; }
00365 
00366       void consume_trace(format &f, const log_param_t &log_param)
00367       {
00368         /* make here check to avoid producing a useless trace */
00369         if (get<LEVEL>(log_param) > m_max_log_level)
00370           return ;
00371 
00372         qualifier_list_t::const_iterator it = m_qualifier_list.begin();
00373         bool qualifier_present = false;
00374         for ( ; !qualifier_present && it !=  m_qualifier_list.end(); ++it)
00375           qualifier_present = (**it == *get<QUALIFIER>(log_param));
00376 
00377         if (!qualifier_present)
00378           return ;
00379 
00380         *m_output_stream << f.produce_trace(log_param);
00381       }
00382 
00383       void attach_qualifier(qualifier &q)
00384       {
00385         m_qualifier_list.push_back(&q);
00386       }
00387 
00388     private:
00389       level_t                  m_max_log_level;
00390       shared_ptr<std::ostream> m_output_stream;
00391       qualifier_list_t         m_qualifier_list;      
00392     };
00393    
00394 //  Element static instantiations --------------------------------------------//
00395     static level_element     level     = level_element();
00396     static filename_element  filename  = filename_element();
00397     static line_element      line      = line_element();
00398     static date_element      date      = date_element();
00399     static time_element      time      = time_element();
00400     static trace_element     trace     = trace_element();
00401     static eol_element       eol       = eol_element();
00402 
00403     static log_qualifier     log       = log_qualifier();
00404     static notice_qualifier  notice    = notice_qualifier();
00405     static warning_qualifier warning   = warning_qualifier();
00406     static error_qualifier   error     = error_qualifier();
00407 
00408 //  Logger class declaration  ------------------------------------------------//
00409     class logger
00410     {
00411     public: 
00412       logger() : m_global_max_log_level(0) {}
00413 
00414       void clear()
00415       {
00416           m_format_list.clear();
00417           m_sink_format_assoc.clear();
00418       }
00419         
00420       static logger *get_instance()
00421       {
00422 #if defined(BOOST_HAS_THREADS)
00423         static boost::mutex m_inst_mutex;
00424         boost::mutex::scoped_lock scoped_lock(m_inst_mutex);
00425 #endif // BOOST_HAS_THREADS
00426         static logger             *l = NULL;
00427         
00428         if (!l)
00429         {
00430           l = new logger();
00431           static shared_ptr<logger> s_ptr_l(l);
00432         }
00433           
00434         return l;
00435       }
00436 
00437       void add_format(const format &f)
00438       {
00439         m_format_list.push_back(f);
00440       }
00441 
00442       void add_sink(const sink &s)
00443       {
00444         if (m_format_list.begin() == m_format_list.end())
00445           throw "no format defined";
00446 
00447         // Updating global_max_level used for full lazy evaluation
00448         m_global_max_log_level = 
00449           (m_global_max_log_level < s.get_max_log_level()) 
00450           ? 
00451             s.get_max_log_level()
00452           : 
00453             m_global_max_log_level;
00454 
00455         m_sink_format_assoc.push_back
00456           (
00457             sink_format_assoc_t(s, *m_format_list.begin())
00458           );
00459       }
00460 
00461       void add_sink(const sink &s, format &f)
00462       {
00463         // Updating global_max_level used for full lazy evaluation
00464         m_global_max_log_level = 
00465           (m_global_max_log_level < s.get_max_log_level()) 
00466           ? 
00467             s.get_max_log_level()
00468           : 
00469             m_global_max_log_level;
00470 
00471         m_sink_format_assoc.push_back(sink_format_assoc_t(s, f));
00472       }
00473 
00474       inline level_t get_global_max_log_level() 
00475       { return m_global_max_log_level; }
00476 
00477       void trace(unsigned short     l, 
00478                  const qualifier   &q, 
00479                  const std::string &t, 
00480                  const std::string &f, 
00481                  unsigned int      ln)
00482       {
00483 #if defined(BOOST_HAS_THREADS)
00484         boost::mutex::scoped_lock scoped_lock(m_mutex);
00485 #endif // BOOST_HAS_THREADS
00486 
00487         log_param_t log_param(l, &q, t, f, ln);
00488         sink_format_assoc_list_t::iterator 
00489           s_it = m_sink_format_assoc.begin();
00490         for (; s_it != m_sink_format_assoc.end(); ++s_it)
00491         {
00492           get<SINK>(*s_it).consume_trace(get<FORMAT>(*s_it), log_param);
00493         }
00494       }
00495       
00496       void unformatted_trace(unsigned short     l, 
00497                  const qualifier   &q, 
00498                  const std::string &t, 
00499                  const std::string &f, 
00500                  unsigned int      ln);
00501 
00502     public:
00503       std::stringstream       m_string_stream;
00504       std::stack<std::string> m_string_stack;
00505       
00506     private:
00507       format_list_t            m_format_list;
00508       sink_format_assoc_list_t m_sink_format_assoc;
00509 
00510       // The global max log level is the highest log level on all the link
00511       // added to the logger. If no sink as a log level high enougth for
00512       // a trace, the trace does not need to be evaluated.
00513       level_t                  m_global_max_log_level;
00514 #if defined(BOOST_HAS_THREADS)
00515       boost::mutex             m_mutex;
00516 #endif // BOOST_HAS_THREADS
00517     };  // logger
00518     
00519 //  Element functions definition ---------------------------------------------//
00520     inline std::string log_element::visit(format &f, 
00521                                           const log_param_t &log_param)
00522     {
00523       return f.accept(*this);
00524     }
00525 
00526     inline std::string level_element::visit(format &f, 
00527                                             const log_param_t &log_param)
00528     {
00529       return f.accept(*this, get<LEVEL>(log_param));
00530     }
00531 
00532     inline std::string trace_element::visit(format &f, 
00533                                             const log_param_t &log_param)
00534     {
00535       return f.accept(*this, get<TRACE>(log_param));
00536     }
00537 
00538     inline std::string filename_element::visit(format &f, 
00539                                                const log_param_t &log_param)
00540     {
00541       return f.accept(*this, get<FILENAME>(log_param));
00542     }
00543 
00544     inline std::string line_element::visit(format &f, 
00545                                            const log_param_t &log_param)
00546     {
00547       return f.accept(*this, get<LINE>(log_param));
00548     }
00549 
00550   } // !namespace logging
00551 
00552 } // !namespace boost
00553 
00554 //  Element global operators -------------------------------------------------//
00555 inline boost::logging::element_list_t operator>>(
00556   boost::logging::log_element &lhs, 
00557   boost::logging::log_element &rhs)
00558 { 
00559   boost::logging::element_list_t l;
00560   l.push_back(boost::shared_ptr<boost::logging::log_element> 
00561                 (&lhs, boost::logging::null_deleter()));
00562   l.push_back(boost::shared_ptr<boost::logging::log_element> 
00563                 (&rhs, boost::logging::null_deleter())); 
00564   return l;
00565 }
00566 
00567 inline boost::logging::element_list_t operator>>(
00568   boost::logging::element_list_t lhs, 
00569   boost::logging::log_element &rhs)
00570 { 
00571   lhs.push_back(boost::shared_ptr<boost::logging::log_element> 
00572                 (&rhs, boost::logging::null_deleter())); 
00573   return lhs; 
00574 }
00575 
00576 inline boost::logging::element_list_t operator>>(
00577   const std::string &s, 
00578   boost::logging::log_element &rhs)
00579 {
00580   boost::logging::element_list_t l;
00581   boost::shared_ptr<boost::logging::literal_element> 
00582     p(new boost::logging::literal_element(s));
00583   l.push_back(p);
00584   l.push_back(boost::shared_ptr<boost::logging::log_element> 
00585                 (&rhs, boost::logging::null_deleter())); 
00586   return l;
00587 }
00588 
00589 inline boost::logging::element_list_t operator>>(
00590   boost::logging::element_list_t lhs, 
00591   const std::string &s)
00592 { 
00593   boost::shared_ptr<boost::logging::literal_element> 
00594     p(new boost::logging::literal_element(s));
00595   lhs.push_back(p);
00596   return lhs;
00597 }
00598 
00599 inline
00600 void boost::logging::logger::unformatted_trace(unsigned short     l, 
00601                            const qualifier   &q, 
00602                                                const std::string &t, 
00603                                                const std::string &f, 
00604                                                unsigned int      ln)
00605 {
00606 #if defined(BOOST_HAS_THREADS)
00607   boost::mutex::scoped_lock scoped_lock(m_mutex);
00608 #endif // BOOST_HAS_THREADS
00609   log_param_t log_param(l, &q, t, f, ln);
00610   sink_format_assoc_list_t::iterator 
00611     s_it = m_sink_format_assoc.begin();
00612   for (; s_it != m_sink_format_assoc.end(); ++s_it)
00613     {
00614       boost::logging::format f(boost::logging::trace);
00615       get<SINK>(*s_it).consume_trace(f, log_param);
00616     }
00617 }
00618 
00619 #endif  // !BOOST_LOGGING_HPP