@ -16,7 +16,6 @@
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
*/
# pragma once
# pragma once
# include <ctime>
# include <ctime>
@ -39,13 +38,13 @@ private:
static uint m_prevMsgCount ;
static uint m_prevMsgCount ;
static uint m_repeatThreshold ;
static uint m_repeatThreshold ;
static void getTimeStamp ( std : : string & s ) ;
static void getTimeStamp ( std : : string & s ) ;
template < typename . . . Args >
template < typename . . . Args >
static void formatLogMessage ( std : : string & output , LOG_SEVERITY severity , const std : : string & f , Args . . . args )
static void formatLogMessage ( std : : string & output , LOG_SEVERITY severity , const std : : string & f , Args . . . args )
{
{
assert ( severity ! = LOG_NONE ) ;
assert ( severity ! = LOG_NONE ) ;
std : : string severityStr ( " " ) ;
std : : string severityStr ( " " ) ;
switch ( severity )
switch ( severity )
{
{
@ -58,7 +57,7 @@ private:
case LOG_FATAL :
case LOG_FATAL :
severityStr . assign ( " FATAL " ) ;
severityStr . assign ( " FATAL " ) ;
break ;
break ;
case LOG_INFO :
case LOG_INFO :
severityStr . assign ( " INFO " ) ;
severityStr . assign ( " INFO " ) ;
break ;
break ;
case LOG_WARNING :
case LOG_WARNING :
@ -74,84 +73,113 @@ private:
std : : string f2 ( " [%s] " ) ;
std : : string f2 ( " [%s] " ) ;
f2 . append ( f ) ;
f2 . append ( f ) ;
CStringUtils : : string_format_in_place ( output , f2 , severityStr . c_str ( ) , args . . . ) ;
CStringUtils : : string_format_in_place ( output , f2 , severityStr . c_str ( ) , args . . . ) ;
boost : : trim_if ( output , [ ] ( char c ) { return c = = ' \n ' | | c = = ' \r ' | | c = = ' ' | | c = = ' \t ' ; } ) ;
boost : : trim_if ( output , [ ] ( char c )
{ return c = = ' \n ' | | c = = ' \r ' | | c = = ' ' | | c = = ' \t ' ; } ) ;
output . push_back ( ' \n ' ) ;
output . push_back ( ' \n ' ) ;
}
}
public :
public :
static void addTarget ( CLogTarget * target ) ;
static void addTarget ( CLogTarget * target ) ;
static void finalise ( ) ;
static void finalise ( ) ;
static uint & getRepeatThreshold ( ) ;
static uint & getRepeatThreshold ( ) ;
template < typename . . . Args > static void logTrace ( const std : : string & f , Args . . . args )
template < typename . . . Args >
static void logTrace ( const std : : string & f , Args . . . args )
{
{
log ( LOG_TRACE , f , args . . . ) ;
log ( LOG_TRACE , f , args . . . ) ;
}
}
template < typename . . . Args > static void logDebug ( const std : : string & f , Args . . . args )
template < typename . . . Args >
static void logDebug ( const std : : string & f , Args . . . args )
{
{
log ( LOG_DEBUG , f , args . . . ) ;
log ( LOG_DEBUG , f , args . . . ) ;
}
}
template < typename . . . Args > static void logInfo ( const std : : string & f , Args . . . args )
template < typename . . . Args >
static void logInfo ( const std : : string & f , Args . . . args )
{
{
log ( LOG_INFO , f , args . . . ) ;
log ( LOG_INFO , f , args . . . ) ;
}
}
template < typename . . . Args > static void logWarning ( const std : : string & f , Args . . . args )
template < typename . . . Args >
static void logWarning ( const std : : string & f , Args . . . args )
{
{
log ( LOG_WARNING , f , args . . . ) ;
log ( LOG_WARNING , f , args . . . ) ;
}
}
template < typename . . . Args > static void logError ( const std : : string & f , Args . . . args )
template < typename . . . Args >
static void logError ( const std : : string & f , Args . . . args )
{
{
log ( LOG_ERROR , f , args . . . ) ;
log ( LOG_ERROR , f , args . . . ) ;
}
}
template < typename . . . Args > static void logFatal ( const std : : string & f , Args . . . args )
template < typename . . . Args >
static void logFatal ( const std : : string & f , Args . . . args )
{
{
log ( LOG_FATAL , f , args . . . ) ;
log ( LOG_FATAL , f , args . . . ) ;
}
}
template < typename . . . Args > static void log ( LOG_SEVERITY severity , const std : : string & f , Args . . . args )
template < typename . . . Args >
static void log ( LOG_SEVERITY severity , const std : : string & f , Args . . . args )
{
{
// Protect against concurrent access to log targets
std : : lock_guard lockTarget ( m_targetsMutex ) ;
std : : lock_guard lockTarget ( m_targetsMutex ) ;
if ( m_targets . empty ( ) )
if ( m_targets . empty ( ) )
return ;
return ;
// Format the message with the given arguments
std : : string msg ;
std : : string msg ;
formatLogMessage ( msg , severity , f , args . . . ) ;
formatLogMessage ( msg , severity , f , args . . . ) ;
bool repeatedMsg = ( msg . compare ( m_prevMsg ) = = 0 ) ;
bool repeatedMsg = ( msg = = m_prevMsg ) ;
if ( repeatedMsg & & m_repeatThreshold > 0U ) {
// Handle repeated messages
if ( repeatedMsg & & m_repeatThreshold > 0U ) {
m_prevMsgCount + + ;
m_prevMsgCount + + ;
if ( m_prevMsgCount > = m_repeatThreshold )
if ( m_prevMsgCount > = m_repeatThreshold )
{
// If threshold reached, skip logging this duplicate
return ;
return ;
}
}
}
m_prevMsg . assign ( msg ) ;
if ( m_prevMsgCount > = m_repeatThreshold & & ! repeatedMsg & & m_repeatThreshold > 0U ) {
// If we are leaving a repetition sequence, log a summary first
formatLogMessage ( msg , severity , " Previous message repeated %d times " , m_prevMsgCount - m_repeatThreshold + 1 ) ;
if ( ! repeatedMsg & & m_repeatThreshold > 0U & & m_prevMsgCount > = m_repeatThreshold ) {
m_prevMsg . clear ( ) ;
std : : string summary ;
}
formatLogMessage ( summary , severity ,
" Previous message repeated %d times " ,
std : : string timestamp ;
m_prevMsgCount - m_repeatThreshold + 1 ) ;
getTimeStamp ( timestamp ) ;
std : : string msgts ;
std : : string ts ;
CStringUtils : : string_format_in_place ( msgts , " [%s] %s " , timestamp . c_str ( ) , msg . c_str ( ) ) ;
getTimeStamp ( ts ) ;
for ( auto target : m_targets ) {
std : : string summaryLine ;
if ( severity > = target - > getLevel ( ) ) {
CStringUtils : : string_format_in_place ( summaryLine , " [%s] %s " , ts . c_str ( ) , summary . c_str ( ) ) ;
target - > printLog ( msgts ) ;
for ( auto target : m_targets )
{
if ( severity > = target - > getLevel ( ) )
target - > printLog ( summaryLine ) ;
}
}
}
if ( m_prevMsgCount ! = 0 & & ! repeatedMsg ) {
// Reset repetition counter after summary
m_prevMsgCount = 0 ;
m_prevMsgCount = 0 ;
log ( severity , f , args . . . ) ;
}
}
// Always log the current message
std : : string ts ;
getTimeStamp ( ts ) ;
std : : string msgLine ;
CStringUtils : : string_format_in_place ( msgLine , " [%s] %s " , ts . c_str ( ) , msg . c_str ( ) ) ;
for ( auto target : m_targets ) {
if ( severity > = target - > getLevel ( ) )
target - > printLog ( msgLine ) ;
}
// Save current message for repetition detection
m_prevMsg = msg ;
}
}
} ;
} ;