1
0
Fork 0
cuberite-2a/src/LoggerListeners.cpp

335 lines
6.1 KiB
C++
Raw Permalink Normal View History

2014-08-12 11:05:04 -04:00
#include "Globals.h"
#include "LoggerListeners.h"
#if defined(_WIN32)
#include <io.h> // Needed for _isatty(), not available on Linux
#include <time.h>
2014-08-12 11:05:04 -04:00
#endif
#if defined(_WIN32) || defined (__linux) || defined (__APPLE__)
2014-08-12 11:05:04 -04:00
class cColouredConsoleListener
: public cLogger::cListener
{
protected:
2016-02-05 16:45:45 -05:00
virtual void SetLogColour(eLogLevel a_LogLevel) = 0;
2014-08-12 11:05:04 -04:00
virtual void SetDefaultLogColour() = 0;
2016-02-05 16:45:45 -05:00
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
2014-08-12 11:05:04 -04:00
{
SetLogColour(a_LogLevel);
2020-05-15 14:10:43 -04:00
fwrite(a_Message.data(), sizeof(char), a_Message.size(), stdout);
2014-08-12 11:05:04 -04:00
SetDefaultLogColour();
}
};
#endif
2014-08-12 11:05:04 -04:00
#ifdef _WIN32
2020-04-13 12:38:06 -04:00
class cWindowsConsoleListener:
public cColouredConsoleListener
2014-08-12 11:05:04 -04:00
{
2020-04-13 12:38:06 -04:00
using Super = cColouredConsoleListener;
2014-08-12 11:05:04 -04:00
public:
2020-04-13 12:38:06 -04:00
cWindowsConsoleListener(HANDLE a_Console, WORD a_DefaultConsoleAttrib):
2014-08-12 11:05:04 -04:00
m_Console(a_Console),
m_DefaultConsoleAttrib(a_DefaultConsoleAttrib)
{
}
2016-02-05 16:45:45 -05:00
#ifndef NDEBUG
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
2014-08-12 11:05:04 -04:00
{
2020-04-13 12:38:06 -04:00
Super::Log(a_Message, a_LogLevel);
2014-08-12 11:05:04 -04:00
// In a Windows Debug build, output the log to debug console as well:
OutputDebugStringA(AString(a_Message).c_str());
2014-08-12 11:05:04 -04:00
}
#endif
virtual void SetLogColour(eLogLevel a_LogLevel) override
2014-08-12 11:05:04 -04:00
{
// by default, gray on black
WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
2014-08-12 11:05:04 -04:00
switch (a_LogLevel)
{
case eLogLevel::Regular:
{
2014-08-27 08:13:13 -04:00
// Gray on black
Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
break;
}
case eLogLevel::Info:
{
2014-08-12 11:05:04 -04:00
// Yellow on black
Attrib = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
}
case eLogLevel::Warning:
{
2014-08-12 11:05:04 -04:00
// Red on black
Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY;
break;
}
case eLogLevel::Error:
{
// Black on red
2014-08-12 11:05:04 -04:00
Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY;
break;
}
2014-08-12 11:05:04 -04:00
}
SetConsoleTextAttribute(m_Console, Attrib);
}
2016-02-05 16:45:45 -05:00
2014-08-12 11:05:04 -04:00
virtual void SetDefaultLogColour() override
2014-08-27 08:13:13 -04:00
{
2014-08-12 11:05:04 -04:00
SetConsoleTextAttribute(m_Console, m_DefaultConsoleAttrib);
}
2016-02-05 16:45:45 -05:00
2014-08-12 11:05:04 -04:00
private:
2016-02-05 16:45:45 -05:00
2014-08-12 11:05:04 -04:00
HANDLE m_Console;
WORD m_DefaultConsoleAttrib;
};
2016-02-05 16:45:45 -05:00
#elif defined (__linux) || defined (__APPLE__)
class cANSIConsoleListener
2014-08-12 11:05:04 -04:00
: public cColouredConsoleListener
{
public:
virtual void SetLogColour(eLogLevel a_LogLevel) override
2014-08-12 11:05:04 -04:00
{
switch (a_LogLevel)
{
case eLogLevel::Regular:
{
2014-08-27 08:13:13 -04:00
// Whatever the console default is
2014-08-12 11:05:04 -04:00
printf("\x1b[0m");
2014-08-27 08:13:13 -04:00
break;
}
case eLogLevel::Info:
{
2014-08-27 08:13:13 -04:00
// Yellow on black
2014-08-12 11:05:04 -04:00
printf("\x1b[33;1m");
break;
}
case eLogLevel::Warning:
{
2014-08-12 11:05:04 -04:00
// Red on black
printf("\x1b[31;1m");
2014-08-27 08:13:13 -04:00
break;
}
case eLogLevel::Error:
{
2014-08-12 11:05:04 -04:00
// Yellow on red
printf("\x1b[1;33;41;1m");
break;
}
2014-08-12 11:05:04 -04:00
}
}
2016-02-05 16:45:45 -05:00
2014-08-12 11:05:04 -04:00
virtual void SetDefaultLogColour() override
{
2014-08-27 08:13:13 -04:00
// Whatever the console default is
2014-08-12 11:05:04 -04:00
printf("\x1b[0m");
fflush(stdout);
2014-08-12 11:05:04 -04:00
}
};
2016-02-05 16:45:45 -05:00
2014-08-12 11:05:04 -04:00
#endif
2014-08-12 11:05:04 -04:00
class cVanillaCPPConsoleListener
: public cLogger::cListener
{
public:
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
2014-08-12 11:05:04 -04:00
{
switch (a_LogLevel)
{
case eLogLevel::Regular:
{
fputs("Log: ", stdout);
2014-08-12 11:05:04 -04:00
break;
}
case eLogLevel::Info:
{
fputs("Info: ", stdout);
2014-08-12 11:05:04 -04:00
break;
}
case eLogLevel::Warning:
{
fputs("Warning: ", stdout);
2014-08-12 11:05:04 -04:00
break;
}
case eLogLevel::Error:
{
fputs("Error: ", stdout);
2014-08-12 11:05:04 -04:00
break;
}
2014-08-12 11:05:04 -04:00
}
2020-05-15 14:10:43 -04:00
fwrite(a_Message.data(), sizeof(char), a_Message.size(), stdout);
2014-08-12 11:05:04 -04:00
}
};
// Listener for when stdout is closed, i.e. When running as a daemon.
class cNullConsoleListener
: public cLogger::cListener
{
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
{
}
};
std::unique_ptr<cLogger::cListener> MakeConsoleListener(bool a_IsService)
2014-08-12 11:05:04 -04:00
{
if (a_IsService)
{
return std::make_unique<cNullConsoleListener>();
}
2014-08-12 11:05:04 -04:00
#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);
2014-08-12 11:05:04 -04:00
GetConsoleScreenBufferInfo(Console, &sbi);
WORD DefaultConsoleAttrib = sbi.wAttributes;
return std::make_unique<cWindowsConsoleListener>(Console, DefaultConsoleAttrib);
}
else
{
return std::make_unique<cVanillaCPPConsoleListener>();
2014-08-12 11:05:04 -04:00
}
#elif defined (__linux) || defined (__APPLE__)
2014-08-12 11:05:04 -04:00
// TODO: lookup terminal in terminfo
if (isatty(fileno(stdout)))
{
return std::make_unique<cANSIConsoleListener>();
}
else
{
return std::make_unique<cVanillaCPPConsoleListener>();
2014-08-12 11:05:04 -04:00
}
#else
return std::make_unique<cVanillaCPPConsoleListener>();
2014-08-12 11:05:04 -04:00
#endif
}
////////////////////////////////////////////////////////////////////////////////
// cFileListener:
class cFileListener
: public cLogger::cListener
2014-08-12 11:05:04 -04:00
{
public:
cFileListener(void) {}
bool Open()
{
// Assume creation succeeds, as the API does not provide a way to tell if the folder exists.
2020-05-07 15:14:00 -04:00
cFile::CreateFolder("logs");
bool success = m_File.Open(
2020-05-07 15:14:00 -04:00
Printf(
"logs/LOG_%d.txt",
std::chrono::duration_cast<std::chrono::duration<int, std::ratio<1>>>(
std::chrono::system_clock::now().time_since_epoch()
).count()
),
cFile::fmAppend
);
return success;
}
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
2014-08-12 11:05:04 -04:00
{
std::string_view LogLevelPrefix = "Unkn ";
bool ShouldFlush = false;
switch (a_LogLevel)
{
case eLogLevel::Regular:
{
LogLevelPrefix = " ";
break;
}
case eLogLevel::Info:
{
LogLevelPrefix = "Info ";
break;
}
case eLogLevel::Warning:
{
LogLevelPrefix = "Warn ";
ShouldFlush = true;
break;
}
case eLogLevel::Error:
{
LogLevelPrefix = "Err ";
ShouldFlush = true;
break;
}
}
m_File.Write(LogLevelPrefix);
m_File.Write(a_Message);
if (ShouldFlush)
{
m_File.Flush();
}
2014-08-12 11:05:04 -04:00
}
2016-02-05 16:45:45 -05:00
private:
cFile m_File;
};
std::pair<bool, std::unique_ptr<cLogger::cListener>> MakeFileListener()
{
auto listener = std::make_unique<cFileListener>();
if (!listener->Open())
{
return {false, nullptr};
}
return {true, std::move(listener)};
2014-08-12 11:05:04 -04:00
}