diff options
author | Tycho <work.tycho+git@gmail.com> | 2014-08-10 20:44:49 +0200 |
---|---|---|
committer | Tycho <work.tycho+git@gmail.com> | 2014-08-10 20:44:49 +0200 |
commit | bf0050e066af60b5f4060b298118d74cf84dc299 (patch) | |
tree | cf2f9afe5cc8e530a005236e270596d66d119c38 | |
parent | First Implementatation of new Loggin framework (diff) | |
download | cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.tar cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.tar.gz cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.tar.bz2 cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.tar.lz cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.tar.xz cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.tar.zst cuberite-bf0050e066af60b5f4060b298118d74cf84dc299.zip |
-rw-r--r-- | src/Listeners.cpp | 236 | ||||
-rw-r--r-- | src/Listeners.h | 21 | ||||
-rw-r--r-- | src/LogDispacher.cpp | 115 | ||||
-rw-r--r-- | src/LogDispacher.h | 85 |
4 files changed, 457 insertions, 0 deletions
diff --git a/src/Listeners.cpp b/src/Listeners.cpp new file mode 100644 index 000000000..384dcaf91 --- /dev/null +++ b/src/Listeners.cpp @@ -0,0 +1,236 @@ + +#include "Globals.h" + +#include "Listeners.h" + +#if defined(_WIN32) + #include <io.h> // Needed for _isatty(), not available on Linux +#elif defined(__linux) && !defined(ANDROID_NDK) + #include <unistd.h> // Needed for isatty() on Linux +#elif defined(ANDROID_NDK) + #include <android/log.h> +#endif + + +namespace Logger +{ + + #if defined(_WIN32) || (defined (__linux) && !defined(ANDROID_NDK)) + class cColouredConsoleListener + : public cLoggerListener + { + + virtual void SetLogColour(eLogLevel a_LogLevel) = 0; + virtual void SetDefaultLogColour() = 0; + + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + SetLogColour(a_LogLevel); + puts(a_Message.c_str()); + SetDefaultLogColour(); + } + }; + #endif + + #ifdef _WIN32 + class cWindowsConsoleListener + : public cColouredConsoleListener + { + public: + cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib) : + m_Console(a_Console), + m_DefaultConsoleAttrib(a_DefaultConsoleAttrib) + { + } + + #ifdef DEBUG + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + cColouredConsoleListener::Log(a_Message, a_LogLevel); + // In a Windows Debug build, output the log to debug console as well: + OutputDebugStringA(a_Message.c_str()); + } + #endif // _WIN32 + + + virtual void SetLogColour(eLogLevel a_LogLevel) override + { + // by default, gray on black + WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + switch (a_LogLevel) + { + case llRegular: + // Gray on black + Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + break; + case llInfo: + // Yellow on black + Attrib = FOREGROUND_GREEN | ; + break; + case llWarning: + // Red on black + Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case llError: + // Black on red + Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY; + break; + } + SetConsoleTextAttribute(m_Console, Attrib); + } + virtual void SetDefaultLogColour() override + { + SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib); + } + private: + HANDLE m_Console; + WORD m_DefaultConsoleAttrib; + }; + #elif defined (__linux) && !defined(ANDROID_NDK) + class cLinuxConsoleListener + : public cColouredConsoleListener + { + public: + virtual void SetLogColour(eLogLevel a_LogLevel) override + { + switch (a_LogLevel) + { + case llRegular: + // Whatever the console default is + printf("\x1b[0m"); + break; + case llInfo: + // Yellow on black + printf("\x1b[33;1m"); + break; + case llWarning: + // Red on black + printf("\x1b[31;1m"); + break; + case llError: + // Yellow on red + printf("\x1b[1;33;41;1m"); + break; + } + } + virtual void SetDefaultLogColour() override + { + // Whatever the console default is + printf("\x1b[0m"); + } + }; + #elif defined(ANDROID_NDK) + class cAndroidConsoleListener + : public cLoggerListener + { + public: + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + android_LogPriority AndroidLogLevel; + switch (a_LogLevel) + { + case llRegular: + AndroidLogLevel = ANDROID_LOG_VERBOSE; + break; + case llInfo: + AndroidLogLevel = ANDROID_LOG_INFO; + break; + case llWarning: + AndroidLogLevel = ANDROID_LOG_WARNING; + break; + case llError: + AndroidLogLevel = ANDROID_LOG_ERROR; + break; + } + __android_log_print(AndroidLogLevel, "MCServer", "%s", a_Message.c_str()); + } + }; + #endif + + class cVanillaCPPConsoleListener + : public cLoggerListener + { + public: + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override + { + AString LogLevelString; + switch (a_LogLevel) + { + case llRegular: + LogLevelString = "Log"; + break; + case llInfo: + LogLevelString = "Info"; + break; + case llWarning: + LogLevelString = "Warning"; + break; + case llError: + LogLevelString = "Error"; + break; + } + printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + } + }; + + + + cLoggerListener * MakeConsoleListener() + { + #ifdef _WIN32 + // See whether we are writing to a console the default console attrib: + bool ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); + if (ShouldColorOutput) + { + CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE Console = getStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(Console, &sbi); + WORD DefaultConsoleAttrib = sbi.wAttributes; + return new cWindowsConsoleListener(Console, DefaultConsoleAttrib); + } else { + return new cVanillaCPPConsoleListener(); + } + + #elif defined (__linux) && !defined(ANDROID_NDK) + // TODO: lookup terminal in terminfo + if (isatty(fileno(stdout))) + { + return new cLinuxConsoleListener(); + } else { + return new cVanillaCPPConsoleListener(); + } + #else + return new cVanillaCPPConsoleListener(); + #endif + } + + cFileListener::cFileListener() + { + cFile::CreateFolder(FILE_IO_PREFIX + AString("logs")); + AString FileName; + FileName = Printf("%s%sLOG_%d.txt", FILE_IO_PREFIX, "logs/", (int)time(NULL)); + m_File.Open(FileName, cFile::fmAppend); + } + + void cFileListener::Log(AString a_Message, eLogLevel a_LogLevel) + { + AString LogLevelString; + switch (a_LogLevel) + { + case llRegular: + LogLevelString = "Log"; + break; + case llInfo: + LogLevelString = "Info"; + break; + case llWarning: + LogLevelString = "Warning"; + break; + case llError: + LogLevelString = "Error"; + break; + } + m_File.Printf("%s: %s", LogLevelString.c_str(), a_Message.c_str()); + } + +} diff --git a/src/Listeners.h b/src/Listeners.h new file mode 100644 index 000000000..bc29d0c06 --- /dev/null +++ b/src/Listeners.h @@ -0,0 +1,21 @@ + +#include "LogDispacher.h" + +namespace Logger +{ + + class cFileListener + : public cLoggerListener + { + public: + + cFileListener(); + cFileListener(AString a_Filename); + + virtual void Log(AString a_Message, eLogLevel a_LogLevel) override; + private: + cFile m_File; + }; + + cLoggerListener * MakeConsoleListener(); +} diff --git a/src/LogDispacher.cpp b/src/LogDispacher.cpp new file mode 100644 index 000000000..337d718e6 --- /dev/null +++ b/src/LogDispacher.cpp @@ -0,0 +1,115 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Log.h" +#include "OSSupport/IsThread.h" + + + +namespace Logger +{ + + cLogDispacher & GetInstance(void) + { + static cLogDispacher Instance; + return Instance; + } + + void InitiateMultithreading() + { + GetInstance(); + } + + void cLogDispacher::LogSimple(AString a_Message, eLogLevel a_LogLevel) + { + time_t rawtime; + time ( &rawtime); + + struct tm* timeinfo; + #ifdef _MSC_VER + struct tm timeinforeal; + timeinfo = &timeinforeal; + localtime_s(timeinfo, &rawtime); + #else + timeinfo = localtime( &rawtime); + #endif + + AString Line; + #ifdef _DEBUG + Printf(Line, "[%04lx|%02d:%02d:%02d] %s\n", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + #else + Printf(Line, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, a_Message.c_str()); + #endif + + + cCSLock Lock(m_CriticalSection); + for(size_t i = 0; i < m_LogListeners.size(); i++) + { + m_LogListeners[i]->Log(a_Message, a_LogLevel); + } + } + + + + + + void cLogDispacher::Log(const char * a_Format, eLogLevel a_LogLevel, va_list a_ArgList) + { + AString Message; + AppendVPrintf(Message, a_Format, a_ArgList); + LogSimple(Message, a_LogLevel); + } + + void cLogDispacher::AttachListener(Logger::cLoggerListener * a_Listener) + { + cCSLock Lock(m_CriticalSection); + m_LogListeners.push_back(a_Listener); + } + + void cLogDispacher::DetachListener(Logger::cLoggerListener * a_Listener) + { + cCSLock Lock(m_CriticalSection); + m_LogListeners.erase(std::remove(m_LogListeners.begin(), m_LogListeners.end(), a_Listener)); + } +}; + + + +//////////////////////////////////////////////////////////////////////////////// +// Global functions + +void LOG(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log(a_Format, Logger::llRegular, argList); + va_end(argList); +} + +void LOGINFO(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log( a_Format, Logger::llInfo, argList); + va_end(argList); +} + +void LOGWARN(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log( a_Format, Logger::llWarning, argList); + va_end(argList); +} + +void LOGERROR(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + Logger::GetInstance().Log( a_Format, Logger::llError, argList); + va_end(argList); +} + + + + diff --git a/src/LogDispacher.h b/src/LogDispacher.h new file mode 100644 index 000000000..31b3b3fc1 --- /dev/null +++ b/src/LogDispacher.h @@ -0,0 +1,85 @@ + +#pragma once + + + +class cLog; + + +namespace Logger +{ + + enum eLogLevel + { + llRegular, + llInfo, + llWarning, + llError, + }; + + class cLogDispacher; + + // Must be called before calling GetInstance in a multithreaded context + void InitiateMultithreading(); + + cLogDispacher & GetInstance(void); + + class cLoggerListener + { + public: + virtual void Log(AString a_Message, eLogLevel a_LogLevel) = 0; + + virtual ~cLoggerListener(){} + }; + + class cLogDispacher + { + public: + + void Log (const char * a_Format, Logger::eLogLevel a_LogLevel, va_list a_ArgList) FORMATSTRING(2, 0); + + /** Logs the simple text message at the specified log level. */ + void LogSimple(AString a_Message, Logger::eLogLevel a_LogLevel = Logger::llRegular); + + void AttachListener(Logger::cLoggerListener * a_Listener); + void DetachListener(Logger::cLoggerListener * a_Listener); + + private: + + cCriticalSection m_CriticalSection; + std::vector<Logger::cLoggerListener *> m_LogListeners; + + }; + +} + + + + + + +extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2); +extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2); +extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2); +extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2); + + + + + +// In debug builds, translate LOGD to LOG, otherwise leave it out altogether: +#ifdef _DEBUG + #define LOGD LOG +#else + #define LOGD(...) +#endif // _DEBUG + + + + + +#define LOGWARNING LOGWARN + + + + |