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