//---------------------------------------------------------------------------- // EgalTech 2013-2023 //---------------------------------------------------------------------------- // File : EgtLogger.h Data : 15.12.23 Versione : 2.5l3 // Contenuto : Classi per logger. // // // // Modifiche : 06.12.13 DS Creazione modulo. // 15.12.23 DS Ora default è thread safe. // //---------------------------------------------------------------------------- #pragma once #include "/EgtDev/Include/EgtILogger.h" #include #include #define NOMINMAX #include #include //---------------------------------------------------------------------------- namespace egtlogger { //---------------------------------------------------------------------------- class IntraProcessLock { public : IntraProcessLock( bool bThreadSafe) : m_bThreadSafe( bThreadSafe) { if ( m_bThreadSafe) InitializeCriticalSection( &m_cs) ; } ~IntraProcessLock( void) { if ( m_bThreadSafe) DeleteCriticalSection( &m_cs) ; } void Lock( void) { if ( m_bThreadSafe) EnterCriticalSection( &m_cs) ; } void Unlock( void) { if ( m_bThreadSafe) LeaveCriticalSection( &m_cs) ; } private : bool m_bThreadSafe ; CRITICAL_SECTION m_cs ; } ; //---------------------------------------------------------------------------- class Logger : public ILogger { private : struct StreamInfo { std::ostream* pStream ; bool bOwned ; LogLevel nLevel ; StreamInfo( std::ostream* pStream, bool bOwned, LogLevel nLevel) { this->pStream = pStream ; this->bOwned = bOwned ; this->nLevel = nLevel ; } } ; public : Logger( LogLevel nLevel, const char* szName, bool bThreadSafe = true, int nLoggableItems = LI_DATETIME | LI_LOGGERNAME | LI_LOGGERLEVEL | LI_FUNCTION | LI_LINENUMBER) : m_nLevel( nLevel), m_name( szName), m_threadProtect( bThreadSafe), m_loggableItem( nLoggableItems) {} ~Logger( void) { ClearOutputStreams() ; } void AddOutputStream( std::ostream& os, bool bOwn, LogLevel nLevel) { AddOutputStream( &os, bOwn, nLevel) ; } void AddOutputStream( std::ostream& os, bool bOwn) { AddOutputStream( os, bOwn, m_nLevel) ; } void AddOutputStream( std::ostream* os, bool bOwn) { AddOutputStream( os, bOwn, m_nLevel) ; } void AddOutputStream( std::ostream* os, bool bOwn, LogLevel nLevel) { StreamInfo si( os, bOwn, nLevel) ; m_outputStreams.push_back( si) ; } void ClearOutputStreams( void) { for ( auto iter = m_outputStreams.cbegin() ; iter < m_outputStreams.cend() ; ++iter) { if ( iter->bOwned) delete iter->pStream ; } m_outputStreams.clear() ; } void Log( LogLevel nLevel, const char* szFile, int nLine, const char* szFunc, const char* szText) { Log( nLevel, m_loggableItem, szFile, nLine, szFunc, szText) ; } void Log( LogLevel nLevel, int nItem, const char* szFile, int nLine, const char* szFunc, const char* szText) { m_threadProtect.Lock() ; for ( auto iter = m_outputStreams.cbegin() ; iter < m_outputStreams.cend() ; ++iter) { if ( nLevel < iter->nLevel) continue ; bool bWritten = false ; std::ostream* pStream = iter->pStream ; if ( pStream == nullptr) continue ; if ( nItem & LI_DATETIME) bWritten = write_datetime( bWritten, pStream) ; if ( nItem & LI_THREADID) bWritten = write( GetCurrentThreadId(), bWritten, pStream) ; if ( nItem & LI_LOGGERNAME) bWritten = write( m_name.c_str(), bWritten, pStream) ; if ( nItem & LI_LOGGERLEVEL) { char strLevel[4] ; LogLevelToString( nLevel, strLevel) ; bWritten = write( strLevel, bWritten, pStream) ; } if ( nItem & LI_FUNCTION) bWritten = write( szFunc, bWritten, pStream) ; if ( nItem & LI_FILENAME) bWritten = write( szFile, bWritten, pStream) ; if ( nItem & LI_LINENUMBER) bWritten = write( nLine, bWritten, pStream) ; bWritten = write( szText, bWritten, pStream) ; if ( bWritten) { (*pStream) << std::endl ; pStream->flush() ; } } m_threadProtect.Unlock() ; } private : int m_loggableItem ; LogLevel m_nLevel ; std::string m_name ; std::vector m_outputStreams ; IntraProcessLock m_threadProtect ; template bool write( T data, bool bWritten, std::ostream* strm) { if ( bWritten) (*strm) << " " ; (*strm) << data ; return true ; } bool write_datetime( bool bWritten, std::ostream* strm) { if ( bWritten) (*strm) << " " ; // seconds elapsed since midnight, January 1, 1970 time_t _time ; time( &_time) ; // structured time tm _tm ; if ( localtime_s( &_tm, &_time) != 0) (*strm) << "time/date error" ; // string format const int DT_LEN = 24 ; char szDateTime[DT_LEN] = { '\0'} ; strftime( szDateTime, DT_LEN, "%Y/%m/%d %H:%M:%S", &_tm) ; // output (*strm) << szDateTime ; return true ; } void LogLevelToString( LogLevel nLevel, char* strLevel) { switch ( nLevel) { case LL_ERROR : strcpy_s( strLevel, 4, "ERR") ; break ; case LL_WARN : strcpy_s( strLevel, 4, "WRN") ; break ; case LL_INFO : strcpy_s( strLevel, 4, "INF") ; break ; case LL_DEBUG : strcpy_s( strLevel, 4, "DBG") ; break ; } } } ; }