libzypp  10.5.0
LogControl.cc
Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <fstream>
00014 #include <string>
00015 
00016 #include "zypp/base/Logger.h"
00017 #include "zypp/base/LogControl.h"
00018 #include "zypp/base/ProfilingFormater.h"
00019 #include "zypp/base/String.h"
00020 #include "zypp/Date.h"
00021 #include "zypp/PathInfo.h"
00022 
00023 using std::endl;
00024 
00026 namespace zypp
00027 { 
00028 
00030   namespace log
00031   { 
00032 
00033     StdoutLineWriter::StdoutLineWriter()
00034       : StreamLineWriter( std::cout )
00035     {}
00036 
00037     StderrLineWriter::StderrLineWriter()
00038       : StreamLineWriter( std::cerr )
00039     {}
00040 
00041     FileLineWriter::FileLineWriter( const Pathname & file_r, mode_t mode_r )
00042     {
00043       if ( file_r == Pathname("-") )
00044       {
00045         _str = &std::cerr;
00046       }
00047       else
00048       {
00049         // set unbuffered write
00050         std::ofstream * fstr = 0;
00051         _outs.reset( (fstr = new std::ofstream( file_r.asString().c_str(), std::ios_base::app )) );
00052         fstr->rdbuf()->pubsetbuf(0,0);
00053         _str = &(*fstr);
00054         if ( mode_r )
00055         {
00056           // not filesystem::chmod, as filesystem:: functions log,
00057           // and this FileWriter is not yet in place.
00058           ::chmod( file_r.asString().c_str(), mode_r );
00059         }
00060       }
00061     }
00062 
00064   } // namespace log
00066 
00068   namespace base
00069   { 
00070 
00072     // LineFormater
00074     std::string LogControl::LineFormater::format( const std::string & group_r,
00075                                                   logger::LogLevel    level_r,
00076                                                   const char *        file_r,
00077                                                   const char *        func_r,
00078                                                   int                 line_r,
00079                                                   const std::string & message_r )
00080     {
00081       static char hostname[1024];
00082       static char nohostname[] = "unknown";
00083       std::string now( Date::now().form( "%Y-%m-%d %H:%M:%S" ) );
00084       return str::form( "%s <%d> %s(%d) [%s] %s(%s):%d %s",
00085                         now.c_str(), level_r,
00086                         ( gethostname( hostname, 1024 ) ? nohostname : hostname ),
00087                         getpid(),
00088                         group_r.c_str(),
00089                         file_r, func_r, line_r,
00090                         message_r.c_str() );
00091     }
00092 
00094     namespace logger
00095     { 
00096 
00097       inline void putStream( const std::string & group_r, LogLevel level_r,
00098                              const char * file_r, const char * func_r, int line_r,
00099                              const std::string & buffer_r );
00100 
00102       //
00103       //        CLASS NAME : Loglinebuf
00104       //
00105       class Loglinebuf : public std::streambuf {
00106 
00107       public:
00109         Loglinebuf( const std::string & group_r, LogLevel level_r )
00110         : _group( group_r )
00111         , _level( level_r )
00112         , _file( "" )
00113         , _func( "" )
00114         , _line( -1 )
00115         {}
00117         ~Loglinebuf()
00118         {
00119           if ( !_buffer.empty() )
00120             writeout( "\n", 1 );
00121         }
00122 
00124         void tagSet( const char * fil_r, const char * fnc_r, int lne_r )
00125         {
00126           _file = fil_r;
00127           _func = fnc_r;
00128           _line = lne_r;
00129         }
00130 
00131       private:
00133         virtual std::streamsize xsputn( const char * s, std::streamsize n )
00134         { return writeout( s, n ); }
00136         virtual int overflow( int ch = EOF )
00137         {
00138           if ( ch != EOF )
00139             {
00140               char tmp = ch;
00141               writeout( &tmp, 1 );
00142             }
00143           return 0;
00144         }
00146         virtual int writeout( const char* s, std::streamsize n )
00147         {
00148           //logger::putStream( _group, _level, _file, _func, _line, _buffer );
00149           //return n;
00150           if ( s && n )
00151             {
00152               const char * c = s;
00153               for ( int i = 0; i < n; ++i, ++c )
00154                 {
00155                   if ( *c == '\n' ) {
00156                     _buffer += std::string( s, c-s );
00157                     logger::putStream( _group, _level, _file, _func, _line, _buffer );
00158                     _buffer = std::string();
00159                     s = c+1;
00160                   }
00161                 }
00162               if ( s < c )
00163                 {
00164                   _buffer += std::string( s, c-s );
00165                 }
00166             }
00167           return n;
00168         }
00169 
00170       private:
00171         std::string  _group;
00172         LogLevel     _level;
00173         const char * _file;
00174         const char * _func;
00175         int          _line;
00176         std::string  _buffer;
00177       };
00178 
00180 
00182       //
00183       //        CLASS NAME : Loglinestream
00184       //
00185       class Loglinestream {
00186 
00187       public:
00189         Loglinestream( const std::string & group_r, LogLevel level_r )
00190         : _mybuf( group_r, level_r )
00191         , _mystream( &_mybuf )
00192         {}
00194         ~Loglinestream()
00195         { _mystream.flush(); }
00196 
00197       public:
00199         std::ostream & getStream( const char * fil_r, const char * fnc_r, int lne_r )
00200         {
00201           _mybuf.tagSet( fil_r, fnc_r, lne_r );
00202           return _mystream;
00203         }
00204 
00205       private:
00206         Loglinebuf   _mybuf;
00207         std::ostream _mystream;
00208       };
00210 
00212       //
00213       //        CLASS NAME : LogControlImpl
00214       //
00224       struct LogControlImpl
00225       {
00226       public:
00227         bool isExcessive()
00228         { return _excessive; }
00229 
00230         void excessive( bool onOff_r )
00231         { _excessive = onOff_r; }
00232 
00234         void setLineWriter( const shared_ptr<LogControl::LineWriter> & writer_r )
00235         { _lineWriter = writer_r; }
00236 
00237         shared_ptr<LogControl::LineWriter> getLineWriter() const
00238         { return _lineWriter; }
00239 
00241         void setLineFormater( const shared_ptr<LogControl::LineFormater> & format_r )
00242         {
00243           if ( format_r )
00244             _lineFormater = format_r;
00245           else
00246             _lineFormater.reset( new LogControl::LineFormater );
00247         }
00248 
00249         void logfile( const Pathname & logfile_r, mode_t mode_r = 0640 )
00250         {
00251           if ( logfile_r.empty() )
00252             setLineWriter( shared_ptr<LogControl::LineWriter>() );
00253           else if ( logfile_r == Pathname( "-" ) )
00254             setLineWriter( shared_ptr<LogControl::LineWriter>(new log::StderrLineWriter) );
00255           else
00256             setLineWriter( shared_ptr<LogControl::LineWriter>(new log::FileLineWriter(logfile_r, mode_r)) );
00257         }
00258 
00259       private:
00260         std::ostream _no_stream;
00261         bool         _excessive;
00262 
00263         shared_ptr<LogControl::LineFormater> _lineFormater;
00264         shared_ptr<LogControl::LineWriter>   _lineWriter;
00265 
00266       public:
00268         std::ostream & getStream( const std::string & group_r,
00269                                   LogLevel            level_r,
00270                                   const char *        file_r,
00271                                   const char *        func_r,
00272                                   const int           line_r )
00273         {
00274           if ( ! _lineWriter )
00275             return _no_stream;
00276           if ( level_r == E_XXX && !_excessive )
00277             return _no_stream;
00278 
00279           if ( !_streamtable[group_r][level_r] )
00280             {
00281               _streamtable[group_r][level_r].reset( new Loglinestream( group_r, level_r ) );
00282             }
00283           return _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r );
00284         }
00285 
00287         void putStream( const std::string & group_r,
00288                         LogLevel            level_r,
00289                         const char *        file_r,
00290                         const char *        func_r,
00291                         int                 line_r,
00292                         const std::string & message_r )
00293         {
00294           if ( _lineWriter )
00295             _lineWriter->writeOut( _lineFormater->format( group_r, level_r,
00296                                                           file_r, func_r, line_r,
00297                                                           message_r ) );
00298         }
00299 
00300       private:
00301         typedef shared_ptr<Loglinestream>        StreamPtr;
00302         typedef std::map<LogLevel,StreamPtr>     StreamSet;
00303         typedef std::map<std::string,StreamSet>  StreamTable;
00305         StreamTable _streamtable;
00306 
00307       private:
00311         LogControlImpl()
00312         : _no_stream( NULL )
00313         , _excessive( getenv("ZYPP_FULLLOG") )
00314         , _lineFormater( new LogControl::LineFormater )
00315         {
00316           if ( getenv("ZYPP_LOGFILE") )
00317             logfile( getenv("ZYPP_LOGFILE") );
00318 
00319           if ( getenv("ZYPP_PROFILING") )
00320           {
00321             shared_ptr<LogControl::LineFormater> formater(new ProfilingFormater);
00322             setLineFormater(formater);
00323           }
00324         }
00325 
00326         ~LogControlImpl()
00327         {
00328           _lineWriter.reset();
00329         }
00330 
00331       public:
00338         static LogControlImpl & instance();
00339       };
00341 
00342       // 'THE' LogControlImpl singleton
00343       inline LogControlImpl & LogControlImpl::instance()
00344       {
00345         static LogControlImpl _instance;
00346         return _instance;
00347       }
00348 
00350 
00352       inline std::ostream & operator<<( std::ostream & str, const LogControlImpl & obj )
00353       {
00354         return str << "LogControlImpl";
00355       }
00356 
00358       //
00359       // Access from logger::
00360       //
00362 
00363       std::ostream & getStream( const char * group_r,
00364                                 LogLevel     level_r,
00365                                 const char * file_r,
00366                                 const char * func_r,
00367                                 const int    line_r )
00368       {
00369         return LogControlImpl::instance().getStream( group_r,
00370                                                    level_r,
00371                                                    file_r,
00372                                                    func_r,
00373                                                    line_r );
00374       }
00375 
00377       inline void putStream( const std::string & group_r, LogLevel level_r,
00378                              const char * file_r, const char * func_r, int line_r,
00379                              const std::string & buffer_r )
00380       {
00381         LogControlImpl::instance().putStream( group_r, level_r,
00382                                             file_r, func_r, line_r,
00383                                             buffer_r );
00384       }
00385 
00386       bool isExcessive()
00387       { return LogControlImpl::instance().isExcessive(); }
00388 
00390     } // namespace logger
00392 
00394     //
00395     //  CLASS NAME : LogControl
00396     //  Forward to LogControlImpl singleton.
00397     //
00399 
00400     using logger::LogControlImpl;
00401 
00402     void LogControl::logfile( const Pathname & logfile_r )
00403     { LogControlImpl::instance().logfile( logfile_r ); }
00404 
00405     void LogControl::logfile( const Pathname & logfile_r, mode_t mode_r )
00406     { LogControlImpl::instance().logfile( logfile_r, mode_r ); }
00407 
00408     shared_ptr<LogControl::LineWriter> LogControl::getLineWriter() const
00409     { return LogControlImpl::instance().getLineWriter(); }
00410 
00411     void LogControl::setLineWriter( const shared_ptr<LineWriter> & writer_r )
00412     { LogControlImpl::instance().setLineWriter( writer_r ); }
00413 
00414     void LogControl::setLineFormater( const shared_ptr<LineFormater> & formater_r )
00415     { LogControlImpl::instance().setLineFormater( formater_r ); }
00416 
00417     void LogControl::logNothing()
00418     { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>() ); }
00419 
00420     void LogControl::logToStdErr()
00421     { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>( new log::StderrLineWriter ) ); }
00422 
00424     //
00425     // LogControl::TmpExcessive
00426     //
00428     LogControl::TmpExcessive::TmpExcessive()
00429     { LogControlImpl::instance().excessive( true ); }
00430     LogControl::TmpExcessive::~TmpExcessive()
00431     { LogControlImpl::instance().excessive( false );  }
00432 
00433     /******************************************************************
00434      **
00435      ** FUNCTION NAME : operator<<
00436      ** FUNCTION TYPE : std::ostream &
00437     */
00438     std::ostream & operator<<( std::ostream & str, const LogControl & obj )
00439     {
00440       return str << LogControlImpl::instance();
00441     }
00442 
00444   } // namespace base
00447 } // namespace zypp