// Generate a composite log message - then finally send to handler to write and/or display void _Log(enum LogType type, const char* fmt, ...) { // check to see if logging of the level is enabled, or if s_LogConsole is specified // if not, don't process it. int logLevel = SG_GET_INT(OptionLogLevel); if (((type - logERROR) > logLevel && s_LogConsole == false)) { return; } // Define buffer to store maximum current log message. // Different destinations will receive a subset of this string. // On Win32 the entire string is passed to OutputDebugString() char fullString[PS_LOG_MAX_LENGTH] = ""; int nLen = 0; int nSize; bool truncated = false; char* pLogString; // String to print to logfile char* pConsole; // String to print to console doesn't include debug information char* pRaw; // Raw string passed in without any additional decoration if (truncated == false) { // Prepend "PerfStudio: " for windows OutputDebugString() messages nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "PerfStudio: "); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } pLogString = &fullString[nLen]; // logfile message doesn't include above WIN32 section #if (defined PS_LOG_DEBUG) && (defined _DEBUG) if (truncated == false) { // In debug builds, include the __FILE__, __LINE__ and __FUNCTION__ information nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "%s(%d) : %s(): ", s_LogFile, s_LogLine, s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } #endif // Prepend accurate timestamp if (truncated == false) { gtASCIIString time = GetMicroTimeStr(); time = time.substr(12); nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "%-14s: ", time.asCharArray()); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } pConsole = &fullString[nLen]; // String to print to console starts here if (truncated == false) { // Add the message type string switch (type) { case logERROR: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Error: "); break; case logWARNING: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Warning: "); break; case logMESSAGE: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Message: "); break; case logTRACE: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Trace: "); break; case logASSERT: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Assert: "); break; case logDEBUG: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Debug: "); break; case logRAW: // Skip nSize = 0; break; default: nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "Unknown: "); break; } if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } // Add the module identifier if (s_LogModule && (truncated == false)) { nSize = _snprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, "PID: %10u TID: %10u %-14s: ", osGetCurrentProcessId(), osGetCurrentThreadId(), s_LogModule); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } if (truncated == false) { if (SG_GET_INT(OptionLogLevel) >= logTRACE - logERROR) { // Add the indent for (int i = 0; (i < logIndent) && (nLen < PS_LOG_MAX_LENGTH - 1); i++, nLen++) { fullString[nLen] = ' '; } fullString[nLen] = 0; // Ensure string in buffer remains null terminated truncated = (nLen == PS_LOG_MAX_LENGTH - 1); } } pRaw = &fullString[nLen]; // Raw undecorated string starts here // Add the actual Log Message if (truncated == false) { va_list arg_ptr; va_start(arg_ptr, fmt); nSize = vsnprintf_s(&fullString[nLen], PS_LOG_MAX_LENGTH - nLen, _TRUNCATE, fmt, arg_ptr); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } va_end(arg_ptr); } // Check if message has been truncated and clean up accordingly if (truncated == true) { // Truncation occurred - change end of line to reflect this char truncationString[] = " ... \n"; sprintf_s(&fullString[PS_LOG_MAX_LENGTH - sizeof(truncationString)], sizeof(truncationString), "%s", truncationString); } // Message Constructed. Print to Log, Console, and OutputDebugString as necessary if (type == logRAW) { if (s_LogConsole) { // Send string to console printf("%s", pRaw); } _logWrite(pRaw); } else { if (s_LogConsole) { // Console messages are always printed in console and in log file // regardless of logLEVEL printf("%s", pConsole); _logWrite(pLogString); OutputDebugString(fullString); } else { // not a console message - filter based on log level if ((type - logERROR) <= SG_GET_INT(OptionLogLevel)) { if (type == logTRACE) { // Trace messages also go to the console printf("%s", pConsole); } _logWrite(pLogString); OutputDebugString(fullString); } } } }
void Log(enum LogType type, const char* fmt, ...) { #ifdef DISABLE_LOG SP_UNREFERENCED_PARAMETER(type); SP_UNREFERENCED_PARAMETER(fmt); return; #else AMDTScopeLock s(&sMutex); bool s_LogConsole = false; const char* s_LogFunction = __FUNCTION__; va_list arg_ptr; va_start(arg_ptr, fmt); // check to see if logging of the level is enabled, or if s_LogConsole is specified // if not, don't process it. if (type > OptionLogLevel) { va_end(arg_ptr); return; } // Define buffer to store maximum current log message. // Different destinations will receive a subset of this string. // On Win32 the entire string is passed to OutputDebugString() char fullString[SP_LOG_MAX_LENGTH] = "\0"; int nLen = 0; int nSize; bool truncated = false; char* pLogString; // String to print to logfile char* pConsole; // String to print to console doesn't include debug information char* pRaw; // Raw string passed in without any additional decoration switch (type) { case traceENTER: if (truncated == false) { nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Enter: %s() ", s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } break; case traceEXIT: logIndent -= SP_LOG_INDENT_SIZE; if (logIndent < 0) { logIndent = 0; } truncated = (nLen == SP_LOG_MAX_LENGTH); if (truncated == false) { nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Exit : %s() ", s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } break; default: break; } #ifdef WIN32 if (truncated == false) { // Prepend "CodeXL GPU Profiler: " for windows OutputDebugString() messages nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "CodeXL GPU Profiler: "); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } #endif pLogString = &fullString[nLen]; // logfile message doesn't include above WIN32 section #if (defined SP_LOG_DEBUG) && (defined _DEBUG) char* s_LogFile = __FILE__; int s_LogLine = __LINE__; if (truncated == false) { // In debug builds, include the __FILE__, __LINE__ and __FUNCTION__ information nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "%s(%d) : %s(): ", s_LogFile, s_LogLine, s_LogFunction); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } #endif //// Prepend accurate timestamp //if ( truncated == false ) //{ // std::string time = StringUtils::GetTimeString(); // nSize = _snprintf_s( &fullString[nLen], SP_LOG_MAX_LENGTH - nLen, _TRUNCATE, "%-14s: ", time.c_str() ); // if ( ( truncated = ( nSize == -1 ) ) == false ) // { // nLen += nSize; // } //} pConsole = &fullString[nLen]; // String to print to console starts here if (truncated == false) { // Add the message type string switch (type) { case logERROR: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Error: "); break; case logWARNING: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Warning: "); break; case logMESSAGE: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Message: "); break; case logTRACE: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Trace: "); break; case logASSERT: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Assert: "); break; case logRAW: // Skip nSize = 0; break; case traceENTER: case traceEXIT: case traceMESSAGE: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Trace: "); break; default: nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "Unknown: "); break; } if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } // Add the module identifier if (s_LogModule && (truncated == false)) { nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "%-14s: ", s_LogModule); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } if (truncated == false) { if (OptionLogLevel >= logTRACE - logERROR) { // Add the indent for (int i = 0; (i < logIndent) && (nLen < SP_LOG_MAX_LENGTH); i++, nLen++) { fullString[nLen] = ' '; } truncated = (nLen == SP_LOG_MAX_LENGTH); } } pRaw = &fullString[nLen]; // Raw undecorated string starts here // Add the actual Log Message if (truncated == false) { nSize = SP_vsnprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, fmt, arg_ptr); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } // Check if message has been truncated and clean up accordingly if (truncated == true) { // Truncation occurred - change end of line to reflect this char truncationString[] = " ... \n"; SP_sprintf(&fullString[SP_LOG_MAX_LENGTH - sizeof(truncationString)], sizeof(truncationString), "%s", truncationString); } if (type > logTRACE) { // For trace messages - force a "\n" at the end if (truncated == false) { nSize = SP_snprintf(&fullString[nLen], SP_LOG_MAX_LENGTH - nLen, "\n"); if ((truncated = (nSize == -1)) == false) { nLen += nSize; } } } // Message Constructed. Print to Log, Console, and OutputDebugString as necessary // if (type == logRAW) { if (s_LogConsole) { // Send string to console printf("%s", pRaw); } _logWrite(pRaw); } else { if (s_LogConsole) { // Console messages are always printed in console and in log file // regardless of logLEVEL printf("%s", pConsole); _logWrite(pLogString); #ifdef WIN32 SP_TODO("revisit use of OutputDebugStringA for Unicode support") OutputDebugStringA(fullString); #endif } else { // not a console message - filter based on log level if ((type - logERROR) <= OptionLogLevel) { if (type == logTRACE) { // Trace messages also go to the console printf("%s", pConsole); } _logWrite(pLogString); #ifdef WIN32 SP_TODO("revisit use of OutputDebugStringA for Unicode support") OutputDebugStringA(fullString); #endif } } } va_end(arg_ptr); #endif }