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 { /////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////
31 { /////////////////////////////////////////////////////////////////
33 StdoutLineWriter::StdoutLineWriter()
34 : StreamLineWriter( std::cout )
37 StderrLineWriter::StderrLineWriter()
38 : StreamLineWriter( std::cerr )
41 FileLineWriter::FileLineWriter( const Pathname & file_r, mode_t mode_r )
43 if ( file_r == Pathname("-") )
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 );
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);
65 /////////////////////////////////////////////////////////////////
67 ///////////////////////////////////////////////////////////////////
69 ///////////////////////////////////////////////////////////////////
71 { /////////////////////////////////////////////////////////////////
73 ///////////////////////////////////////////////////////////////////
75 ///////////////////////////////////////////////////////////////////
76 std::string LogControl::LineFormater::format( const std::string & group_r,
77 logger::LogLevel level_r,
81 const std::string & message_r )
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",
88 ( gethostname( hostname, 1024 ) ? nohostname : hostname ),
91 file_r, func_r, line_r,
95 ///////////////////////////////////////////////////////////////////
97 { /////////////////////////////////////////////////////////////////
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 );
103 ///////////////////////////////////////////////////////////////////
105 // CLASS NAME : Loglinebuf
107 class Loglinebuf : public std::streambuf {
111 Loglinebuf( const std::string & group_r, LogLevel level_r )
121 if ( !_buffer.empty() )
126 void tagSet( const char * fil_r, const char * fnc_r, int lne_r )
135 virtual std::streamsize xsputn( const char * s, std::streamsize n )
136 { return writeout( s, n ); }
138 virtual int overflow( int ch = EOF )
148 virtual int writeout( const char* s, std::streamsize n )
150 //logger::putStream( _group, _level, _file, _func, _line, _buffer );
155 for ( int i = 0; i < n; ++i, ++c )
158 _buffer += std::string( s, c-s );
159 logger::putStream( _group, _level, _file, _func, _line, _buffer );
160 _buffer = std::string();
166 _buffer += std::string( s, c-s );
181 ///////////////////////////////////////////////////////////////////
183 ///////////////////////////////////////////////////////////////////
185 // CLASS NAME : Loglinestream
187 class Loglinestream {
191 Loglinestream( const std::string & group_r, LogLevel level_r )
192 : _mybuf( group_r, level_r )
193 , _mystream( &_mybuf )
197 { _mystream.flush(); }
201 std::ostream & getStream( const char * fil_r, const char * fnc_r, int lne_r )
203 _mybuf.tagSet( fil_r, fnc_r, lne_r );
209 std::ostream _mystream;
211 ///////////////////////////////////////////////////////////////////
213 ///////////////////////////////////////////////////////////////////
215 // CLASS NAME : LogControlImpl
217 /** LogControl implementation (Singleton).
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
226 struct LogControlImpl
230 { return _excessive; }
232 void excessive( bool onOff_r )
233 { _excessive = onOff_r; }
235 /** NULL _lineWriter indicates no loggin. */
236 void setLineWriter( const shared_ptr<LogControl::LineWriter> & writer_r )
237 { _lineWriter = writer_r; }
239 shared_ptr<LogControl::LineWriter> getLineWriter() const
240 { return _lineWriter; }
242 /** Assert \a _lineFormater is not NULL. */
243 void setLineFormater( const shared_ptr<LogControl::LineFormater> & format_r )
246 _lineFormater = format_r;
248 _lineFormater.reset( new LogControl::LineFormater );
251 void logfile( const Pathname & logfile_r, mode_t mode_r = 0640 )
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) );
258 setLineWriter( shared_ptr<LogControl::LineWriter>(new log::FileLineWriter(logfile_r, mode_r)) );
262 std::ostream _no_stream;
265 shared_ptr<LogControl::LineFormater> _lineFormater;
266 shared_ptr<LogControl::LineWriter> _lineWriter;
269 /** Provide the log stream to write (logger interface) */
270 std::ostream & getStream( const std::string & group_r,
278 if ( level_r == E_XXX && !_excessive )
281 if ( !_streamtable[group_r][level_r] )
283 _streamtable[group_r][level_r].reset( new Loglinestream( group_r, level_r ) );
285 std::ostream & ret( _streamtable[group_r][level_r]->getStream( file_r, func_r, line_r ) );
289 ret << "---<RESET LOGSTREAM FROM FAILED STATE]" << endl;
294 /** Format and write out a logline from Loglinebuf. */
295 void putStream( const std::string & group_r,
300 const std::string & message_r )
303 _lineWriter->writeOut( _lineFormater->format( group_r, level_r,
304 file_r, func_r, line_r,
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;
317 * No logging per default, unless enabled via $ZYPP_LOGFILE.
321 , _excessive( getenv("ZYPP_FULLLOG") )
322 , _lineFormater( new LogControl::LineFormater )
324 if ( getenv("ZYPP_LOGFILE") )
325 logfile( getenv("ZYPP_LOGFILE") );
327 if ( getenv("ZYPP_PROFILING") )
329 shared_ptr<LogControl::LineFormater> formater(new ProfilingFormater);
330 setLineFormater(formater);
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.
346 static LogControlImpl & instance();
348 ///////////////////////////////////////////////////////////////////
350 // 'THE' LogControlImpl singleton
351 inline LogControlImpl & LogControlImpl::instance()
353 static LogControlImpl _instance;
357 ///////////////////////////////////////////////////////////////////
359 /** \relates LogControlImpl Stream output */
360 inline std::ostream & operator<<( std::ostream & str, const LogControlImpl & obj )
362 return str << "LogControlImpl";
365 ///////////////////////////////////////////////////////////////////
367 // Access from logger::
369 ///////////////////////////////////////////////////////////////////
371 std::ostream & getStream( const char * group_r,
377 return LogControlImpl::instance().getStream( group_r,
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 )
389 LogControlImpl::instance().putStream( group_r, level_r,
390 file_r, func_r, line_r,
395 { return LogControlImpl::instance().isExcessive(); }
397 /////////////////////////////////////////////////////////////////
398 } // namespace logger
399 ///////////////////////////////////////////////////////////////////
401 ///////////////////////////////////////////////////////////////////
403 // CLASS NAME : LogControl
404 // Forward to LogControlImpl singleton.
406 ///////////////////////////////////////////////////////////////////
408 using logger::LogControlImpl;
410 void LogControl::logfile( const Pathname & logfile_r )
411 { LogControlImpl::instance().logfile( logfile_r ); }
413 void LogControl::logfile( const Pathname & logfile_r, mode_t mode_r )
414 { LogControlImpl::instance().logfile( logfile_r, mode_r ); }
416 shared_ptr<LogControl::LineWriter> LogControl::getLineWriter() const
417 { return LogControlImpl::instance().getLineWriter(); }
419 void LogControl::setLineWriter( const shared_ptr<LineWriter> & writer_r )
420 { LogControlImpl::instance().setLineWriter( writer_r ); }
422 void LogControl::setLineFormater( const shared_ptr<LineFormater> & formater_r )
423 { LogControlImpl::instance().setLineFormater( formater_r ); }
425 void LogControl::logNothing()
426 { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>() ); }
428 void LogControl::logToStdErr()
429 { LogControlImpl::instance().setLineWriter( shared_ptr<LineWriter>( new log::StderrLineWriter ) ); }
431 ///////////////////////////////////////////////////////////////////
433 // LogControl::TmpExcessive
435 ///////////////////////////////////////////////////////////////////
436 LogControl::TmpExcessive::TmpExcessive()
437 { LogControlImpl::instance().excessive( true ); }
438 LogControl::TmpExcessive::~TmpExcessive()
439 { LogControlImpl::instance().excessive( false ); }
441 /******************************************************************
443 ** FUNCTION NAME : operator<<
444 ** FUNCTION TYPE : std::ostream &
446 std::ostream & operator<<( std::ostream & str, const LogControl & obj )
448 return str << LogControlImpl::instance();
451 /////////////////////////////////////////////////////////////////
453 ///////////////////////////////////////////////////////////////////
454 /////////////////////////////////////////////////////////////////
456 ///////////////////////////////////////////////////////////////////