LCOV - code coverage report
Current view: top level - lunchbox - log.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 106 200 53.0 %
Date: 2014-10-01 Functions: 28 53 52.8 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2013, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *               2011-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #include <pthread.h>
      20             : 
      21             : #include "log.h"
      22             : 
      23             : #include "clock.h"
      24             : #include "perThread.h"
      25             : #include "scopedMutex.h"
      26             : #include "thread.h"
      27             : 
      28             : #include <cstdio>
      29             : #include <cstdlib>
      30             : #include <fstream>
      31             : 
      32             : #ifdef _MSC_VER
      33             : #  include <process.h>
      34             : #  define atoll _atoi64
      35             : #  define snprintf _snprintf
      36             : #  define getpid _getpid
      37             : #else
      38             : #  include <unistd.h>
      39             : #endif
      40             : 
      41             : namespace lunchbox
      42             : {
      43             : static const size_t threadNameLength = 8;
      44             : 
      45             : static unsigned getLogTopics();
      46          30 : static Clock    _defaultClock;
      47             : static Clock*   _clock = &_defaultClock;
      48          30 : static Lock     _lock; // The write lock
      49             : 
      50             : namespace detail
      51             : {
      52             : /** @internal The string buffer used for logging. */
      53             : class Log : public std::streambuf
      54             : {
      55             : public:
      56        3505 :     explicit Log( std::ostream& stream )
      57             :         : _indent(0), _blocked(0), _noHeader(0),
      58        3505 :           _newLine(true), _stream(stream)
      59        3505 :     { _file[0] = 0; }
      60             : 
      61        7005 :     virtual ~Log() {}
      62             : 
      63           0 :     void indent() { ++_indent; }
      64           0 :     void exdent() { --_indent; }
      65             : 
      66           0 :     void disableFlush() { ++_blocked; assert( _blocked < 100 ); }
      67           0 :     void enableFlush()
      68             :     {
      69           0 :         assert( _blocked );// Too many enableFlush on log stream
      70           0 :         --_blocked;
      71           0 :     }
      72             : 
      73           0 :     void disableHeader() { ++_noHeader; } // use counted variable to allow
      74           0 :     void enableHeader()  { --_noHeader; } //   nested enable/disable calls
      75             : 
      76        3530 :     void setThreadName( const std::string& name )
      77             :     {
      78        3530 :         LBASSERT( !name.empty( ));
      79        3530 :         _thread = name.substr( 0, threadNameLength );
      80       25100 :         while( _thread.size() < threadNameLength )
      81       18040 :             _thread += std::string( " " );
      82        3530 :     }
      83             : 
      84         306 :     const std::string& getThreadName() const { return _thread; }
      85             : 
      86        3507 :     void setLogInfo( const char* f, const int line )
      87             :     {
      88        3507 :         LBASSERT( f );
      89        3507 :         std::string file( f );
      90        3507 :         const size_t length = file.length();
      91             : 
      92        3507 :         if( length > 29 )
      93        3507 :             file = file.substr( length - 29, length );
      94             : 
      95        3507 :         snprintf( _file, 35, "%29s:%-4d", file.c_str(), line );
      96        3507 :     }
      97             : 
      98             : protected:
      99      194598 :     virtual int_type overflow( Log::int_type c ) override
     100             :     {
     101      194598 :         if( c == EOF )
     102           0 :             return EOF;
     103             : 
     104      194598 :         if( _newLine )
     105             :         {
     106        3507 :             if( !_noHeader )
     107             :             {
     108        3507 :                 _stringStream << getpid()  << "." << _thread << " " << _file
     109        7014 :                               << " " << _clock->getTime64() << " ";
     110             :             }
     111             : 
     112        3507 :             for( int i=0; i<_indent; ++i )
     113           0 :                 _stringStream << "    ";
     114        3507 :             _newLine = false;
     115             :         }
     116             : 
     117      194598 :         _stringStream << (char)c;
     118      194598 :         return c;
     119             :     }
     120             : 
     121       10412 :     virtual int sync() override
     122             :     {
     123       10412 :         if( !_blocked )
     124             :         {
     125       10452 :             const std::string& string = _stringStream.str();
     126             :             {
     127       10440 :                 ScopedMutex< lunchbox::Lock > mutex( _lock );
     128       10477 :                 _stream.write( string.c_str(), string.length( ));
     129       10477 :                 _stream.rdbuf()->pubsync();
     130             :             }
     131       10460 :             _stringStream.str( "" );
     132             :         }
     133       10454 :         _newLine = true;
     134       10454 :         return 0;
     135             :     }
     136             : 
     137             : private:
     138             :     Log( const Log& );
     139             :     Log& operator = ( const Log& );
     140             : 
     141             :     /** Short thread name. */
     142             :     std::string _thread;
     143             : 
     144             :     /** The current file logging. */
     145             :     char _file[35];
     146             : 
     147             :     /** The current indentation level. */
     148             :     int _indent;
     149             : 
     150             :     /** Flush reference counter. */
     151             :     int _blocked;
     152             : 
     153             :     /** The header disable counter. */
     154             :     int _noHeader;
     155             : 
     156             :     /** The flag that a new line has started. */
     157             :     bool _newLine;
     158             : 
     159             :     /** The temporary buffer. */
     160             :     std::ostringstream _stringStream;
     161             : 
     162             :     /** The wrapped ostream. */
     163             :     std::ostream& _stream;
     164             : };
     165             : }
     166             : 
     167             : namespace
     168             : {
     169         150 : class LogTable
     170             : {
     171             : public:
     172         150 :     LogTable( const LogLevel _level, const std::string& _name )
     173         150 :             : level( _level ), name( _name ) {}
     174             : 
     175             :     LogLevel level;
     176             :     std::string name;
     177             : };
     178             : 
     179             : #define LOG_TABLE_ENTRY( name ) LogTable( LOG_ ## name, std::string( #name ))
     180             : #define LOG_TABLE_SIZE (5)
     181             : 
     182          60 : static LogTable _logTable[ LOG_TABLE_SIZE ] =
     183             : {
     184             :     LOG_TABLE_ENTRY( ERROR ),
     185             :     LOG_TABLE_ENTRY( WARN ),
     186             :     LOG_TABLE_ENTRY( INFO ),
     187             :     LOG_TABLE_ENTRY( VERB ),
     188             :     LOG_TABLE_ENTRY( ALL )
     189          30 : };
     190             : }
     191             : 
     192          30 : int      Log::level  = Log::getLogLevel( getenv( "LB_LOG_LEVEL" ));
     193          30 : unsigned Log::topics = getLogTopics();
     194             : 
     195          30 : static PerThread< Log > _logInstance;
     196             : 
     197             : #ifdef NDEBUG
     198             : static std::ostream* _logStream = &std::cout;
     199             : #else
     200             : static std::ostream* _logStream = &std::cerr;
     201             : #endif
     202             : static std::ostream* _logFile = 0;
     203             : 
     204        3505 : Log::Log()
     205        3505 :     : std::ostream( new detail::Log( getOutput( )))
     206        7010 :     , impl_( dynamic_cast< detail::Log* >( rdbuf( )))
     207        3505 : {}
     208             : 
     209       13962 : Log::~Log()
     210             : {
     211        3492 :     impl_->pubsync();
     212        3500 :     delete impl_;
     213       10476 : }
     214             : 
     215           0 : void Log::indent()
     216             : {
     217           0 :     impl_->indent();
     218           0 : }
     219             : 
     220           0 : void Log::exdent()
     221             : {
     222           0 :     impl_->exdent();
     223           0 : }
     224             : 
     225           0 : void Log::disableFlush()
     226             : {
     227           0 :     impl_->disableFlush();
     228           0 : }
     229             : 
     230           0 : void Log::enableFlush()
     231             : {
     232           0 :     impl_->enableFlush();
     233           0 : }
     234             : 
     235        3418 : void Log::forceFlush()
     236             : {
     237        3418 :     impl_->pubsync();
     238        3449 : }
     239             : 
     240           0 : void Log::disableHeader()
     241             : {
     242           0 :     impl_->disableHeader();
     243           0 : }
     244             : 
     245           0 : void Log::enableHeader()
     246             : {
     247           0 :     impl_->enableHeader();
     248           0 : }
     249             : 
     250        3507 : void Log::setLogInfo( const char* file, const int line )
     251             : {
     252        3507 :     impl_->setLogInfo( file, line );
     253        3507 : }
     254             : 
     255        3530 : void Log::setThreadName( const std::string& name )
     256             : {
     257        3530 :     impl_->setThreadName( name );
     258        3530 : }
     259             : 
     260         306 : const std::string& Log::getThreadName() const
     261             : {
     262         306 :     return impl_->getThreadName();
     263             : }
     264             : 
     265          60 : int Log::getLogLevel( const char* text )
     266             : {
     267          60 :     if( text )
     268             :     {
     269          60 :         const int num = atoi( text );
     270          60 :         if( num > 0 && num <= LOG_ALL )
     271          60 :             return num;
     272             : 
     273           0 :         for( uint32_t i = 0; i < LOG_TABLE_SIZE; ++i )
     274           0 :             if( _logTable[i].name == text )
     275           0 :                 return _logTable[i].level;
     276             :     }
     277             : 
     278             : #ifdef NDEBUG
     279             :     return LOG_WARN;
     280             : #else
     281           0 :     return LOG_INFO;
     282             : #endif
     283             : }
     284             : 
     285           5 : std::string& Log::getLogLevelString()
     286             : {
     287          15 :     for( uint32_t i=0; i<LOG_TABLE_SIZE; ++i )
     288          15 :         if( _logTable[i].level == level )
     289           5 :                 return _logTable[i].name;
     290             : 
     291           0 :     return _logTable[0].name;
     292             : }
     293             : 
     294          30 : unsigned getLogTopics()
     295             : {
     296          30 :     Log::level = Log::getLogLevel( getenv( "LB_LOG_LEVEL" ));
     297          30 :     const char *env = getenv( "LB_LOG_TOPICS" );
     298             : 
     299          30 :     if( env )
     300           0 :         return atoll(env);
     301             : 
     302          30 :     if( Log::level == LOG_ALL )
     303           0 :         return 0xffffffffu;
     304             : 
     305          30 :     return 0;
     306             : }
     307             : 
     308       14229 : Log& Log::instance()
     309             : {
     310       14229 :     Log* log = _logInstance.get();
     311       14227 :     if( !log )
     312             :     {
     313        3505 :         log = new Log();
     314        3505 :         _logInstance = log;
     315             :     }
     316             : 
     317       14243 :     return *log;
     318             : }
     319             : 
     320        3507 : Log& Log::instance( const char* file, const int line )
     321             : {
     322        3507 :     Log& log = instance();
     323        3507 :     log.setLogInfo( file, line );
     324        3507 :     return log;
     325             : }
     326             : 
     327        3451 : void Log::exit()
     328             : {
     329        3451 :     Log* log = _logInstance.get();
     330        3453 :     _logInstance = 0;
     331        3457 :     delete log;
     332        3456 : }
     333             : 
     334           5 : void Log::reset()
     335             : {
     336           5 :     exit();
     337             : 
     338           5 :     delete _logFile;
     339           5 :     _logFile = 0;
     340             : 
     341             : #ifdef NDEBUG
     342             :     _logStream = &std::cout;
     343             : #else
     344           5 :     _logStream = &std::cerr;
     345             : #endif
     346           5 : }
     347             : 
     348           0 : void Log::setOutput( std::ostream& stream )
     349             : {
     350           0 :     _logStream = &stream;
     351           0 :     exit();
     352           0 : }
     353             : 
     354           0 : bool Log::setOutput( const std::string& file )
     355             : {
     356           0 :     std::ostream* oldLog = _logStream;
     357           0 :     std::ofstream* newLog = new std::ofstream( file.c_str( ));
     358             : 
     359           0 :     if( newLog->is_open( ))
     360             :     {
     361           0 :         setOutput( *newLog );
     362           0 :         *oldLog << "Redirected log to " << file << std::endl;
     363             : 
     364           0 :         delete _logFile;
     365           0 :         _logFile = newLog;
     366           0 :         return true;
     367             :     }
     368             : 
     369           0 :     LBWARN << "Can't open log file " << file << ": " << sysError << std::endl;
     370           0 :     delete newLog;
     371           0 :     return false;
     372             : }
     373             : 
     374           0 : void Log::setClock( Clock* clock )
     375             : {
     376           0 :     if( clock )
     377           0 :         _clock = clock;
     378             :     else
     379           0 :         _clock = &_defaultClock;
     380           0 : }
     381             : 
     382           0 : const Clock& Log::getClock()
     383             : {
     384           0 :     return *_clock;
     385             : }
     386             : 
     387        3505 : std::ostream& Log::getOutput()
     388             : {
     389        3505 :     return *_logStream;
     390             : }
     391             : 
     392           0 : std::ostream& indent( std::ostream& os )
     393             : {
     394           0 :     Log* log = dynamic_cast<Log*>(&os);
     395           0 :     if( log )
     396           0 :         log->indent();
     397           0 :     return os;
     398             : }
     399           0 : std::ostream& exdent( std::ostream& os )
     400             : {
     401           0 :     Log* log = dynamic_cast<Log*>(&os);
     402           0 :     if( log )
     403           0 :         log->exdent();
     404           0 :         return os;
     405             : }
     406             : 
     407           0 : std::ostream& disableFlush( std::ostream& os )
     408             : {
     409           0 :     Log* log = dynamic_cast<Log*>(&os);
     410           0 :     if( log )
     411           0 :         log->disableFlush();
     412           0 :     return os;
     413             : }
     414           0 : std::ostream& enableFlush( std::ostream& os )
     415             : {
     416           0 :     Log* log = dynamic_cast<Log*>(&os);
     417           0 :     if( log )
     418           0 :         log->enableFlush();
     419           0 :     return os;
     420             : }
     421           0 : std::ostream& forceFlush( std::ostream& os )
     422             : {
     423           0 :     Log* log = dynamic_cast<Log*>(&os);
     424           0 :     if( log )
     425           0 :         log->forceFlush();
     426           0 :     return os;
     427             : }
     428             : 
     429           0 : std::ostream& disableHeader( std::ostream& os )
     430             : {
     431           0 :     Log* log = dynamic_cast<Log*>(&os);
     432           0 :     if( log )
     433           0 :         log->disableHeader();
     434           0 :     return os;
     435             : }
     436           0 : std::ostream& enableHeader( std::ostream& os )
     437             : {
     438           0 :     Log* log = dynamic_cast<Log*>(&os);
     439           0 :     if( log )
     440           0 :         log->enableHeader();
     441           0 :     return os;
     442             : }
     443             : 
     444          90 : }

Generated by: LCOV version 1.10