Further implement logging system

This commit is contained in:
DankParrot 2020-07-28 21:32:35 -07:00
parent b67d8a11e8
commit 174af32355
3 changed files with 150 additions and 23 deletions

View File

@ -5,19 +5,12 @@
using namespace Feather; using namespace Feather;
int main() int main()
{ {
ServerProperties properties("server.properties"); ServerProperties properties("server.properties");
properties.Save(); properties.Save();
auto server = DedicatedServer(&properties);
// 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);
return 1; return 1;
} }

View File

@ -3,23 +3,127 @@
#include <cstdio> #include <cstdio>
#include <cstdarg> #include <cstdarg>
#define MAX_LOG_MESSAGE_LENGTH 2048 // Platform-dependent console initialization
static void InitPlatformConsole();
namespace Feather::Logging namespace Feather::Logging
{ {
Channel LOG_GENERAL;
Logger GlobalLogger; 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]; char buffer[MAX_LOG_MESSAGE_LENGTH];
int offset = 0;
// All color escape sequences follow the following ANSI format:
// ESC (\x1B) CSI ([) <COLOR CODES> 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_list args;
va_start(args, message); 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); 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);
}
} }
}
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 <windows.h>
#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;
}

View File

@ -2,6 +2,11 @@
namespace Feather::Logging namespace Feather::Logging
{ {
const int MAX_LOG_MESSAGE_LENGTH = 2048;
const int MAX_LOGGING_CHANNEL_COUNT = 256;
/*==== Severity Levels ==============================*/
enum class Level enum class Level
{ {
// Serious problems // Serious problems
@ -18,26 +23,51 @@ namespace Feather::Logging
// Fine grained spew // Fine grained spew
TRACE = 2, TRACE = 2,
// These are an inclusve interval
MIN_LEVEL = ERROR,
MAX_LEVEL = TRACE,
}; };
/*==== Channels ==============================*/
typedef int ChannelID;
class Channel 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 class Logger
{ {
public: 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; 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_Msg(_Channel, _Level, _Message, ...) Feather::Logging::GlobalLogger.LogDirect(Feather::Logging::_Channel, Feather::Logging::Level::_Level, _Message, ##__VA_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_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__)