Imported Upstream version 15.1.0
[platform/upstream/libzypp.git] / zypp / base / LogControl.cc
index 8dc5844..3dda602 100644 (file)
 
 #include "zypp/base/Logger.h"
 #include "zypp/base/LogControl.h"
+#include "zypp/base/ProfilingFormater.h"
 #include "zypp/base/String.h"
+#include "zypp/Date.h"
+#include "zypp/PathInfo.h"
 
 using std::endl;
 
 ///////////////////////////////////////////////////////////////////
 namespace zypp
 { /////////////////////////////////////////////////////////////////
+
+#ifndef ZYPP_NDEBUG
+  namespace debug
+  {
+    void osdlog( const std::string & msg_r, unsigned level_r )
+    {
+      // Fg::Black:   30  Bg: 40 Attr::Normal:  22;27
+      // Fg::Red:     31  ...    Attr::Bright:  1
+      // Fg::Green:   32         Attr::Reverse: 7
+      // Fg::Yellow:  33
+      // Fg::Blue:    34
+      // Fg::Magenta: 35
+      // Fg::Cyan:    36
+      // Fg::White:   37
+      // Fg::Default: 39
+      static const char * ansi[] = {
+       "\033[37;40m",          // 0 w
+       "\033[36;40m",          // 1 c
+       "\033[33;1;40m",        // 2 y
+       "\033[32;40m",          // 3 g
+       "\033[31;1;40m",        // 4 r
+       "\033[35;40m",          // 5 m
+      };
+      static const unsigned n = sizeof(ansi)/sizeof(const char *);
+      switch ( level_r )
+      {
+       case 'w': level_r = 0; break;
+       case 'c': level_r = 1; break;
+       case 'y': level_r = 2; break;
+       case 'g': level_r = 3; break;
+       case 'r': level_r = 4; break;
+       case 'm': level_r = 5; break;
+      }
+      std::cerr << ansi[level_r%n] << "OSD[" << msg_r << "]\033[0m" << std::endl;
+    }
+}
+#endif // ZYPP_NDEBUG
+
   ///////////////////////////////////////////////////////////////////
-  namespace base
+  namespace log
   { /////////////////////////////////////////////////////////////////
-    ///////////////////////////////////////////////////////////////////
-    namespace logger
-    { /////////////////////////////////////////////////////////////////
 
-      void logFormat( const std::string & group_r, LogLevel level_r,
-                      const char * file_r, const char * func_r, int line_r,
-                      const std::string & buffer_r );
+    StdoutLineWriter::StdoutLineWriter()
+      : StreamLineWriter( std::cout )
+    {}
 
-      ///////////////////////////////////////////////////////////////////
-      struct StdErrWriter : public LogControl::LineWriter
+    StderrLineWriter::StderrLineWriter()
+      : StreamLineWriter( std::cerr )
+    {}
+
+    FileLineWriter::FileLineWriter( const Pathname & file_r, mode_t mode_r )
+    {
+      if ( file_r == Pathname("-") )
       {
-        virtual void writeOut( const std::string & formated_r )
-        {
-          std::cerr << formated_r << endl;
-        }
-      };
-      ///////////////////////////////////////////////////////////////////
-      struct FileWriter : public LogControl::LineWriter
+        _str = &std::cerr;
+      }
+      else
       {
-        FileWriter( const Pathname & logfile_r )
-        : _logfile( logfile_r )
-        {}
-        Pathname _logfile;
+       if ( mode_r )
+       {
+          // not filesystem::assert_file as filesystem:: functions log,
+         // and this FileWriter is not yet in place.
+         int fd = ::open( file_r.c_str(), O_CREAT|O_EXCL, mode_r );
+         if ( fd != -1 )
+           ::close( fd );
+       }
+        // set unbuffered write
+        std::ofstream * fstr = 0;
+        _outs.reset( (fstr = new std::ofstream( file_r.asString().c_str(), std::ios_base::app )) );
+        fstr->rdbuf()->pubsetbuf(0,0);
+        _str = &(*fstr);
+      }
+    }
 
-        virtual void writeOut( const std::string & formated_r )
-        {
-          std::ofstream outs( _logfile.asString().c_str(), std::ios_base::app );
-          outs << formated_r << endl;
-        }
-      };
+    /////////////////////////////////////////////////////////////////
+  } // namespace log
+  ///////////////////////////////////////////////////////////////////
+
+  ///////////////////////////////////////////////////////////////////
+  namespace base
+  { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    // LineFormater
+    ///////////////////////////////////////////////////////////////////
+    std::string LogControl::LineFormater::format( const std::string & group_r,
+                                                  logger::LogLevel    level_r,
+                                                  const char *        file_r,
+                                                  const char *        func_r,
+                                                  int                 line_r,
+                                                  const std::string & message_r )
+    {
+      static char hostname[1024];
+      static char nohostname[] = "unknown";
+      std::string now( Date::now().form( "%Y-%m-%d %H:%M:%S" ) );
+      return str::form( "%s <%d> %s(%d) [%s] %s(%s):%d %s",
+                        now.c_str(), level_r,
+                        ( gethostname( hostname, 1024 ) ? nohostname : hostname ),
+                        getpid(),
+                        group_r.c_str(),
+                        file_r, func_r, line_r,
+                        message_r.c_str() );
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    namespace logger
+    { /////////////////////////////////////////////////////////////////
+
+      inline void putStream( const std::string & group_r, LogLevel level_r,
+                             const char * file_r, const char * func_r, int line_r,
+                             const std::string & buffer_r );
 
       ///////////////////////////////////////////////////////////////////
       //
@@ -103,6 +184,8 @@ namespace zypp
         /** */
         virtual int writeout( const char* s, std::streamsize n )
         {
+         //logger::putStream( _group, _level, _file, _func, _line, _buffer );
+         //return n;
           if ( s && n )
             {
               const char * c = s;
@@ -110,7 +193,7 @@ namespace zypp
                 {
                   if ( *c == '\n' ) {
                     _buffer += std::string( s, c-s );
-                    logger::logFormat( _group, _level, _file, _func, _line, _buffer );
+                    logger::putStream( _group, _level, _file, _func, _line, _buffer );
                     _buffer = std::string();
                     s = c+1;
                   }
@@ -168,34 +251,69 @@ namespace zypp
       //
       //       CLASS NAME : LogControlImpl
       //
-      /** LogControl implementation (Singleton). */
+      /** LogControl implementation (Singleton).
+       *
+       * \note There is a slight difference in using the _lineFormater and _lineWriter!
+       * \li \c _lineFormater must not be NULL (create default LogControl::LineFormater)
+       * \li \c _lineWriter is NULL if no logging is performed, this way we can pass
+       *        _no_stream as logstream to the application, and avoid unnecessary formating
+       *        of logliles, which would then be discarded when passed to some dummy
+       *        LineWriter.
+      */
       struct LogControlImpl
       {
       public:
+       bool isExcessive()
+       { return _excessive; }
+
         void excessive( bool onOff_r )
         { _excessive = onOff_r; }
 
+        /** NULL _lineWriter indicates no loggin. */
         void setLineWriter( const shared_ptr<LogControl::LineWriter> & writer_r )
         { _lineWriter = writer_r; }
 
+        shared_ptr<LogControl::LineWriter> getLineWriter() const
+        { return _lineWriter; }
+
+        /** Assert \a _lineFormater is not NULL. */
+        void setLineFormater( const shared_ptr<LogControl::LineFormater> & format_r )
+        {
+          if ( format_r )
+            _lineFormater = format_r;
+          else
+            _lineFormater.reset( new LogControl::LineFormater );
+        }
+
+        void logfile( const Pathname & logfile_r, mode_t mode_r = 0640 )
+        {
+          if ( logfile_r.empty() )
+            setLineWriter( shared_ptr<LogControl::LineWriter>() );
+          else if ( logfile_r == Pathname( "-" ) )
+            setLineWriter( shared_ptr<LogControl::LineWriter>(new log::StderrLineWriter) );
+          else
+            setLineWriter( shared_ptr<LogControl::LineWriter>(new log::FileLineWriter(logfile_r, mode_r)) );
+        }
+
       private:
         std::ostream _no_stream;
         bool         _excessive;
 
-        shared_ptr<LogControl::LineWriter> _lineWriter;
+        shared_ptr<LogControl::LineFormater> _lineFormater;
+        shared_ptr<LogControl::LineWriter>   _lineWriter;
 
       public:
-        /** Provide the stream to write (logger interface) */
+        /** Provide the log stream to write (logger interface) */
         std::ostream & getStream( const std::string & group_r,
                                   LogLevel            level_r,
                                   const char *        file_r,
                                   const char *        func_r,
                                   const int           line_r )
         {
+          if ( ! _lineWriter )
+            return _no_stream;
           if ( level_r == E_XXX && !_excessive )
-            {
-              return _no_stream;
-            }
+            return _no_stream;
 
           if ( !_streamtable[group_r][level_r] )
             {
@@ -204,11 +322,18 @@ namespace zypp
           return _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r );
         }
 
-        /** Write out formated line from Loglinebuf. */
-        void writeLine( const std::string & formated_r )
+        /** Format and write out a logline from Loglinebuf. */
+        void putStream( const std::string & group_r,
+                        LogLevel            level_r,
+                        const char *        file_r,
+                        const char *        func_r,
+                        int                 line_r,
+                        const std::string & message_r )
         {
           if ( _lineWriter )
-            _lineWriter->writeOut( formated_r );
+            _lineWriter->writeOut( _lineFormater->format( group_r, level_r,
+                                                          file_r, func_r, line_r,
+                                                          message_r ) );
         }
 
       private:
@@ -219,12 +344,28 @@ namespace zypp
         StreamTable _streamtable;
 
       private:
-        /** Singleton */
+        /** Singleton ctor.
+         * No logging per default, unless enabled via $ZYPP_LOGFILE.
+        */
         LogControlImpl()
-        : _no_stream( 0 )
+        : _no_stream( NULL )
         , _excessive( getenv("ZYPP_FULLLOG") )
-        , _lineWriter( getenv("ZYPP_NOLOG") ? NULL : new StdErrWriter )
-        {}
+        , _lineFormater( new LogControl::LineFormater )
+        {
+          if ( getenv("ZYPP_LOGFILE") )
+            logfile( getenv("ZYPP_LOGFILE") );
+
+          if ( getenv("ZYPP_PROFILING") )
+          {
+            shared_ptr<LogControl::LineFormater> formater(new ProfilingFormater);
+            setLineFormater(formater);
+          }
+        }
+
+        ~LogControlImpl()
+        {
+          _lineWriter.reset();
+        }
 
       public:
         /** The LogControlImpl singleton
@@ -233,16 +374,20 @@ namespace zypp
          * destructed. At least destucted after all statics
          * which log from their dtor.
         */
-        static LogControlImpl instance;
+        static LogControlImpl & instance();
       };
       ///////////////////////////////////////////////////////////////////
 
       // 'THE' LogControlImpl singleton
-      LogControlImpl LogControlImpl::instance;
+      inline LogControlImpl & LogControlImpl::instance()
+      {
+        static LogControlImpl _instance;
+        return _instance;
+      }
 
       ///////////////////////////////////////////////////////////////////
 
-      /** \relates LogControl::Impl Stream output */
+      /** \relates LogControlImpl Stream output */
       inline std::ostream & operator<<( std::ostream & str, const LogControlImpl & obj )
       {
         return str << "LogControlImpl";
@@ -254,14 +399,13 @@ namespace zypp
       //
       ///////////////////////////////////////////////////////////////////
 
-      /** That's what logger:: calls.  */
       std::ostream & getStream( const char * group_r,
                                 LogLevel     level_r,
                                 const char * file_r,
                                 const char * func_r,
                                 const int    line_r )
       {
-        return LogControlImpl::instance.getStream( group_r,
+        return LogControlImpl::instance().getStream( group_r,
                                                    level_r,
                                                    file_r,
                                                    func_r,
@@ -269,16 +413,18 @@ namespace zypp
       }
 
       /** That's what Loglinebuf calls.  */
-      inline void logFormat( const std::string & group_r, LogLevel level_r,
+      inline void putStream( const std::string & group_r, LogLevel level_r,
                              const char * file_r, const char * func_r, int line_r,
                              const std::string & buffer_r )
       {
-        LogControlImpl::instance.writeLine( str::form( "<%d> [%s] %s(%s):%d %s",
-                                                       level_r, group_r.c_str(),
-                                                       file_r, func_r, line_r,
-                                                       buffer_r.c_str() ) );
+        LogControlImpl::instance().putStream( group_r, level_r,
+                                            file_r, func_r, line_r,
+                                            buffer_r );
       }
 
+      bool isExcessive()
+      { return LogControlImpl::instance().isExcessive(); }
+
       /////////////////////////////////////////////////////////////////
     } // namespace logger
     ///////////////////////////////////////////////////////////////////
@@ -293,16 +439,25 @@ namespace zypp
     using logger::LogControlImpl;
 
     void LogControl::logfile( const Pathname & logfile_r )
-    { LogControlImpl::instance.setLineWriter( shared_ptr<LineWriter>( new logger::FileWriter(logfile_r) ) ); }
+    { LogControlImpl::instance().logfile( logfile_r ); }
+
+    void LogControl::logfile( const Pathname & logfile_r, mode_t mode_r )
+    { LogControlImpl::instance().logfile( logfile_r, mode_r ); }
+
+    shared_ptr<LogControl::LineWriter> LogControl::getLineWriter() const
+    { return LogControlImpl::instance().getLineWriter(); }
 
     void LogControl::setLineWriter( const shared_ptr<LineWriter> & writer_r )
-    { LogControlImpl::instance.setLineWriter( writer_r ); }
+    { LogControlImpl::instance().setLineWriter( writer_r ); }
+
+    void LogControl::setLineFormater( const shared_ptr<LineFormater> & formater_r )
+    { LogControlImpl::instance().setLineFormater( formater_r ); }
 
     void LogControl::logNothing()
-    { LogControlImpl::instance.setLineWriter( shared_ptr<LineWriter>() ); }
+    { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>() ); }
 
     void LogControl::logToStdErr()
-    { LogControlImpl::instance.setLineWriter( shared_ptr<LineWriter>( new logger::StdErrWriter ) ); }
+    { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>( new log::StderrLineWriter ) ); }
 
     ///////////////////////////////////////////////////////////////////
     //
@@ -310,9 +465,9 @@ namespace zypp
     //
     ///////////////////////////////////////////////////////////////////
     LogControl::TmpExcessive::TmpExcessive()
-    { LogControlImpl::instance.excessive( true ); }
+    { LogControlImpl::instance().excessive( true ); }
     LogControl::TmpExcessive::~TmpExcessive()
-    { LogControlImpl::instance.excessive( false );  }
+    { LogControlImpl::instance().excessive( false );  }
 
     /******************************************************************
      **
@@ -321,7 +476,7 @@ namespace zypp
     */
     std::ostream & operator<<( std::ostream & str, const LogControl & obj )
     {
-      return str << LogControlImpl::instance;
+      return str << LogControlImpl::instance();
     }
 
     /////////////////////////////////////////////////////////////////