// 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);
            }
        }
    }
}
Esempio n. 2
0
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
}