liborigin2 13/09/2010
|
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