2022-04-22 23:04:48 +00:00
|
|
|
#include "logger.h"
|
|
|
|
|
|
|
|
#include "color.h"
|
|
|
|
#include "system.h"
|
|
|
|
|
2022-05-21 10:06:54 +00:00
|
|
|
#include <engine/shared/config.h>
|
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
#include <atomic>
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
#if defined(CONF_FAMILY_WINDOWS)
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#undef _WIN32_WINNT
|
|
|
|
#define _WIN32_WINNT 0x0501 /* required for mingw to get getaddrinfo to work */
|
|
|
|
#include <windows.h>
|
2022-05-26 10:32:20 +00:00
|
|
|
#else
|
|
|
|
#include <unistd.h>
|
2022-04-22 23:04:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
std::atomic<ILogger *> global_logger = nullptr;
|
|
|
|
thread_local ILogger *scope_logger = nullptr;
|
|
|
|
thread_local bool in_logger = false;
|
|
|
|
|
|
|
|
void log_set_global_logger(ILogger *logger)
|
|
|
|
{
|
|
|
|
ILogger *null = nullptr;
|
|
|
|
if(!global_logger.compare_exchange_strong(null, logger, std::memory_order_acq_rel))
|
|
|
|
{
|
|
|
|
dbg_assert(false, "global logger has already been set and can only be set once");
|
|
|
|
}
|
|
|
|
atexit(log_global_logger_finish);
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_global_logger_finish()
|
|
|
|
{
|
|
|
|
global_logger.load(std::memory_order_acquire)->GlobalFinish();
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_set_global_logger_default()
|
|
|
|
{
|
|
|
|
std::unique_ptr<ILogger> logger;
|
|
|
|
#if defined(CONF_PLATFORM_ANDROID)
|
|
|
|
logger = log_logger_android();
|
|
|
|
#else
|
|
|
|
logger = log_logger_stdout();
|
|
|
|
#endif
|
|
|
|
log_set_global_logger(logger.release());
|
|
|
|
}
|
|
|
|
|
|
|
|
ILogger *log_get_scope_logger()
|
|
|
|
{
|
|
|
|
if(!scope_logger)
|
|
|
|
{
|
|
|
|
scope_logger = global_logger.load(std::memory_order_acquire);
|
|
|
|
}
|
|
|
|
return scope_logger;
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_set_scope_logger(ILogger *logger)
|
|
|
|
{
|
|
|
|
scope_logger = logger;
|
|
|
|
if(!scope_logger)
|
|
|
|
{
|
|
|
|
scope_logger = global_logger.load(std::memory_order_acquire);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_log_impl(LEVEL level, bool have_color, LOG_COLOR color, const char *sys, const char *fmt, va_list args)
|
|
|
|
{
|
2022-05-21 10:06:54 +00:00
|
|
|
if(level > g_Config.m_Loglevel)
|
|
|
|
return;
|
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
// Make sure we're not logging recursively.
|
|
|
|
if(in_logger)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
in_logger = true;
|
|
|
|
if(!scope_logger)
|
|
|
|
{
|
|
|
|
scope_logger = global_logger.load(std::memory_order_acquire);
|
|
|
|
}
|
|
|
|
if(!scope_logger)
|
|
|
|
{
|
|
|
|
in_logger = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CLogMessage Msg;
|
|
|
|
Msg.m_Level = level;
|
|
|
|
Msg.m_HaveColor = have_color;
|
|
|
|
Msg.m_Color = color;
|
|
|
|
str_timestamp_format(Msg.m_aTimestamp, sizeof(Msg.m_aTimestamp), FORMAT_SPACE);
|
|
|
|
Msg.m_TimestampLength = str_length(Msg.m_aTimestamp);
|
|
|
|
str_copy(Msg.m_aSystem, sys, sizeof(Msg.m_aSystem));
|
|
|
|
Msg.m_SystemLength = str_length(Msg.m_aSystem);
|
|
|
|
|
|
|
|
// TODO: Add level?
|
|
|
|
str_format(Msg.m_aLine, sizeof(Msg.m_aLine), "[%s][%s]: ", Msg.m_aTimestamp, Msg.m_aSystem);
|
|
|
|
Msg.m_LineMessageOffset = str_length(Msg.m_aLine);
|
|
|
|
|
|
|
|
char *pMessage = Msg.m_aLine + Msg.m_LineMessageOffset;
|
|
|
|
int MessageSize = sizeof(Msg.m_aLine) - Msg.m_LineMessageOffset;
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
|
|
|
#endif
|
|
|
|
#if defined(CONF_FAMILY_WINDOWS)
|
|
|
|
_vsnprintf(pMessage, MessageSize, fmt, args);
|
|
|
|
#else
|
|
|
|
vsnprintf(pMessage, MessageSize, fmt, args);
|
|
|
|
#endif
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#pragma GCC diagnostic pop
|
|
|
|
#endif
|
|
|
|
Msg.m_LineLength = str_length(Msg.m_aLine);
|
|
|
|
scope_logger->Log(&Msg);
|
|
|
|
in_logger = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_log_v(LEVEL level, const char *sys, const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
log_log_impl(level, false, LOG_COLOR{0, 0, 0}, sys, fmt, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_log(LEVEL level, const char *sys, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
log_log_impl(level, false, LOG_COLOR{0, 0, 0}, sys, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_log_color_v(LEVEL level, LOG_COLOR color, const char *sys, const char *fmt, va_list args)
|
|
|
|
{
|
|
|
|
log_log_impl(level, true, color, sys, fmt, args);
|
|
|
|
}
|
|
|
|
|
|
|
|
void log_log_color(LEVEL level, LOG_COLOR color, const char *sys, const char *fmt, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
log_log_impl(level, true, color, sys, fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONF_PLATFORM_ANDROID)
|
|
|
|
class CLoggerAndroid : public ILogger
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void Log(const CLogMessage *pMessage) override
|
|
|
|
{
|
|
|
|
int AndroidLevel;
|
|
|
|
switch(Level)
|
|
|
|
{
|
|
|
|
case LEVEL_TRACE: AndroidLevel = ANDROID_LOG_VERBOSE; break;
|
|
|
|
case LEVEL_DEBUG: AndroidLevel = ANDROID_LOG_DEBUG; break;
|
|
|
|
case LEVEL_INFO: AndroidLevel = ANDROID_LOG_INFO; break;
|
|
|
|
case LEVEL_WARN: AndroidLevel = ANDROID_LOG_WARN; break;
|
|
|
|
case LEVEL_ERROR: AndroidLevel = ANDROID_LOG_ERROR; break;
|
|
|
|
}
|
|
|
|
__android_log_write(AndroidLevel, pMessage->m_aSystem, pMessage->Message());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
std::unique_ptr<ILogger> log_logger_android()
|
|
|
|
{
|
2022-05-28 12:46:53 +00:00
|
|
|
return std::make_unique<CLoggerAndroid>();
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
std::unique_ptr<ILogger> log_logger_android()
|
|
|
|
{
|
|
|
|
dbg_assert(0, "Android logger on non-Android");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
class CLoggerCollection : public ILogger
|
|
|
|
{
|
|
|
|
std::vector<std::shared_ptr<ILogger>> m_apLoggers;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CLoggerCollection(std::vector<std::shared_ptr<ILogger>> &&apLoggers) :
|
|
|
|
m_apLoggers(std::move(apLoggers))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void Log(const CLogMessage *pMessage) override
|
|
|
|
{
|
|
|
|
for(auto &pLogger : m_apLoggers)
|
|
|
|
{
|
|
|
|
pLogger->Log(pMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void GlobalFinish() override
|
|
|
|
{
|
|
|
|
for(auto &pLogger : m_apLoggers)
|
|
|
|
{
|
|
|
|
pLogger->GlobalFinish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unique_ptr<ILogger> log_logger_collection(std::vector<std::shared_ptr<ILogger>> &&loggers)
|
|
|
|
{
|
2022-05-28 12:46:53 +00:00
|
|
|
return std::make_unique<CLoggerCollection>(std::move(loggers));
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class CLoggerAsync : public ILogger
|
|
|
|
{
|
|
|
|
ASYNCIO *m_pAio;
|
|
|
|
bool m_AnsiTruecolor;
|
|
|
|
bool m_Close;
|
|
|
|
|
|
|
|
public:
|
|
|
|
CLoggerAsync(IOHANDLE File, bool AnsiTruecolor, bool Close) :
|
|
|
|
m_pAio(aio_new(File)),
|
|
|
|
m_AnsiTruecolor(AnsiTruecolor),
|
|
|
|
m_Close(Close)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void Log(const CLogMessage *pMessage) override
|
|
|
|
{
|
|
|
|
aio_lock(m_pAio);
|
|
|
|
if(m_AnsiTruecolor)
|
|
|
|
{
|
|
|
|
// https://en.wikipedia.org/w/index.php?title=ANSI_escape_code&oldid=1077146479#24-bit
|
|
|
|
char aAnsi[32];
|
|
|
|
if(pMessage->m_HaveColor)
|
|
|
|
{
|
|
|
|
str_format(aAnsi, sizeof(aAnsi),
|
|
|
|
"\x1b[38;2;%d;%d;%dm",
|
|
|
|
pMessage->m_Color.r,
|
|
|
|
pMessage->m_Color.g,
|
|
|
|
pMessage->m_Color.b);
|
|
|
|
}
|
|
|
|
aio_write_unlocked(m_pAio, aAnsi, str_length(aAnsi));
|
|
|
|
}
|
|
|
|
aio_write_unlocked(m_pAio, pMessage->m_aLine, pMessage->m_LineLength);
|
2022-06-03 08:55:18 +00:00
|
|
|
if(m_AnsiTruecolor && pMessage->m_HaveColor)
|
|
|
|
{
|
|
|
|
aio_write_unlocked(m_pAio, "\x1b[0m", 4); // reset
|
|
|
|
}
|
2022-04-22 23:04:48 +00:00
|
|
|
aio_write_newline_unlocked(m_pAio);
|
|
|
|
aio_unlock(m_pAio);
|
|
|
|
}
|
|
|
|
~CLoggerAsync()
|
|
|
|
{
|
|
|
|
if(m_Close)
|
|
|
|
{
|
|
|
|
aio_close(m_pAio);
|
|
|
|
}
|
|
|
|
aio_wait(m_pAio);
|
|
|
|
aio_free(m_pAio);
|
|
|
|
}
|
|
|
|
void GlobalFinish() override
|
|
|
|
{
|
|
|
|
if(m_Close)
|
|
|
|
{
|
|
|
|
aio_close(m_pAio);
|
|
|
|
}
|
|
|
|
aio_wait(m_pAio);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unique_ptr<ILogger> log_logger_file(IOHANDLE logfile)
|
|
|
|
{
|
2022-05-28 12:46:53 +00:00
|
|
|
return std::make_unique<CLoggerAsync>(logfile, false, true);
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONF_FAMILY_WINDOWS)
|
|
|
|
static int color_hsv_to_windows_console_color(const ColorHSVA &Hsv)
|
|
|
|
{
|
|
|
|
int h = Hsv.h * 255.0f;
|
|
|
|
int s = Hsv.s * 255.0f;
|
|
|
|
int v = Hsv.v * 255.0f;
|
|
|
|
if(s >= 0 && s <= 10)
|
|
|
|
{
|
|
|
|
if(v <= 150)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_INTENSITY;
|
|
|
|
return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
2022-05-30 21:00:48 +00:00
|
|
|
if(h < 0)
|
|
|
|
return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
|
|
|
else if(h < 15)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 30)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_GREEN | FOREGROUND_RED;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 60)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 110)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 140)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 170)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_BLUE | FOREGROUND_INTENSITY;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 195)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_BLUE | FOREGROUND_RED;
|
2022-05-30 21:00:48 +00:00
|
|
|
else if(h < 240)
|
2022-05-30 20:57:25 +00:00
|
|
|
return FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2022-04-22 23:04:48 +00:00
|
|
|
else
|
2022-05-30 21:00:48 +00:00
|
|
|
return FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class CWindowsConsoleLogger : public ILogger
|
|
|
|
{
|
2022-05-17 20:21:25 +00:00
|
|
|
HANDLE m_pConsole;
|
2022-05-30 21:15:24 +00:00
|
|
|
int m_BackgroundColor;
|
|
|
|
int m_ForegroundColor;
|
2022-05-31 17:21:40 +00:00
|
|
|
std::mutex m_OutputLock;
|
|
|
|
bool m_Finished = false;
|
2022-05-17 20:21:25 +00:00
|
|
|
|
2022-04-22 23:04:48 +00:00
|
|
|
public:
|
2022-05-17 20:21:25 +00:00
|
|
|
CWindowsConsoleLogger(HANDLE pConsole) :
|
|
|
|
m_pConsole(pConsole)
|
|
|
|
{
|
2022-05-30 21:15:24 +00:00
|
|
|
CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
|
|
|
|
if(GetConsoleScreenBufferInfo(pConsole, &ConsoleInfo))
|
|
|
|
{
|
|
|
|
m_BackgroundColor = ConsoleInfo.wAttributes & (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY);
|
|
|
|
m_ForegroundColor = ConsoleInfo.wAttributes & (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_BackgroundColor = 0;
|
|
|
|
m_ForegroundColor = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
|
|
|
}
|
2022-05-17 20:21:25 +00:00
|
|
|
}
|
2022-04-22 23:04:48 +00:00
|
|
|
void Log(const CLogMessage *pMessage) override
|
|
|
|
{
|
2022-05-17 20:21:25 +00:00
|
|
|
wchar_t *pWide = (wchar_t *)malloc((pMessage->m_LineLength + 2) * sizeof(*pWide));
|
2022-04-22 23:04:48 +00:00
|
|
|
const char *p = pMessage->m_aLine;
|
|
|
|
int WLen = 0;
|
|
|
|
|
2022-05-17 20:21:25 +00:00
|
|
|
mem_zero(pWide, (pMessage->m_LineLength + 2) * sizeof(*pWide));
|
2022-04-22 23:04:48 +00:00
|
|
|
|
|
|
|
for(int Codepoint = 0; (Codepoint = str_utf8_decode(&p)); WLen++)
|
|
|
|
{
|
|
|
|
char aU16[4] = {0};
|
|
|
|
|
|
|
|
if(Codepoint < 0)
|
|
|
|
{
|
|
|
|
free(pWide);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(str_utf16le_encode(aU16, Codepoint) != 2)
|
|
|
|
{
|
|
|
|
free(pWide);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_copy(&pWide[WLen], aU16, 2);
|
|
|
|
}
|
2022-05-17 20:21:25 +00:00
|
|
|
pWide[WLen++] = '\r';
|
|
|
|
pWide[WLen++] = '\n';
|
2022-05-30 21:15:24 +00:00
|
|
|
int Color = m_BackgroundColor;
|
2022-04-22 23:04:48 +00:00
|
|
|
if(pMessage->m_HaveColor)
|
|
|
|
{
|
|
|
|
ColorRGBA Rgba(1.0, 1.0, 1.0, 1.0);
|
|
|
|
Rgba.r = pMessage->m_Color.r / 255.0;
|
|
|
|
Rgba.g = pMessage->m_Color.g / 255.0;
|
|
|
|
Rgba.b = pMessage->m_Color.b / 255.0;
|
2022-05-30 21:15:24 +00:00
|
|
|
Color |= color_hsv_to_windows_console_color(color_cast<ColorHSVA>(Rgba));
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
2022-05-30 21:15:24 +00:00
|
|
|
else
|
|
|
|
Color |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
2022-05-31 17:21:40 +00:00
|
|
|
|
|
|
|
m_OutputLock.lock();
|
|
|
|
if(!m_Finished)
|
|
|
|
{
|
|
|
|
SetConsoleTextAttribute(m_pConsole, Color);
|
|
|
|
WriteConsoleW(m_pConsole, pWide, WLen, NULL, NULL);
|
|
|
|
}
|
|
|
|
m_OutputLock.unlock();
|
2022-04-22 23:04:48 +00:00
|
|
|
free(pWide);
|
|
|
|
}
|
2022-05-30 21:15:24 +00:00
|
|
|
void GlobalFinish() override
|
|
|
|
{
|
|
|
|
// Restore original color
|
2022-05-31 17:21:40 +00:00
|
|
|
m_OutputLock.lock();
|
2022-05-30 21:15:24 +00:00
|
|
|
SetConsoleTextAttribute(m_pConsole, m_BackgroundColor | m_ForegroundColor);
|
2022-05-31 17:21:40 +00:00
|
|
|
m_Finished = true;
|
|
|
|
m_OutputLock.unlock();
|
2022-05-30 21:15:24 +00:00
|
|
|
}
|
2022-04-22 23:04:48 +00:00
|
|
|
};
|
2022-05-17 20:21:25 +00:00
|
|
|
class CWindowsFileLogger : public ILogger
|
|
|
|
{
|
|
|
|
HANDLE m_pFile;
|
2022-05-31 17:21:40 +00:00
|
|
|
std::mutex m_OutputLock;
|
2022-05-17 20:21:25 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
CWindowsFileLogger(HANDLE pFile) :
|
|
|
|
m_pFile(pFile)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
void Log(const CLogMessage *pMessage) override
|
|
|
|
{
|
2022-05-31 17:21:40 +00:00
|
|
|
m_OutputLock.lock();
|
2022-05-17 20:21:25 +00:00
|
|
|
WriteFile(m_pFile, pMessage->m_aLine, pMessage->m_LineLength, NULL, NULL);
|
|
|
|
WriteFile(m_pFile, "\r\n", 2, NULL, NULL);
|
2022-05-31 17:21:40 +00:00
|
|
|
m_OutputLock.unlock();
|
2022-05-17 20:21:25 +00:00
|
|
|
}
|
|
|
|
};
|
2022-04-22 23:04:48 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
std::unique_ptr<ILogger> log_logger_stdout()
|
|
|
|
{
|
|
|
|
#if !defined(CONF_FAMILY_WINDOWS)
|
|
|
|
// TODO: Only enable true color when COLORTERM contains "truecolor".
|
|
|
|
// https://github.com/termstandard/colors/tree/65bf0cd1ece7c15fa33a17c17528b02c99f1ae0b#checking-for-colorterm
|
2022-05-26 10:32:20 +00:00
|
|
|
const bool colors = getenv("NO_COLOR") == nullptr && isatty(STDOUT_FILENO);
|
2022-05-28 12:46:53 +00:00
|
|
|
return std::make_unique<CLoggerAsync>(io_stdout(), colors, false);
|
2022-04-22 23:04:48 +00:00
|
|
|
#else
|
2022-05-19 19:24:46 +00:00
|
|
|
if(GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_UNKNOWN)
|
|
|
|
AttachConsole(ATTACH_PARENT_PROCESS);
|
2022-05-17 20:21:25 +00:00
|
|
|
HANDLE pOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
switch(GetFileType(pOutput))
|
|
|
|
{
|
2022-05-28 12:46:53 +00:00
|
|
|
case FILE_TYPE_CHAR: return std::make_unique<CWindowsConsoleLogger>(pOutput);
|
2022-05-17 20:21:25 +00:00
|
|
|
case FILE_TYPE_PIPE: // fall through, writing to pipe works the same as writing to a file
|
2022-05-28 12:46:53 +00:00
|
|
|
case FILE_TYPE_DISK: return std::make_unique<CWindowsFileLogger>(pOutput);
|
|
|
|
default: return std::make_unique<CLoggerAsync>(io_stdout(), false, false);
|
2022-05-17 20:21:25 +00:00
|
|
|
}
|
2022-04-22 23:04:48 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONF_FAMILY_WINDOWS)
|
|
|
|
class CLoggerWindowsDebugger : public ILogger
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void Log(const CLogMessage *pMessage) override
|
|
|
|
{
|
|
|
|
WCHAR aWBuffer[4096];
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, pMessage->m_aLine, -1, aWBuffer, sizeof(aWBuffer) / sizeof(WCHAR));
|
|
|
|
OutputDebugStringW(aWBuffer);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
std::unique_ptr<ILogger> log_logger_windows_debugger()
|
|
|
|
{
|
2022-05-28 12:46:53 +00:00
|
|
|
return std::make_unique<CLoggerWindowsDebugger>();
|
2022-04-22 23:04:48 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
std::unique_ptr<ILogger> log_logger_windows_debugger()
|
|
|
|
{
|
|
|
|
dbg_assert(0, "Windows Debug logger on non-Windows");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void CFutureLogger::Set(std::unique_ptr<ILogger> &&pLogger)
|
|
|
|
{
|
|
|
|
ILogger *null = nullptr;
|
|
|
|
m_PendingLock.lock();
|
|
|
|
ILogger *pLoggerRaw = pLogger.release();
|
|
|
|
if(!m_pLogger.compare_exchange_strong(null, pLoggerRaw, std::memory_order_acq_rel))
|
|
|
|
{
|
|
|
|
dbg_assert(false, "future logger has already been set and can only be set once");
|
|
|
|
}
|
|
|
|
for(const auto &Pending : m_aPending)
|
|
|
|
{
|
|
|
|
pLoggerRaw->Log(&Pending);
|
|
|
|
}
|
|
|
|
m_aPending.clear();
|
|
|
|
m_aPending.shrink_to_fit();
|
|
|
|
m_PendingLock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFutureLogger::Log(const CLogMessage *pMessage)
|
|
|
|
{
|
|
|
|
ILogger *pLogger = m_pLogger.load(std::memory_order_acquire);
|
|
|
|
if(pLogger)
|
|
|
|
{
|
|
|
|
pLogger->Log(pMessage);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_PendingLock.lock();
|
|
|
|
m_aPending.push_back(*pMessage);
|
|
|
|
m_PendingLock.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFutureLogger::GlobalFinish()
|
|
|
|
{
|
|
|
|
ILogger *pLogger = m_pLogger.load(std::memory_order_acquire);
|
|
|
|
if(pLogger)
|
|
|
|
{
|
|
|
|
pLogger->GlobalFinish();
|
|
|
|
}
|
|
|
|
}
|