Log.h#

This file contains Logging functionality.

Includes#

  • PVRCore/Errors.h

  • assert.h

  • cstdarg

  • cstdio

  • cstdlib

  • cstring

  • string (CompileTimeHash.h)

Included By#

Namespaces#

Classes#

Enums#

Functions#

Defines#

Variables#

Source Code#

#ifndef _PVR_LOG_H
#define _PVR_LOG_H
#pragma once

#include <string>
#include <assert.h>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <cstdio>
#include "PVRCore/Errors.h"

#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#define vsnprintf _vsnprintf
#endif

#if defined(__linux__)
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <signal.h>
#endif

#if defined(__ANDROID__)
#include <android/log.h>
static const android_LogPriority messageTypes[] = {
    ANDROID_LOG_VERBOSE,
    ANDROID_LOG_DEBUG,
    ANDROID_LOG_INFO,
    ANDROID_LOG_WARN,
    ANDROID_LOG_ERROR,
    ANDROID_LOG_FATAL,
};
#elif defined(__QNXNTO__)
#include <sys/slog.h>
static const int messageTypes[] = { _SLOG_DEBUG1, _SLOG_DEBUG1, _SLOG_INFO, _SLOG_WARNING, _SLOG_ERROR, _SLOG_CRITICAL };
#else
static const char* messageTypes[] = { "VERBOSE: ", "DEBUG: ", "INFORMATION: ", "WARNING: ", "ERROR: ", "CRITICAL: ", "PERFORMANCE: " };
#endif

#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || defined(__ANDROID__)
#define PVR_PLATFORM_IS_MOBILE 1
#else
#define PVR_PLATFORM_IS_DESKTOP 1
#endif

enum class LogLevel
{
    Verbose = 0,
    Debug = 1,
    Information = 2,
    Warning = 3,
    Error = 4,
    Critical = 5,
    Performance = 6,
    None = 100,
};

class ILogger
{
public:
    ILogger() : _verbosityThreshold(LogLevel::Information) {}
    void setVerbosity(const LogLevel minimumLevelToOutput) { _verbosityThreshold = minimumLevelToOutput; }
    LogLevel getVerbosity() const { return _verbosityThreshold; }

    void operator()(LogLevel severity, const char* const formatString, ...) const
    {
        if (severity < _verbosityThreshold) { return; }
        va_list argumentList;
        va_start(argumentList, formatString);
        vaOutput(severity, formatString, argumentList);
        va_end(argumentList);
    }

    void operator()(const char* const formatString, ...) const
    {
        if (LogLevel::Error < _verbosityThreshold) { return; }
        va_list argumentList;
        va_start(argumentList, formatString);
        vaOutput(LogLevel::Error, formatString, argumentList);
        va_end(argumentList);
    }

    void output(LogLevel severity, const char* formatString, ...) const
    {
        if (severity < _verbosityThreshold) { return; }
        va_list argumentList;
        va_start(argumentList, formatString);
        vaOutput(severity, formatString, argumentList);
        va_end(argumentList);
    }
    void output(const char* formatString, ...) const
    {
        if (LogLevel::Error < _verbosityThreshold) { return; }
        va_list argumentList;
        va_start(argumentList, formatString);
        vaOutput(LogLevel::Error, formatString, argumentList);
        va_end(argumentList);
    }

    virtual void vaOutput(LogLevel severity, const char* formatString, va_list argumentList) const = 0;

private:
    LogLevel _verbosityThreshold;
};

class Logger : public ILogger
{
    FILE* file;

public:
    Logger()
    {
#if defined(PVR_PLATFORM_IS_DESKTOP) && !defined(TARGET_OS_MAC)
        file = fopen("log.txt", "w");
#endif
    }
    virtual ~Logger() { close(); }

    void close()
    {
        if (file)
        {
            fclose(file);
            file = 0;
        }
    }

    virtual void vaOutput(LogLevel severity, const char* formatString, va_list argumentList) const
    {
#ifndef DEBUG
        if (severity > LogLevel::Debug)
#endif
        {
#if defined(__ANDROID__)
            // Note: There may be issues displaying 64bits values with this function
            // Note: This function will truncate long messages
            __android_log_vprint(messageTypes[static_cast<uint32_t>(severity)], "com.powervr.Example", formatString, argumentList);
#elif defined(__QNXNTO__)
            vslogf(1, messageTypes[static_cast<uint32_t>(severity)], formatString, argumentList);
#else // Not android Not QNX
            static char buffer[4096];
            va_list tempList;
            memset(buffer, 0, sizeof(buffer));
#if (defined _MSC_VER) // Pre VS2013
            tempList = argumentList;
#else
            va_copy(tempList, argumentList);
#endif
            vsnprintf(buffer, 4095, formatString, argumentList);
            buffer[4095] = 0;

#if defined(_WIN32)
            if (isDebuggerPresent())
            {
                OutputDebugString(messageTypes[static_cast<int>(severity)]);
                OutputDebugString(buffer);
                OutputDebugString("\n");
            }
#endif
            vprintf(formatString, tempList);
            printf("\n");

#if defined(PVR_PLATFORM_IS_DESKTOP) && !defined(TARGET_OS_MAC)
            {
                if (file)
                {
                    fwrite(messageTypes[static_cast<int>(severity)], 1, strlen(messageTypes[static_cast<int>(severity)]), file);
                    fwrite(buffer, 1, strlen(buffer), file);
                    fwrite("\n", 1, 1, file);
                    fflush(file);
                }
            }
#endif
#endif
        }
    }
};

namespace impl {
static Logger originalDefaultLogger;
}
inline Logger& originalDefaultLogger() { return impl::originalDefaultLogger; }

inline Logger& DefaultLogger()
{
    static Logger* logger = &originalDefaultLogger();
    return *logger;
}

inline void LogClose() { DefaultLogger().close(); }

inline void Log(LogLevel severity, const char* formatString, ...)
{
    va_list argumentList;
    va_start(argumentList, formatString);
    DefaultLogger().vaOutput(severity, formatString, argumentList);
    va_end(argumentList);
}

inline void Log(const char* formatString, ...)
{
    va_list argumentList;
    va_start(argumentList, formatString);
    DefaultLogger().vaOutput(LogLevel::Error, formatString, argumentList);
    va_end(argumentList);
}

// clang-format off
#define SLASH(s) /##s
#define COMMENT SLASH(/)
// clang-format on

#ifdef DEBUG
#define DebugLog(message) Log(LogLevel::Debug, message)
#else
#define DebugLog(message) void(0)
#endif

#ifdef DEBUG
#define debug_warning(condition, message) assert_warning(condition, message)
#else
#define debug_warning(condition, message) ((void)0)
#endif

inline void assert_warning(bool condition, const char* msg)
{
    if (!condition) { Log(LogLevel::Warning, msg); }
}

inline void assertion(bool condition, const char* msg)
{
    if (!condition)
    {
        Log(LogLevel::Critical, "ASSERTION FAILED: %s", msg);
        debuggerBreak();
        assert(0);
    }
}

inline void assertion(bool condition) { assertion(condition, ""); }

#ifdef DEBUG
#define debug_assertion(condition, message) assertion(condition, message)
#else
#define debug_assertion(condition, message) ((void)0)
#endif
inline void assertion(bool condition, const std::string& message)
{
    if (!condition)
    {
        Log(LogLevel::Critical, ("ASSERTION FAILED: " + message).c_str());
        debuggerBreak();
        assert(0);
    }
}

#endif