Imported Upstream version 17.14.0
[platform/upstream/libzypp.git] / zypp / base / LogControl.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/base/LogControl.cc
10  *
11 */
12 #include <iostream>
13 #include <fstream>
14 #include <string>
15
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/LogControl.h"
18 #include "zypp/base/ProfilingFormater.h"
19 #include "zypp/base/String.h"
20 #include "zypp/Date.h"
21 #include "zypp/PathInfo.h"
22
23 using std::endl;
24
25 ///////////////////////////////////////////////////////////////////
26 namespace zypp
27 { /////////////////////////////////////////////////////////////////
28
29 #ifndef ZYPP_NDEBUG
30   namespace debug
31   {
32     void osdlog( const std::string & msg_r, unsigned level_r )
33     {
34       // Fg::Black:   30  Bg: 40 Attr::Normal:  22;27
35       // Fg::Red:     31  ...    Attr::Bright:  1
36       // Fg::Green:   32         Attr::Reverse: 7
37       // Fg::Yellow:  33
38       // Fg::Blue:    34
39       // Fg::Magenta: 35
40       // Fg::Cyan:    36
41       // Fg::White:   37
42       // Fg::Default: 39
43       static const char * ansi[] = {
44         "\033[37;40m",          // 0 w
45         "\033[36;40m",          // 1 c
46         "\033[33;1;40m",        // 2 y
47         "\033[32;40m",          // 3 g
48         "\033[31;1;40m",        // 4 r
49         "\033[35;40m",          // 5 m
50       };
51       static const unsigned n = sizeof(ansi)/sizeof(const char *);
52       switch ( level_r )
53       {
54         case 'w': level_r = 0; break;
55         case 'c': level_r = 1; break;
56         case 'y': level_r = 2; break;
57         case 'g': level_r = 3; break;
58         case 'r': level_r = 4; break;
59         case 'm': level_r = 5; break;
60       }
61       std::cerr << ansi[level_r%n] << "OSD[" << msg_r << "]\033[0m" << std::endl;
62     }
63
64
65     unsigned TraceLeave::_depth = 0;
66
67     TraceLeave::TraceLeave( const char * file_r, const char *  fnc_r, int line_r )
68     : _file( std::move(file_r) )
69     , _fnc( std::move(fnc_r) )
70     , _line( line_r )
71     {
72       //std::string::size_type p( _file.find_last_of( '/' ) );
73       //if ( p != std::string::npos )
74       //_file.erase( 0, p+1 );
75       USR << ">>> " << std::string(_depth++,'>') << " " << _file << "(" << _fnc << "):" << _line << endl;
76     }
77
78     TraceLeave::~TraceLeave()
79     { USR << "<<< " << std::string(--_depth,'<') << " " << _file << "(" << _fnc << "):" << _line << endl; }
80 }
81 #endif // ZYPP_NDEBUG
82
83   ///////////////////////////////////////////////////////////////////
84   namespace log
85   { /////////////////////////////////////////////////////////////////
86
87     StdoutLineWriter::StdoutLineWriter()
88       : StreamLineWriter( std::cout )
89     {}
90
91     StderrLineWriter::StderrLineWriter()
92       : StreamLineWriter( std::cerr )
93     {}
94
95     FileLineWriter::FileLineWriter( const Pathname & file_r, mode_t mode_r )
96     {
97       if ( file_r == Pathname("-") )
98       {
99         _str = &std::cerr;
100       }
101       else
102       {
103         if ( mode_r )
104         {
105           // not filesystem::assert_file as filesystem:: functions log,
106           // and this FileWriter is not yet in place.
107           int fd = ::open( file_r.c_str(), O_CREAT|O_EXCL, mode_r );
108           if ( fd != -1 )
109             ::close( fd );
110         }
111         // set unbuffered write
112         std::ofstream * fstr = 0;
113         _outs.reset( (fstr = new std::ofstream( file_r.asString().c_str(), std::ios_base::app )) );
114         fstr->rdbuf()->pubsetbuf(0,0);
115         _str = &(*fstr);
116       }
117     }
118
119     /////////////////////////////////////////////////////////////////
120   } // namespace log
121   ///////////////////////////////////////////////////////////////////
122
123   ///////////////////////////////////////////////////////////////////
124   namespace base
125   { /////////////////////////////////////////////////////////////////
126
127     ///////////////////////////////////////////////////////////////////
128     // LineFormater
129     ///////////////////////////////////////////////////////////////////
130     std::string LogControl::LineFormater::format( const std::string & group_r,
131                                                   logger::LogLevel    level_r,
132                                                   const char *        file_r,
133                                                   const char *        func_r,
134                                                   int                 line_r,
135                                                   const std::string & message_r )
136     {
137       static char hostname[1024];
138       static char nohostname[] = "unknown";
139       std::string now( Date::now().form( "%Y-%m-%d %H:%M:%S" ) );
140       return str::form( "%s <%d> %s(%d) [%s] %s(%s):%d %s",
141                         now.c_str(), level_r,
142                         ( gethostname( hostname, 1024 ) ? nohostname : hostname ),
143                         getpid(),
144                         group_r.c_str(),
145                         file_r, func_r, line_r,
146                         message_r.c_str() );
147     }
148
149     ///////////////////////////////////////////////////////////////////
150     namespace logger
151     { /////////////////////////////////////////////////////////////////
152
153       inline void putStream( const std::string & group_r, LogLevel level_r,
154                              const char * file_r, const char * func_r, int line_r,
155                              const std::string & buffer_r );
156
157       ///////////////////////////////////////////////////////////////////
158       //
159       //        CLASS NAME : Loglinebuf
160       //
161       class Loglinebuf : public std::streambuf {
162
163       public:
164         /** */
165         Loglinebuf( const std::string & group_r, LogLevel level_r )
166         : _group( group_r )
167         , _level( level_r )
168         , _file( "" )
169         , _func( "" )
170         , _line( -1 )
171         {}
172         /** */
173         ~Loglinebuf()
174         {
175           if ( !_buffer.empty() )
176             writeout( "\n", 1 );
177         }
178
179         /** */
180         void tagSet( const char * fil_r, const char * fnc_r, int lne_r )
181         {
182           _file = fil_r;
183           _func = fnc_r;
184           _line = lne_r;
185         }
186
187       private:
188         /** */
189         virtual std::streamsize xsputn( const char * s, std::streamsize n )
190         { return writeout( s, n ); }
191         /** */
192         virtual int overflow( int ch = EOF )
193         {
194           if ( ch != EOF )
195             {
196               char tmp = ch;
197               writeout( &tmp, 1 );
198             }
199           return 0;
200         }
201         /** */
202         virtual int writeout( const char* s, std::streamsize n )
203         {
204           //logger::putStream( _group, _level, _file, _func, _line, _buffer );
205           //return n;
206           if ( s && n )
207             {
208               const char * c = s;
209               for ( int i = 0; i < n; ++i, ++c )
210                 {
211                   if ( *c == '\n' ) {
212                     _buffer += std::string( s, c-s );
213                     logger::putStream( _group, _level, _file, _func, _line, _buffer );
214                     _buffer = std::string();
215                     s = c+1;
216                   }
217                 }
218               if ( s < c )
219                 {
220                   _buffer += std::string( s, c-s );
221                 }
222             }
223           return n;
224         }
225
226       private:
227         std::string  _group;
228         LogLevel     _level;
229         const char * _file;
230         const char * _func;
231         int          _line;
232         std::string  _buffer;
233       };
234
235       ///////////////////////////////////////////////////////////////////
236
237       ///////////////////////////////////////////////////////////////////
238       //
239       //        CLASS NAME : Loglinestream
240       //
241       class Loglinestream {
242
243       public:
244         /** */
245         Loglinestream( const std::string & group_r, LogLevel level_r )
246         : _mybuf( group_r, level_r )
247         , _mystream( &_mybuf )
248         {}
249         /** */
250         ~Loglinestream()
251         { _mystream.flush(); }
252
253       public:
254         /** */
255         std::ostream & getStream( const char * fil_r, const char * fnc_r, int lne_r )
256         {
257           _mybuf.tagSet( fil_r, fnc_r, lne_r );
258           return _mystream;
259         }
260
261       private:
262         Loglinebuf   _mybuf;
263         std::ostream _mystream;
264       };
265       ///////////////////////////////////////////////////////////////////
266
267       ///////////////////////////////////////////////////////////////////
268       //
269       //        CLASS NAME : LogControlImpl
270       //
271       /** LogControl implementation (Singleton).
272        *
273        * \note There is a slight difference in using the _lineFormater and _lineWriter!
274        * \li \c _lineFormater must not be NULL (create default LogControl::LineFormater)
275        * \li \c _lineWriter is NULL if no logging is performed, this way we can pass
276        *        _no_stream as logstream to the application, and avoid unnecessary formating
277        *        of logliles, which would then be discarded when passed to some dummy
278        *        LineWriter.
279       */
280       struct LogControlImpl
281       {
282       public:
283         bool isExcessive()
284         { return _excessive; }
285
286         void excessive( bool onOff_r )
287         { _excessive = onOff_r; }
288
289         /** NULL _lineWriter indicates no loggin. */
290         void setLineWriter( const shared_ptr<LogControl::LineWriter> & writer_r )
291         { _lineWriter = writer_r; }
292
293         shared_ptr<LogControl::LineWriter> getLineWriter() const
294         { return _lineWriter; }
295
296         /** Assert \a _lineFormater is not NULL. */
297         void setLineFormater( const shared_ptr<LogControl::LineFormater> & format_r )
298         {
299           if ( format_r )
300             _lineFormater = format_r;
301           else
302             _lineFormater.reset( new LogControl::LineFormater );
303         }
304
305         void logfile( const Pathname & logfile_r, mode_t mode_r = 0640 )
306         {
307           if ( logfile_r.empty() )
308             setLineWriter( shared_ptr<LogControl::LineWriter>() );
309           else if ( logfile_r == Pathname( "-" ) )
310             setLineWriter( shared_ptr<LogControl::LineWriter>(new log::StderrLineWriter) );
311           else
312             setLineWriter( shared_ptr<LogControl::LineWriter>(new log::FileLineWriter(logfile_r, mode_r)) );
313         }
314
315       private:
316         std::ostream _no_stream;
317         bool         _excessive;
318
319         shared_ptr<LogControl::LineFormater> _lineFormater;
320         shared_ptr<LogControl::LineWriter>   _lineWriter;
321
322       public:
323         /** Provide the log stream to write (logger interface) */
324         std::ostream & getStream( const std::string & group_r,
325                                   LogLevel            level_r,
326                                   const char *        file_r,
327                                   const char *        func_r,
328                                   const int           line_r )
329         {
330           if ( ! _lineWriter )
331             return _no_stream;
332           if ( level_r == E_XXX && !_excessive )
333             return _no_stream;
334
335           if ( !_streamtable[group_r][level_r] )
336             {
337               _streamtable[group_r][level_r].reset( new Loglinestream( group_r, level_r ) );
338             }
339           std::ostream & ret( _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r ) );
340           if ( !ret )
341           {
342             ret.clear();
343             ret << "---<RESET LOGSTREAM FROM FAILED STATE]" << endl;
344           }
345           return ret;
346         }
347
348         /** Format and write out a logline from Loglinebuf. */
349         void putStream( const std::string & group_r,
350                         LogLevel            level_r,
351                         const char *        file_r,
352                         const char *        func_r,
353                         int                 line_r,
354                         const std::string & message_r )
355         {
356           if ( _lineWriter )
357             _lineWriter->writeOut( _lineFormater->format( group_r, level_r,
358                                                           file_r, func_r, line_r,
359                                                           message_r ) );
360         }
361
362       private:
363         typedef shared_ptr<Loglinestream>        StreamPtr;
364         typedef std::map<LogLevel,StreamPtr>     StreamSet;
365         typedef std::map<std::string,StreamSet>  StreamTable;
366         /** one streambuffer per group and level */
367         StreamTable _streamtable;
368
369       private:
370         /** Singleton ctor.
371          * No logging per default, unless enabled via $ZYPP_LOGFILE.
372         */
373         LogControlImpl()
374         : _no_stream( NULL )
375         , _excessive( getenv("ZYPP_FULLLOG") )
376         , _lineFormater( new LogControl::LineFormater )
377         {
378           if ( getenv("ZYPP_LOGFILE") )
379             logfile( getenv("ZYPP_LOGFILE") );
380
381           if ( getenv("ZYPP_PROFILING") )
382           {
383             shared_ptr<LogControl::LineFormater> formater(new ProfilingFormater);
384             setLineFormater(formater);
385           }
386         }
387
388         ~LogControlImpl()
389         {
390           _lineWriter.reset();
391         }
392
393       public:
394         /** The LogControlImpl singleton
395          * \note As most dtors log, it is inportant that the
396          * LogControlImpl instance is the last static variable
397          * destructed. At least destucted after all statics
398          * which log from their dtor.
399         */
400         static LogControlImpl & instance();
401       };
402       ///////////////////////////////////////////////////////////////////
403
404       // 'THE' LogControlImpl singleton
405       inline LogControlImpl & LogControlImpl::instance()
406       {
407         static LogControlImpl _instance;
408         return _instance;
409       }
410
411       ///////////////////////////////////////////////////////////////////
412
413       /** \relates LogControlImpl Stream output */
414       inline std::ostream & operator<<( std::ostream & str, const LogControlImpl & obj )
415       {
416         return str << "LogControlImpl";
417       }
418
419       ///////////////////////////////////////////////////////////////////
420       //
421       // Access from logger::
422       //
423       ///////////////////////////////////////////////////////////////////
424
425       std::ostream & getStream( const char * group_r,
426                                 LogLevel     level_r,
427                                 const char * file_r,
428                                 const char * func_r,
429                                 const int    line_r )
430       {
431         return LogControlImpl::instance().getStream( group_r,
432                                                    level_r,
433                                                    file_r,
434                                                    func_r,
435                                                    line_r );
436       }
437
438       /** That's what Loglinebuf calls.  */
439       inline void putStream( const std::string & group_r, LogLevel level_r,
440                              const char * file_r, const char * func_r, int line_r,
441                              const std::string & buffer_r )
442       {
443         LogControlImpl::instance().putStream( group_r, level_r,
444                                             file_r, func_r, line_r,
445                                             buffer_r );
446       }
447
448       bool isExcessive()
449       { return LogControlImpl::instance().isExcessive(); }
450
451       /////////////////////////////////////////////////////////////////
452     } // namespace logger
453     ///////////////////////////////////////////////////////////////////
454
455     ///////////////////////////////////////////////////////////////////
456     //
457     //  CLASS NAME : LogControl
458     //  Forward to LogControlImpl singleton.
459     //
460     ///////////////////////////////////////////////////////////////////
461
462     using logger::LogControlImpl;
463
464     void LogControl::logfile( const Pathname & logfile_r )
465     { LogControlImpl::instance().logfile( logfile_r ); }
466
467     void LogControl::logfile( const Pathname & logfile_r, mode_t mode_r )
468     { LogControlImpl::instance().logfile( logfile_r, mode_r ); }
469
470     shared_ptr<LogControl::LineWriter> LogControl::getLineWriter() const
471     { return LogControlImpl::instance().getLineWriter(); }
472
473     void LogControl::setLineWriter( const shared_ptr<LineWriter> & writer_r )
474     { LogControlImpl::instance().setLineWriter( writer_r ); }
475
476     void LogControl::setLineFormater( const shared_ptr<LineFormater> & formater_r )
477     { LogControlImpl::instance().setLineFormater( formater_r ); }
478
479     void LogControl::logNothing()
480     { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>() ); }
481
482     void LogControl::logToStdErr()
483     { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>( new log::StderrLineWriter ) ); }
484
485     ///////////////////////////////////////////////////////////////////
486     //
487     // LogControl::TmpExcessive
488     //
489     ///////////////////////////////////////////////////////////////////
490     LogControl::TmpExcessive::TmpExcessive()
491     { LogControlImpl::instance().excessive( true ); }
492     LogControl::TmpExcessive::~TmpExcessive()
493     { LogControlImpl::instance().excessive( false );  }
494
495     /******************************************************************
496      **
497      ** FUNCTION NAME : operator<<
498      ** FUNCTION TYPE : std::ostream &
499     */
500     std::ostream & operator<<( std::ostream & str, const LogControl & obj )
501     {
502       return str << LogControlImpl::instance();
503     }
504
505     /////////////////////////////////////////////////////////////////
506   } // namespace base
507   ///////////////////////////////////////////////////////////////////
508   /////////////////////////////////////////////////////////////////
509 } // namespace zypp
510 ///////////////////////////////////////////////////////////////////