From 174af32355677265dfdf89e347ac79b8b52f871a Mon Sep 17 00:00:00 2001 From: DankParrot Date: Tue, 28 Jul 2020 21:32:35 -0700 Subject: [PATCH] Further implement logging system --- src/Main.cpp | 11 +--- src/logging/Logger.cpp | 118 ++++++++++++++++++++++++++++++++++++++--- src/logging/Logger.h | 44 ++++++++++++--- 3 files changed, 150 insertions(+), 23 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index cdf4158..b3ff5bd 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -5,19 +5,12 @@ using namespace Feather; + int main() { ServerProperties properties("server.properties"); properties.Save(); - - // TEMP - - printf("Starting server on port %d\n", properties.serverPort.GetValue()); - - Log_Info("Starting server on port %d\n", properties.serverPort.GetValue()); - Logging::GlobalLogger.LogDirect(Logging::LOG_GENERAL, Logging::Level::INFO, "Starting server on port %d\n", properties.serverPort.GetValue() ); - - //auto server = DedicatedServer(&properties); + auto server = DedicatedServer(&properties); return 1; } diff --git a/src/logging/Logger.cpp b/src/logging/Logger.cpp index ba36c90..667185d 100644 --- a/src/logging/Logger.cpp +++ b/src/logging/Logger.cpp @@ -3,23 +3,127 @@ #include #include -#define MAX_LOG_MESSAGE_LENGTH 2048 +// Platform-dependent console initialization +static void InitPlatformConsole(); namespace Feather::Logging { - Channel LOG_GENERAL; - Logger GlobalLogger; - void Logger::LogDirect(Channel channel, Level level, const char *message, ...) + ChannelID LOG_GENERAL = REGISTER_LOGGING_CHANNEL("General"); + + // Since min and max are inclusive we have to add 1 here + // This assumes max > min (they better be) + static constexpr int NUM_LEVELS = ((int)Level::MAX_LEVEL - (int)Level::MIN_LEVEL) + 1; + + // Temporary solution while we don't have named enums + static const char *s_levelNames[NUM_LEVELS] = {"ERROR", "WARNING", "INFO", "DEBUG", "TRACE"}; + + // Shifts an enum value to be a positive index in s_levelNames + static constexpr int LEVEL_NAME_OFFSET = 0 - (int)Level::MIN_LEVEL; + + + Logger::Logger() + { + InitPlatformConsole(); + } + + void Logger::LogDirect(ChannelID channel, Level level, const char *message, ...) { char buffer[MAX_LOG_MESSAGE_LENGTH]; + int offset = 0; + + // All color escape sequences follow the following ANSI format: + // ESC (\x1B) CSI ([) SGR (m) + switch (level) + { + case Level::WARNING: + // 1 BRIGHT, 33 YELLOW + offset += snprintf(buffer + offset, MAX_LOG_MESSAGE_LENGTH - offset, "\x1B[1;33m"); + break; + case Level::ERROR: + // 1 BRIGHT, 31 RED + offset += snprintf(buffer + offset, MAX_LOG_MESSAGE_LENGTH - offset, "\x1B[1;31m"); + break; + default: + case Level::INFO: + break; + } + const char* levelName = s_levelNames[(int)level + LEVEL_NAME_OFFSET]; + + if (channel == LOG_GENERAL) { + // Print only severity level + offset += snprintf(buffer + offset, MAX_LOG_MESSAGE_LENGTH - offset, "[%s] ", levelName); + } else { + // Print channel name and severity level + const char *channelName = m_channels[channel]->GetName(); + offset += snprintf(buffer + offset, MAX_LOG_MESSAGE_LENGTH - offset, "[%s] [%s] ", channelName, levelName); + } + + // Write our message va_list args; va_start(args, message); - vsnprintf(buffer, MAX_LOG_MESSAGE_LENGTH, message, args); + offset += vsnprintf(buffer + offset, MAX_LOG_MESSAGE_LENGTH - offset, message, args); va_end(args); - printf(buffer); + // Ignore any terminal newline + if (buffer[offset - 1] == '\n') offset--; + + // Append ANSI style reset code 0 and newline + offset += snprintf(buffer + offset, MAX_LOG_MESSAGE_LENGTH - offset, "\x1b[0m\n"); + + if (level >= Level::INFO) { + // Info and above go to stdout + printf(buffer); + } else { + // Error and warn go to stderr + fprintf(stderr, buffer); + } } -} \ No newline at end of file + + ChannelID Logger::RegisterChannel(const char* name) + { + Channel* channel = new Channel(name); + if (m_channelCount >= MAX_LOGGING_CHANNEL_COUNT) { + // complain + } + m_channels[m_channelCount] = channel; + int id = m_channelCount++; + printf("Registered channel %d '%s'\n", id, name); + return id; + } +} + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + +#endif + +static void InitPlatformConsole() +{ + static bool s_initialized = false; + if (s_initialized) + return; + +#ifdef _WIN32 + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (handle != INVALID_HANDLE_VALUE) + { + DWORD mode = 0; + if (GetConsoleMode(handle, &mode)) + { + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(handle, mode); + } + } +#endif + + s_initialized = true; +} diff --git a/src/logging/Logger.h b/src/logging/Logger.h index d93bbd0..2228894 100644 --- a/src/logging/Logger.h +++ b/src/logging/Logger.h @@ -2,6 +2,11 @@ namespace Feather::Logging { + const int MAX_LOG_MESSAGE_LENGTH = 2048; + const int MAX_LOGGING_CHANNEL_COUNT = 256; + +/*==== Severity Levels ==============================*/ + enum class Level { // Serious problems @@ -18,26 +23,51 @@ namespace Feather::Logging // Fine grained spew TRACE = 2, + + // These are an inclusve interval + MIN_LEVEL = ERROR, + MAX_LEVEL = TRACE, }; +/*==== Channels ==============================*/ + + typedef int ChannelID; + class Channel - { + { + const char* m_name; + public: + Channel(const char* name) : m_name(name) {} + inline const char* GetName() { return m_name; } }; - extern Channel LOG_GENERAL; + extern ChannelID LOG_GENERAL; + +/*==== Logger ==============================*/ class Logger { public: - void LogDirect(Channel channel, Level level, const char* message, ...); + Logger(); + void LogDirect(ChannelID channel, Level level, const char* message, ...); + + ChannelID RegisterChannel(const char* name); + + private: + Channel* m_channels[MAX_LOGGING_CHANNEL_COUNT]; + ChannelID m_channelCount = 0; }; extern Logger GlobalLogger; } -#define Log_Msg( Channel, Message, Args... ) +#define REGISTER_LOGGING_CHANNEL(Name) Feather::Logging::GlobalLogger.RegisterChannel(Name); -#define Log_Debug(Message, Args...) -#define Log_Info(Message, ...) Feather::Logging::GlobalLogger.LogDirect(Feather::Logging::LOG_GENERAL, Feather::Logging::Level::INFO, Message, ##__VA_ARGS__) -#define Log_Warn(Message, Args...) +#define Log_Msg(_Channel, _Level, _Message, ...) Feather::Logging::GlobalLogger.LogDirect(Feather::Logging::_Channel, Feather::Logging::Level::_Level, _Message, ##__VA_ARGS__) + +#define Log_Info(Message, ...) Log_Msg(LOG_GENERAL, INFO, Message, ##__VA_ARGS__) +#define Log_Warn(Message, ...) Log_Msg(LOG_GENERAL, WARNING, Message, ##__VA_ARGS__) +#define Log_Error(Message, ...) Log_Msg(LOG_GENERAL, ERROR, Message, ##__VA_ARGS__) +#define Log_Debug(Message, ...) Log_Msg(LOG_GENERAL, DEBUG, Message, ##__VA_ARGS__) +#define Log_Trace(Message, ...) Log_Msg(LOG_GENERAL, TRACE, Message, ##__VA_ARGS__)