libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/base/logger.hpp
Go to the documentation of this file.
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 */