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
|
2014-08-12 16:43:04 -04:00
|
|
|
#include <time.h>
|
2014-08-12 11:05:04 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2018-10-15 12:03:08 -04:00
|
|
|
#if defined(_WIN32) || defined (__linux) || defined (__APPLE__)
|
2014-08-12 11:05:04 -04:00
|
|
|
class cColouredConsoleListener
|
|
|
|
: public cLogger::cListener
|
|
|
|
{
|
2014-08-13 07:28:45 -04:00
|
|
|
protected:
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2020-05-14 22:35:43 -04: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
|
|
|
|
2020-05-14 22:35:43 -04: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 16:43:04 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2021-01-26 04:41:55 -05:00
|
|
|
#ifndef NDEBUG
|
2020-05-14 22:35:43 -04:00
|
|
|
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:
|
2020-05-14 22:35:43 -04:00
|
|
|
OutputDebugStringA(AString(a_Message).c_str());
|
2014-08-12 11:05:04 -04:00
|
|
|
}
|
|
|
|
#endif
|
2014-08-12 16:43:04 -04:00
|
|
|
|
|
|
|
|
2020-05-14 22:35:43 -04:00
|
|
|
virtual void SetLogColour(eLogLevel a_LogLevel) override
|
2014-08-12 11:05:04 -04:00
|
|
|
{
|
|
|
|
// by default, gray on black
|
2014-08-12 16:43:04 -04:00
|
|
|
WORD Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
|
2014-08-12 11:05:04 -04:00
|
|
|
switch (a_LogLevel)
|
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Regular:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2014-08-27 08:13:13 -04:00
|
|
|
// Gray on black
|
2014-08-12 16:43:04 -04:00
|
|
|
Attrib = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED;
|
|
|
|
break;
|
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Info:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2014-08-12 11:05:04 -04:00
|
|
|
// Yellow on black
|
2014-08-12 16:43:04 -04:00
|
|
|
Attrib = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
|
|
|
break;
|
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Warning:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2014-08-12 11:05:04 -04:00
|
|
|
// Red on black
|
|
|
|
Attrib = FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2014-08-12 16:43:04 -04:00
|
|
|
break;
|
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Error:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
|
|
|
// Black on red
|
2014-08-12 11:05:04 -04:00
|
|
|
Attrib = BACKGROUND_RED | BACKGROUND_INTENSITY;
|
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
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
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-15 12:03:08 -04:00
|
|
|
#elif defined (__linux) || defined (__APPLE__)
|
2014-08-12 16:43:04 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-15 12:03:08 -04:00
|
|
|
class cANSIConsoleListener
|
2014-08-12 11:05:04 -04:00
|
|
|
: public cColouredConsoleListener
|
|
|
|
{
|
|
|
|
public:
|
2020-05-14 22:35:43 -04:00
|
|
|
virtual void SetLogColour(eLogLevel a_LogLevel) override
|
2014-08-12 11:05:04 -04:00
|
|
|
{
|
|
|
|
switch (a_LogLevel)
|
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Regular:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
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;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Info:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2014-08-27 08:13:13 -04:00
|
|
|
// Yellow on black
|
2014-08-12 11:05:04 -04:00
|
|
|
printf("\x1b[33;1m");
|
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Warning:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2014-08-12 11:05:04 -04:00
|
|
|
// Red on black
|
|
|
|
printf("\x1b[31;1m");
|
2014-08-27 08:13:13 -04:00
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Error:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2014-08-12 11:05:04 -04:00
|
|
|
// Yellow on red
|
|
|
|
printf("\x1b[1;33;41;1m");
|
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
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");
|
2018-06-20 03:15:57 -04:00
|
|
|
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 16:43:04 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-08-12 11:05:04 -04:00
|
|
|
class cVanillaCPPConsoleListener
|
|
|
|
: public cLogger::cListener
|
|
|
|
{
|
|
|
|
public:
|
2020-05-14 22:35:43 -04:00
|
|
|
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
|
2014-08-12 11:05:04 -04:00
|
|
|
{
|
|
|
|
switch (a_LogLevel)
|
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Regular:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
fputs("Log: ", stdout);
|
2014-08-12 11:05:04 -04:00
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Info:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
fputs("Info: ", stdout);
|
2014-08-12 11:05:04 -04:00
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Warning:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
fputs("Warning: ", stdout);
|
2014-08-12 11:05:04 -04:00
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Error:
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
fputs("Error: ", stdout);
|
2014-08-12 11:05:04 -04:00
|
|
|
break;
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2014-08-12 16:43:04 -04:00
|
|
|
|
|
|
|
|
2015-06-04 09:13:07 -04:00
|
|
|
// Listener for when stdout is closed, i.e. When running as a daemon.
|
|
|
|
class cNullConsoleListener
|
|
|
|
: public cLogger::cListener
|
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
|
2015-06-04 09:13:07 -04:00
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-08-30 17:57:43 -04:00
|
|
|
std::unique_ptr<cLogger::cListener> MakeConsoleListener(bool a_IsService)
|
2014-08-12 11:05:04 -04:00
|
|
|
{
|
2015-06-04 09:13:07 -04:00
|
|
|
if (a_IsService)
|
|
|
|
{
|
2020-08-01 14:18:03 -04:00
|
|
|
return std::make_unique<cNullConsoleListener>();
|
2015-06-04 09:13:07 -04:00
|
|
|
}
|
|
|
|
|
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;
|
2014-08-12 16:43:04 -04:00
|
|
|
HANDLE Console = GetStdHandle(STD_OUTPUT_HANDLE);
|
2014-08-12 11:05:04 -04:00
|
|
|
GetConsoleScreenBufferInfo(Console, &sbi);
|
|
|
|
WORD DefaultConsoleAttrib = sbi.wAttributes;
|
2020-08-01 14:18:03 -04:00
|
|
|
return std::make_unique<cWindowsConsoleListener>(Console, DefaultConsoleAttrib);
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-01 14:18:03 -04:00
|
|
|
return std::make_unique<cVanillaCPPConsoleListener>();
|
2014-08-12 11:05:04 -04:00
|
|
|
}
|
2020-05-10 12:18:28 -04:00
|
|
|
#elif defined (__linux) || defined (__APPLE__)
|
2014-08-12 11:05:04 -04:00
|
|
|
// TODO: lookup terminal in terminfo
|
|
|
|
if (isatty(fileno(stdout)))
|
|
|
|
{
|
2020-08-01 14:18:03 -04:00
|
|
|
return std::make_unique<cANSIConsoleListener>();
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-08-01 14:18:03 -04:00
|
|
|
return std::make_unique<cVanillaCPPConsoleListener>();
|
2014-08-12 11:05:04 -04:00
|
|
|
}
|
|
|
|
#else
|
2020-08-01 14:18:03 -04:00
|
|
|
return std::make_unique<cVanillaCPPConsoleListener>();
|
2014-08-12 11:05:04 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-08-12 16:43:04 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// cFileListener:
|
|
|
|
|
2015-08-30 17:57:43 -04:00
|
|
|
class cFileListener
|
|
|
|
: public cLogger::cListener
|
2014-08-12 11:05:04 -04:00
|
|
|
{
|
2015-08-30 17:57:43 -04:00
|
|
|
public:
|
2014-08-12 16:43:04 -04:00
|
|
|
|
2015-08-30 17:57:43 -04:00
|
|
|
cFileListener(void) {}
|
2014-08-12 16:43:04 -04:00
|
|
|
|
2015-08-30 17:57:43 -04:00
|
|
|
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");
|
2015-08-30 17:57:43 -04:00
|
|
|
bool success = m_File.Open(
|
2020-05-07 15:14:00 -04:00
|
|
|
Printf(
|
2015-08-30 17:57:43 -04:00
|
|
|
"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;
|
|
|
|
}
|
2014-08-12 16:43:04 -04:00
|
|
|
|
2020-05-14 22:35:43 -04:00
|
|
|
virtual void Log(std::string_view a_Message, eLogLevel a_LogLevel) override
|
2014-08-12 11:05:04 -04:00
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
std::string_view LogLevelPrefix = "Unkn ";
|
2015-08-30 17:57:43 -04:00
|
|
|
bool ShouldFlush = false;
|
|
|
|
switch (a_LogLevel)
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Regular:
|
2015-08-30 17:57:43 -04:00
|
|
|
{
|
|
|
|
LogLevelPrefix = " ";
|
|
|
|
break;
|
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Info:
|
2015-08-30 17:57:43 -04:00
|
|
|
{
|
|
|
|
LogLevelPrefix = "Info ";
|
|
|
|
break;
|
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Warning:
|
2015-08-30 17:57:43 -04:00
|
|
|
{
|
|
|
|
LogLevelPrefix = "Warn ";
|
|
|
|
ShouldFlush = true;
|
|
|
|
break;
|
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
case eLogLevel::Error:
|
2015-08-30 17:57:43 -04:00
|
|
|
{
|
|
|
|
LogLevelPrefix = "Err ";
|
|
|
|
ShouldFlush = true;
|
|
|
|
break;
|
|
|
|
}
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2020-05-14 22:35:43 -04:00
|
|
|
m_File.Write(LogLevelPrefix);
|
|
|
|
m_File.Write(a_Message);
|
|
|
|
|
2015-08-30 17:57:43 -04:00
|
|
|
if (ShouldFlush)
|
2014-08-12 16:43:04 -04:00
|
|
|
{
|
2015-08-30 17:57:43 -04:00
|
|
|
m_File.Flush();
|
2014-08-12 16:43:04 -04:00
|
|
|
}
|
2014-08-12 11:05:04 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2015-08-30 17:57:43 -04:00
|
|
|
private:
|
|
|
|
|
|
|
|
cFile m_File;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::pair<bool, std::unique_ptr<cLogger::cListener>> MakeFileListener()
|
|
|
|
{
|
2020-08-01 14:18:03 -04:00
|
|
|
auto listener = std::make_unique<cFileListener>();
|
2015-08-30 17:57:43 -04:00
|
|
|
if (!listener->Open())
|
2015-08-07 06:47:45 -04:00
|
|
|
{
|
2015-08-30 17:57:43 -04:00
|
|
|
return {false, nullptr};
|
2015-08-07 06:47:45 -04:00
|
|
|
}
|
2015-08-30 17:57:43 -04:00
|
|
|
return {true, std::move(listener)};
|
2014-08-12 11:05:04 -04:00
|
|
|
}
|
2014-08-12 16:43:04 -04:00
|
|
|
|
|
|
|
|