00001
00002
00003
00004
00005
00006
00007
00008
00009
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
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
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
00141 struct null_deleter
00142 { void operator()(void const *) const {} };
00143
00144
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
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
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
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
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
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
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
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
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
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
00511
00512
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 };
00518
00519
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 }
00551
00552 }
00553
00554
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