1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/base/LogControl.cc
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"
25 ///////////////////////////////////////////////////////////////////
27 { /////////////////////////////////////////////////////////////////
32 void osdlog( const std::string & msg_r, unsigned level_r )
34 // Fg::Black: 30 Bg: 40 Attr::Normal: 22;27
35 // Fg::Red: 31 ... Attr::Bright: 1
36 // Fg::Green: 32 Attr::Reverse: 7
43 static const char * ansi[] = {
46 "\033[33;1;40m", // 2 y
48 "\033[31;1;40m", // 4 r
51 static const unsigned n = sizeof(ansi)/sizeof(const char *);
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;
61 std::cerr << ansi[level_r%n] << "OSD[" << msg_r << "]\033[0m" << std::endl;
65 unsigned TraceLeave::_depth = 0;
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) )
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;
78 TraceLeave::~TraceLeave()
79 { USR << "<<< " << std::string(--_depth,'<') << " " << _file << "(" << _fnc << "):" << _line << endl; }
83 ///////////////////////////////////////////////////////////////////
85 { /////////////////////////////////////////////////////////////////
87 StdoutLineWriter::StdoutLineWriter()
88 : StreamLineWriter( std::cout )
91 StderrLineWriter::StderrLineWriter()
92 : StreamLineWriter( std::cerr )
95 FileLineWriter::FileLineWriter( const Pathname & file_r, mode_t mode_r )
97 if ( file_r == Pathname("-") )
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 );
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);
119 /////////////////////////////////////////////////////////////////
121 ///////////////////////////////////////////////////////////////////
123 ///////////////////////////////////////////////////////////////////
125 { /////////////////////////////////////////////////////////////////
127 ///////////////////////////////////////////////////////////////////
129 ///////////////////////////////////////////////////////////////////
130 std::string LogControl::LineFormater::format( const std::string & group_r,
131 logger::LogLevel level_r,
135 const std::string & message_r )
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 ),
145 file_r, func_r, line_r,
149 ///////////////////////////////////////////////////////////////////
151 { /////////////////////////////////////////////////////////////////
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 );
157 ///////////////////////////////////////////////////////////////////
159 // CLASS NAME : Loglinebuf
161 class Loglinebuf : public std::streambuf {
165 Loglinebuf( const std::string & group_r, LogLevel level_r )
175 if ( !_buffer.empty() )
180 void tagSet( const char * fil_r, const char * fnc_r, int lne_r )
189 virtual std::streamsize xsputn( const char * s, std::streamsize n )
190 { return writeout( s, n ); }
192 virtual int overflow( int ch = EOF )
202 virtual int writeout( const char* s, std::streamsize n )
204 //logger::putStream( _group, _level, _file, _func, _line, _buffer );
209 for ( int i = 0; i < n; ++i, ++c )
212 _buffer += std::string( s, c-s );
213 logger::putStream( _group, _level, _file, _func, _line, _buffer );
214 _buffer = std::string();
220 _buffer += std::string( s, c-s );
235 ///////////////////////////////////////////////////////////////////
237 ///////////////////////////////////////////////////////////////////
239 // CLASS NAME : Loglinestream
241 class Loglinestream {
245 Loglinestream( const std::string & group_r, LogLevel level_r )
246 : _mybuf( group_r, level_r )
247 , _mystream( &_mybuf )
251 { _mystream.flush(); }
255 std::ostream & getStream( const char * fil_r, const char * fnc_r, int lne_r )
257 _mybuf.tagSet( fil_r, fnc_r, lne_r );
263 std::ostream _mystream;
265 ///////////////////////////////////////////////////////////////////
267 ///////////////////////////////////////////////////////////////////
269 // CLASS NAME : LogControlImpl
271 /** LogControl implementation (Singleton).
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
280 struct LogControlImpl
284 { return _excessive; }
286 void excessive( bool onOff_r )
287 { _excessive = onOff_r; }
289 /** NULL _lineWriter indicates no loggin. */
290 void setLineWriter( const shared_ptr<LogControl::LineWriter> & writer_r )
291 { _lineWriter = writer_r; }
293 shared_ptr<LogControl::LineWriter> getLineWriter() const
294 { return _lineWriter; }
296 /** Assert \a _lineFormater is not NULL. */
297 void setLineFormater( const shared_ptr<LogControl::LineFormater> & format_r )
300 _lineFormater = format_r;
302 _lineFormater.reset( new LogControl::LineFormater );
305 void logfile( const Pathname & logfile_r, mode_t mode_r = 0640 )
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) );
312 setLineWriter( shared_ptr<LogControl::LineWriter>(new log::FileLineWriter(logfile_r, mode_r)) );
316 std::ostream _no_stream;
319 shared_ptr<LogControl::LineFormater> _lineFormater;
320 shared_ptr<LogControl::LineWriter> _lineWriter;
323 /** Provide the log stream to write (logger interface) */
324 std::ostream & getStream( const std::string & group_r,
332 if ( level_r == E_XXX && !_excessive )
335 if ( !_streamtable[group_r][level_r] )
337 _streamtable[group_r][level_r].reset( new Loglinestream( group_r, level_r ) );
339 std::ostream & ret( _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r ) );
343 ret << "---<RESET LOGSTREAM FROM FAILED STATE]" << endl;
348 /** Format and write out a logline from Loglinebuf. */
349 void putStream( const std::string & group_r,
354 const std::string & message_r )
357 _lineWriter->writeOut( _lineFormater->format( group_r, level_r,
358 file_r, func_r, line_r,
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;
371 * No logging per default, unless enabled via $ZYPP_LOGFILE.
375 , _excessive( getenv("ZYPP_FULLLOG") )
376 , _lineFormater( new LogControl::LineFormater )
378 if ( getenv("ZYPP_LOGFILE") )
379 logfile( getenv("ZYPP_LOGFILE") );
381 if ( getenv("ZYPP_PROFILING") )
383 shared_ptr<LogControl::LineFormater> formater(new ProfilingFormater);
384 setLineFormater(formater);
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.
400 static LogControlImpl & instance();
402 ///////////////////////////////////////////////////////////////////
404 // 'THE' LogControlImpl singleton
405 inline LogControlImpl & LogControlImpl::instance()
407 static LogControlImpl _instance;
411 ///////////////////////////////////////////////////////////////////
413 /** \relates LogControlImpl Stream output */
414 inline std::ostream & operator<<( std::ostream & str, const LogControlImpl & obj )
416 return str << "LogControlImpl";
419 ///////////////////////////////////////////////////////////////////
421 // Access from logger::
423 ///////////////////////////////////////////////////////////////////
425 std::ostream & getStream( const char * group_r,
431 return LogControlImpl::instance().getStream( group_r,
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 )
443 LogControlImpl::instance().putStream( group_r, level_r,
444 file_r, func_r, line_r,
449 { return LogControlImpl::instance().isExcessive(); }
451 /////////////////////////////////////////////////////////////////
452 } // namespace logger
453 ///////////////////////////////////////////////////////////////////
455 ///////////////////////////////////////////////////////////////////
457 // CLASS NAME : LogControl
458 // Forward to LogControlImpl singleton.
460 ///////////////////////////////////////////////////////////////////
462 using logger::LogControlImpl;
464 void LogControl::logfile( const Pathname & logfile_r )
465 { LogControlImpl::instance().logfile( logfile_r ); }
467 void LogControl::logfile( const Pathname & logfile_r, mode_t mode_r )
468 { LogControlImpl::instance().logfile( logfile_r, mode_r ); }
470 shared_ptr<LogControl::LineWriter> LogControl::getLineWriter() const
471 { return LogControlImpl::instance().getLineWriter(); }
473 void LogControl::setLineWriter( const shared_ptr<LineWriter> & writer_r )
474 { LogControlImpl::instance().setLineWriter( writer_r ); }
476 void LogControl::setLineFormater( const shared_ptr<LineFormater> & formater_r )
477 { LogControlImpl::instance().setLineFormater( formater_r ); }
479 void LogControl::logNothing()
480 { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>() ); }
482 void LogControl::logToStdErr()
483 { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>( new log::StderrLineWriter ) ); }
485 ///////////////////////////////////////////////////////////////////
487 // LogControl::TmpExcessive
489 ///////////////////////////////////////////////////////////////////
490 LogControl::TmpExcessive::TmpExcessive()
491 { LogControlImpl::instance().excessive( true ); }
492 LogControl::TmpExcessive::~TmpExcessive()
493 { LogControlImpl::instance().excessive( false ); }
495 /******************************************************************
497 ** FUNCTION NAME : operator<<
498 ** FUNCTION TYPE : std::ostream &
500 std::ostream & operator<<( std::ostream & str, const LogControl & obj )
502 return str << LogControlImpl::instance();
505 /////////////////////////////////////////////////////////////////
507 ///////////////////////////////////////////////////////////////////
508 /////////////////////////////////////////////////////////////////
510 ///////////////////////////////////////////////////////////////////