|
libpsynth 0.2.1
|
00001 00012 /* 00013 * Copyright (C) 2007, 2008, 2009 Juan Pedro BolĂvar Puente 00014 * 00015 * This file is part of Psychosynth. 00016 * 00017 * Psychosynth is free software: you can redistribute it and/or modify 00018 * it under the terms of the GNU General Public License as published by 00019 * the Free Software Foundation, either version 3 of the License, or 00020 * (at your option) any later version. 00021 * 00022 * Psychosynth is distributed in the hope that it will be useful, 00023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00025 * GNU General Public License for more details. 00026 * 00027 * You should have received a copy of the GNU General Public License 00028 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00029 * 00030 */ 00031 00032 #ifndef PSYNTH_BASE_LOGGER_H 00033 #define PSYNTH_BASE_LOGGER_H 00034 00035 #include <map> 00036 #include <list> 00037 #include <iostream> 00038 #include <fstream> 00039 #include <sstream> 00040 00041 #include <psynth/base/singleton.hpp> 00042 #include <psynth/base/tree.hpp> 00043 #include <psynth/base/compat.hpp> 00044 #include <psynth/base/logger_fwd.hpp> 00045 00046 namespace psynth 00047 { 00048 namespace base 00049 { 00050 00054 class log_stream_adapter 00055 { 00056 public: 00062 inline log_stream_adapter (log& l); 00063 inline log_stream_adapter (const log_stream_adapter&); 00064 inline log_stream_adapter (log_stream_adapter&&); 00065 00067 inline ~log_stream_adapter (); 00068 00070 void set_level (int level) 00071 { _level = level; } 00072 00074 int level () const { return _level; } 00075 00077 const std::string message () const { return _str.str (); } 00078 00080 inline void flush (); 00081 00083 inline void dump (); 00084 00085 private: 00086 log& _log; 00087 int _level; 00088 std::ostringstream _str; 00089 00090 template <typename T> 00091 friend log_stream_adapter& operator<< (log_stream_adapter&, const T&); 00092 friend log_stream_adapter& operator<< ( 00093 log_stream_adapter&, log_stream_adapter&(*)(log_stream_adapter&)); 00094 }; 00095 00099 inline log_stream_adapter& flush (log_stream_adapter& s) 00100 { 00101 s.flush (); 00102 return s; 00103 } 00104 00109 class log_stream_adapter_wrapper : public boost::noncopyable 00110 { 00111 public: 00113 log_stream_adapter_wrapper (log_stream_adapter& s) 00114 : _stream (&s) 00115 {} 00116 00118 log_stream_adapter_wrapper (log_stream_adapter_wrapper&& s) 00119 : _stream (s._stream) 00120 { 00121 s._stream = 0; 00122 } 00123 00125 ~log_stream_adapter_wrapper () 00126 { 00127 if (_stream) 00128 *_stream << flush; 00129 } 00130 00132 log_stream_adapter& wrapped () 00133 { 00134 return *_stream; 00135 } 00136 00137 private: 00138 log_stream_adapter* _stream; 00139 }; 00140 00141 template<typename T> inline 00142 log_stream_adapter_wrapper operator<< (log_stream_adapter_wrapper s, T p) 00143 { 00144 s.wrapped () << p; 00145 return std::move (s); 00146 } 00147 00152 class log_sink 00153 { 00154 public: 00155 00162 virtual void dump (log& log, int level, const std::string& msg) = 0; 00163 }; 00164 00177 class log : public tree_node <log>, 00178 public PSYNTH_DEFAULT_THREADING <log> 00179 { 00180 public: 00185 enum level 00186 { 00187 debug, 00188 info, 00189 warning, 00190 error, 00191 fatal 00192 }; 00193 00198 static const char* level_name (int level) 00199 { 00200 switch(level) { 00201 case debug: 00202 return "DEBUG"; 00203 case info: 00204 return "INFO"; 00205 case warning: 00206 return "WARNING"; 00207 case error: 00208 return "ERROR"; 00209 case fatal: 00210 return "FATAL"; 00211 default: 00212 return "UNKNOWN"; 00213 }; 00214 }; 00215 00217 log () 00218 : _stream (*this) 00219 {} 00220 00222 ~log (); 00223 00228 void add_sink (log_sink_ptr d); 00229 00234 void del_sink (log_sink_ptr d); 00235 00242 void operator () (const std::string& child, int level, const std::string& msg) 00243 { 00244 lock lock (this); 00245 path (child) (level, msg); 00246 } 00247 00253 void operator () (int level, const std::string& msg) 00254 { 00255 lock lock (this); 00256 operator () (*this, level, msg); 00257 }; 00258 00263 log_stream_adapter_wrapper stream () 00264 { 00265 return log_stream_adapter_wrapper (_stream); 00266 } 00267 00268 private: 00276 void operator () (log& log, int level, const std::string& msg); 00277 00278 log_stream_adapter _stream; // TODO: We want to avoid the 00279 // ostringstream instance here :( 00280 std::list<log_sink_ptr> _dumpers; 00281 }; 00282 00286 struct logger : public singleton_holder<log> {}; 00287 00297 class log_std_sink : public log_sink 00298 { 00299 public: 00306 void dump (log& l, int level, const std::string& msg) 00307 { 00308 (level > log::info ? std::cerr : std::cout) 00309 << '[' 00310 << l.path_name () 00311 << "] " 00312 << log::level_name (level) 00313 << ": " 00314 << msg 00315 << std::endl; 00316 } 00317 }; 00318 00327 class log_stream_sink : public log_sink 00328 { 00329 public: 00331 log_stream_sink () 00332 : _output (0) 00333 {} 00334 00336 log_stream_sink (const log_stream_sink& s) 00337 : _output (s._output) 00338 {} 00339 00341 log_stream_sink (std::ostream& os) 00342 : _output (&os) 00343 {} 00344 00351 void dump (log& l, int level, const std::string& msg) 00352 { 00353 if (_output) 00354 *(_output) 00355 << '[' 00356 << l.path_name () 00357 << "] " 00358 << log::level_name (level) 00359 << ": " 00360 << msg 00361 << std::endl; 00362 } 00363 00364 protected: 00365 void set_stream (std::ostream& os) 00366 { 00367 _output = &os; 00368 } 00369 00370 private: 00371 std::ostream* _output; 00372 }; 00373 00377 class log_file_sink : public log_stream_sink 00378 { 00379 public: 00380 log_file_sink (const char* file, 00381 std::ios_base::openmode mode = 00382 std::ios_base::out | std::ios_base::app) 00383 : _file (file, mode) 00384 { 00385 set_stream (_file); 00386 } 00387 00388 private: 00389 std::ofstream _file; 00390 }; 00391 00392 void log_stream_adapter::flush () 00393 { 00394 _log (_level, _str.str ()); 00395 _str.str (""); 00396 } 00397 00398 void log_stream_adapter::dump () 00399 { 00400 _log (_level, _str.str ()); 00401 } 00402 00403 inline 00404 log_stream_adapter& operator<< (log_stream_adapter& s, log::level x) 00405 { 00406 s.set_level (x); 00407 return s; 00408 } 00409 00410 template <class T> inline 00411 log_stream_adapter& operator<< (log_stream_adapter& s, const T& x) 00412 { 00413 s._str << x; 00414 return s; 00415 } 00416 00417 inline log_stream_adapter& operator<< ( 00418 log_stream_adapter& stm, 00419 log_stream_adapter&(*func)(log_stream_adapter&)) 00420 { 00421 return func (stm); 00422 } 00423 00424 log_stream_adapter::log_stream_adapter (log& l) 00425 : _log (l) 00426 , _level (log::info) 00427 {} 00428 00429 log_stream_adapter::log_stream_adapter (const log_stream_adapter& l) 00430 : _log (l._log) 00431 , _level (l._level) 00432 { 00433 _str << l._str.str (); 00434 } 00435 00436 log_stream_adapter::log_stream_adapter (log_stream_adapter&& l) 00437 : _log (l._log) 00438 , _level (l._level) 00439 { 00440 _str << l._str.str (); // FIXME: SLOW!!! 00441 } 00442 00443 log_stream_adapter::~log_stream_adapter () 00444 { 00445 // *this << log_msg; 00446 } 00447 00448 #define PSYNTH_LOG \ 00449 ::psynth::base::logger::self ().path (PSYNTH_MODULE_NAME).stream () 00450 00451 #if PSYNTH_DEBUG 00452 #define PSYNTH_LOG_DEBUG \ 00453 ::psynth::base::logger::self ().path (PSYNTH_MODULE_NAME).stream () \ 00454 << ::psynth::base::log::debug 00455 #else 00456 #define PSYNTH_LOG_DEBUG ::psynth::base::nop_ostream () 00457 #endif 00458 00459 extern template class tree_node <log>; 00460 extern template class PSYNTH_DEFAULT_THREADING <log>; 00461 extern template class singleton_holder <log>; 00462 00463 } /* namespace base */ 00464 } /* namespace psynth */ 00465 00466 #endif /* PSYNTH_BASE_LOGGER_H */
1.7.4