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