文章目录 main.cpp Log.h Log.cpp ClassAuxMacro.h Singleton.h
main.cpp
# include "Log.h" int main ( )
{ LogInfo << "main start" ; int i = 1 ; double d = 3.14 ; LogInfo << "i = " << i << ", d = " << d; getchar ( ) ;
}
Log.h
# pragma once
# include <sstream>
# include <string>
# include <chrono>
# include "Singleton.h" template < typename T , size_t N>
inline constexpr size_t GetFileNameOffset ( const T ( & str) [ N] , size_t i = N - 1 )
{ return ( str[ i] == '/' || str[ i] == '\\' ? i + 1 : i > 0 ? GetFileNameOffset ( str, i - 1 ) : 0 ) ;
}
template < typename T >
inline constexpr size_t GetFileNameOffset ( const T ( & str) [ 1 ] )
{ return 0 ;
}
# define SRC_FILE_NAME ( FilePath) ( & FilePath[ GetFileNameOffset ( FilePath) ] ) enum class ELevel { _FATAL, _ERROR, _WARN, _INFO, _DEBUF,
} ; class LogStream {
public : LogStream ( ) ; LogStream ( const std:: string& name) ; ~ LogStream ( ) ;
public : std:: ostringstream& Process ( ELevel level, const char * fileName, int lineNum, const char * funcName) ;
private : std:: ostringstream osstream_; std:: string logName_;
} ; class Log { SINGLE_INSTANCE_CLASS ( Log) ; DEF_MEMBER_VAR_DEFAULT_VALUE ( ELevel, m_globalLogLevel, GlobalLogLevel, ELevel:: _INFO) ; DEF_MEMBER_VAR_DEFAULT_VALUE ( std:: string, m_logDir, LogDir, "./" ) ; DEF_MEMBER_VAR_DEFAULT_VALUE ( bool , m_stop, Stop, false ) ;
public : void StartAsyncLog ( ) ;
} ;
# define GLogInst Log :: GetInstance ( ) # define LogInfo if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _INFO && ! GLogInst-> GetStop ( ) ) LogStream ( ) . Process ( ELevel:: _INFO, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogWarn if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _WARN && ! GLogInst-> GetStop ( ) ) LogStream ( ) . Process ( ELevel:: _WARN, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogError if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _ERROR && ! GLogInst-> GetStop ( ) ) LogStream ( ) . Process ( ELevel:: _ERROR, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogFatal if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _FATAL && ! GLogInst-> GetStop ( ) ) LogStream ( ) . Process ( ELevel:: _FATAL, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogDebug if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _DEBUF && ! GLogInst-> GetStop ( ) ) LogStream ( ) . Process ( ELevel:: _DEBUF, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogInfoF ( logPath) if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _INFO && ! GLogInst-> GetStop ( ) ) LogStream ( logPath) . Process ( ELevel:: _INFO, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogWarnF ( logPath) if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _WARN && ! GLogInst-> GetStop ( ) ) LogStream ( logPath) . Process ( ELevel:: _WARN, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogErrorF ( logPath) if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _ERROR && ! GLogInst-> GetStop ( ) ) LogStream ( logPath) . Process ( ELevel:: _ERROR, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogFatalF ( logPath) if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _FATAL && ! GLogInst-> GetStop ( ) ) LogStream ( logPath) . Process ( ELevel:: _FATAL, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ )
# define LogDebugF ( logPath) if ( GLogInst-> GetGlobalLogLevel ( ) >= ELevel:: _DEBUF && ! GLogInst-> GetStop ( ) ) LogStream ( logPath) . Process ( ELevel:: _DEBUF, SRC_FILE_NAME ( __FILE__ ) , __LINE__ , __func__ ) struct BeginEndLog { BeginEndLog ( const char * name) : name_ ( name) { LogInfo << "begin " << name_; } ~ BeginEndLog ( ) { LogInfo << "end " << name_; } const char * name_;
} ; struct CostTimeLog { CostTimeLog ( const char * name) : name_ ( name) { start_ = std:: chrono:: system_clock:: now ( ) ; } ~ CostTimeLog ( ) { auto end = std:: chrono:: system_clock:: now ( ) ; double duration = std:: chrono:: duration_cast< std:: chrono:: milliseconds> ( end - start_) . count ( ) ; LogInfo << "call " << name_ << " cost time " << duration << "ms" ; } decltype ( std:: chrono:: system_clock:: now ( ) ) start_; const char * name_;
} ; # define ENABLE_CALL_LOG 1
# define ENABLE_CALL_COST_TIME_LOG 1 # if ENABLE_CALL_LOG
# define RECORD_FUNC_CALL_LOG BeginEndLog BeginEndLog___ ( __FUNCTION__)
# else
# define RECORD_FUNC_CALL_LOG
# endif # if ENABLE_CALL_COST_TIME_LOG
# define RECORD_FUNC_CALL_COST_TIME_LOG CostTimeLog CostTimeLog___ ( __FUNCTION__)
# else
# define RECORD_FUNC_CALL_COST_TIME_LOG
# endif
Log.cpp
# include "Log.h"
# include <fstream>
# include <iomanip>
# include "BlockingQueue.h" namespace {
std:: mutex mtx;
void SaveLogToFile ( std:: string path, std:: string content)
{ std:: unique_lock< std:: mutex> lock ( mtx) ; std:: ofstream out ( path, std:: ios:: app) ; if ( out. rdstate ( ) == std:: ofstream:: goodbit) { out << content << std:: endl; out. close ( ) ; }
}
const char * loglevelStr[ ] = { "Fatal" , "Error" , "Warn" , "Info" , "Debug" } ;
std:: thread asyncThread;
std:: unique_ptr< BlockingQueue< std:: pair< std:: string, std:: string>> > blockingQueue;
std:: function< void ( std:: string, std:: string) > logProcess; void AsyncLogProcess ( std:: string path, std:: string content)
{ blockingQueue-> Push ( { path, content } ) ;
}
std:: string GetFormatDateTime ( )
{ std:: stringstream ss; auto curTime = std:: chrono:: system_clock:: to_time_t ( std:: chrono:: system_clock:: now ( ) ) ; struct tm t; localtime_s ( & t, & curTime) ; ss << std:: put_time ( & t, "%Y-%m-%d %H:%M:%S" ) ; auto tNow = std:: chrono:: system_clock:: now ( ) ; auto tMilli = std:: chrono:: duration_cast< std:: chrono:: milliseconds> ( tNow. time_since_epoch ( ) ) ; auto tSeconds = std:: chrono:: duration_cast< std:: chrono:: seconds> ( tNow. time_since_epoch ( ) ) ; auto ms = tMilli - tSeconds; ss << "." << std:: setfill ( '0' ) << std:: setw ( 3 ) << ms. count ( ) ; return ss. str ( ) ;
}
std:: string GetTodayDate ( )
{ auto curTime = std:: chrono:: system_clock:: to_time_t ( std:: chrono:: system_clock:: now ( ) ) ; struct tm t; localtime_s ( & t, & curTime) ; std:: ostringstream os; os << std:: put_time ( & t, "%Y-%m-%d" ) << ".log" ; return os. str ( ) ;
}
} LogStream :: LogStream ( ) : logName_ ( GLogInst-> GetLogDir ( ) + GetTodayDate ( ) ) { }
LogStream :: LogStream ( const std:: string & name) : logName_ ( name) { }
LogStream :: ~ LogStream ( )
{ if ( ! logProcess) { logProcess = SaveLogToFile; } logProcess ( logName_, osstream_. str ( ) ) ;
}
std:: ostringstream& LogStream :: Process ( ELevel level, const char * fileName, int lineNum, const char * funcName)
{ osstream_ << loglevelStr[ static_cast < int > ( level) ] << ";" << GetFormatDateTime ( ) << ";" << fileName << ";" << std:: setfill ( '0' ) << std:: setw ( 4 ) << lineNum << ";" << "tid:" << std:: this_thread:: get_id ( ) << ";" ; return osstream_;
} void Log :: StartAsyncLog ( )
{ blockingQueue = std:: make_unique< BlockingQueue< std:: pair< std:: string, std:: string>> > ( ) ; blockingQueue-> SetMaxSize ( INT_MAX) ; logProcess = AsyncLogProcess; std:: thread t ( [ this ] { while ( true ) { std:: pair< std:: string, std:: string> pair; bool res = blockingQueue-> Pop ( pair) ; if ( res) SaveLogToFile ( pair. first, pair. second) ; } } ) ; t. detach ( ) ;
}
ClassAuxMacro.h
# pragma once # define DEF_MEMBER_VAR ( type, name, opName) \
public : \ type Get ## opName ( ) { return name; } \ void Set## opName ( const type& val) { name = val; } \
private : \ type name # define DEF_MEMBER_VAR_DEFAULT_VALUE ( type, name, opName, value) \
public : \ type Get ## opName ( ) { return name; } \ void Set## opName ( const type& val) { name = val; } \
private : \ type name = value # define DEF_MEMBER_VAR_READONLY ( type, name, opName, value) \
public : \ const type& Get## opName ( ) { return name; } \
private : \ const type name = value# define DEF_MEMBER_VAR_PTR ( type, name, opName) \
public : \ type* Get ## opName ( ) { return name; } \ void Set## opName ( type* val) { name = val; } \
private : \ type* name # define DEF_MEMBER_VAR_LOW_LIMIT ( type, name, opName, value) \
public : \ type Get ## opName ( ) { return name; } \ void Set## opName ( const type& val) { \ name = val; \ if ( name < value) { \ name = value; \ } \ } \
private : \ type name = value
Singleton.h
# pragma once # include "ClassAuxMacro.h" # define SINGLE_INSTANCE_CLASS ( type) \
public : \ static type* GetInstance ( ) { \ static type i; \ return & i; \ } \
private : \ type ( ) = default # define SINGLE_INSTANCE_CLASS_CUSTOM ( type) \
public : \ static type* GetInstance ( ) { \ static type i; \ return & i; \ } \
private : \ type ( )