2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2012-12-06 18:03:12 +00:00
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
2012-11-01 15:19:01 +00:00
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
2017-02-28 00:47:13 +00:00
|
|
|
#include "ppsspp_config.h"
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
#include <algorithm>
|
2020-08-15 14:25:50 +00:00
|
|
|
#include <cstring>
|
2017-03-17 16:57:32 +00:00
|
|
|
|
2020-10-01 11:05:04 +00:00
|
|
|
#include "Common/Data/Encoding/Utf8.h"
|
2020-08-15 16:40:50 +00:00
|
|
|
|
|
|
|
#include "Common/LogManager.h"
|
|
|
|
#include "Common/ConsoleListener.h"
|
2020-10-05 18:58:33 +00:00
|
|
|
#include "Common/TimeUtil.h"
|
2020-10-04 18:48:47 +00:00
|
|
|
#include "Common/File/FileUtil.h"
|
2020-08-15 16:40:50 +00:00
|
|
|
#include "Common/StringUtils.h"
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-03-11 05:25:03 +00:00
|
|
|
// Don't need to savestate this.
|
2017-03-18 09:47:10 +00:00
|
|
|
const char *hleCurrentThreadName = nullptr;
|
|
|
|
|
2020-08-15 16:40:50 +00:00
|
|
|
bool *g_bLogEnabledSetting = nullptr;
|
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
static const char level_to_char[8] = "-NEWIDV";
|
2013-03-11 05:25:03 +00:00
|
|
|
|
2017-02-28 00:47:13 +00:00
|
|
|
#if PPSSPP_PLATFORM(UWP) && defined(_DEBUG)
|
|
|
|
#define LOG_MSC_OUTPUTDEBUG true
|
|
|
|
#else
|
2013-02-27 16:52:51 +00:00
|
|
|
#define LOG_MSC_OUTPUTDEBUG false
|
2017-02-28 00:47:13 +00:00
|
|
|
#endif
|
2013-01-30 06:33:14 +00:00
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char* fmt, ...) {
|
2020-08-15 16:40:50 +00:00
|
|
|
if (g_bLogEnabledSetting && !(*g_bLogEnabledSetting))
|
2015-10-04 09:09:44 +00:00
|
|
|
return;
|
2012-11-01 15:19:01 +00:00
|
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
2015-10-04 09:09:44 +00:00
|
|
|
LogManager *instance = LogManager::GetInstance();
|
|
|
|
if (instance) {
|
|
|
|
instance->Log(level, type, file, line, fmt, args);
|
2020-08-15 14:25:50 +00:00
|
|
|
} else {
|
|
|
|
// Fall back to printf if we're before the log manager has been initialized.
|
|
|
|
vprintf(fmt, args);
|
2020-08-15 22:38:31 +00:00
|
|
|
printf("\n");
|
2015-10-04 09:09:44 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
va_end(args);
|
|
|
|
}
|
|
|
|
|
2015-03-22 07:12:08 +00:00
|
|
|
bool GenericLogEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type) {
|
|
|
|
if (LogManager::GetInstance())
|
2020-08-15 16:40:50 +00:00
|
|
|
return (*g_bLogEnabledSetting) && LogManager::GetInstance()->IsEnabled(level, type);
|
2015-03-22 07:12:08 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-09-07 11:38:37 +00:00
|
|
|
LogManager *LogManager::logManager_ = NULL;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-09-07 10:34:19 +00:00
|
|
|
struct LogNameTableEntry {
|
|
|
|
LogTypes::LOG_TYPE logType;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const LogNameTableEntry logTable[] = {
|
2017-03-06 12:50:22 +00:00
|
|
|
{LogTypes::SYSTEM, "SYSTEM"},
|
|
|
|
{LogTypes::BOOT, "BOOT"},
|
|
|
|
{LogTypes::COMMON, "COMMON"},
|
|
|
|
{LogTypes::CPU, "CPU"},
|
|
|
|
{LogTypes::FILESYS, "FILESYS"},
|
|
|
|
{LogTypes::G3D, "G3D"},
|
|
|
|
{LogTypes::HLE, "HLE"},
|
|
|
|
{LogTypes::JIT, "JIT"},
|
|
|
|
{LogTypes::LOADER, "LOADER"},
|
|
|
|
{LogTypes::ME, "ME"}, // Media Engine
|
|
|
|
{LogTypes::MEMMAP, "MEMMAP"},
|
|
|
|
{LogTypes::SASMIX, "SASMIX"},
|
|
|
|
{LogTypes::SAVESTATE, "SAVESTATE"},
|
2020-08-15 18:02:07 +00:00
|
|
|
{LogTypes::FRAMEBUF, "FRAMEBUF"},
|
2020-08-15 09:51:22 +00:00
|
|
|
{LogTypes::AUDIO, "AUDIO"},
|
|
|
|
{LogTypes::IO, "IO"},
|
2017-03-06 12:50:22 +00:00
|
|
|
|
2017-03-06 12:10:23 +00:00
|
|
|
{LogTypes::SCEAUDIO, "SCEAUDIO"},
|
|
|
|
{LogTypes::SCECTRL, "SCECTRL"},
|
|
|
|
{LogTypes::SCEDISPLAY, "SCEDISP"},
|
|
|
|
{LogTypes::SCEFONT, "SCEFONT"},
|
2018-08-23 01:28:36 +00:00
|
|
|
{LogTypes::SCEGE, "SCEGE"},
|
2017-03-06 12:10:23 +00:00
|
|
|
{LogTypes::SCEINTC, "SCEINTC"},
|
|
|
|
{LogTypes::SCEIO, "SCEIO"},
|
|
|
|
{LogTypes::SCEKERNEL, "SCEKERNEL"},
|
|
|
|
{LogTypes::SCEMODULE, "SCEMODULE"},
|
|
|
|
{LogTypes::SCENET, "SCENET"},
|
|
|
|
{LogTypes::SCERTC, "SCERTC"},
|
|
|
|
{LogTypes::SCESAS, "SCESAS"},
|
|
|
|
{LogTypes::SCEUTILITY, "SCEUTIL"},
|
|
|
|
{LogTypes::SCEMISC, "SCEMISC"},
|
2013-09-07 10:34:19 +00:00
|
|
|
};
|
|
|
|
|
2020-08-15 16:40:50 +00:00
|
|
|
LogManager::LogManager(bool *enabledSetting) {
|
|
|
|
g_bLogEnabledSetting = enabledSetting;
|
|
|
|
|
2013-09-07 10:34:19 +00:00
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(logTable); i++) {
|
2020-08-15 09:51:22 +00:00
|
|
|
_assert_msg_(i == logTable[i].logType, "Bad logtable at %i", (int)i);
|
2017-03-18 09:47:10 +00:00
|
|
|
truncate_cpy(log_[logTable[i].logType].m_shortName, logTable[i].name);
|
|
|
|
log_[logTable[i].logType].enabled = true;
|
|
|
|
#if defined(_DEBUG)
|
|
|
|
log_[logTable[i].logType].level = LogTypes::LDEBUG;
|
|
|
|
#else
|
|
|
|
log_[logTable[i].logType].level = LogTypes::LINFO;
|
|
|
|
#endif
|
2013-09-07 10:34:19 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2017-03-08 13:20:15 +00:00
|
|
|
// Remove file logging on small devices in Release mode.
|
|
|
|
#if PPSSPP_PLATFORM(UWP)
|
|
|
|
if (IsDebuggerPresent())
|
|
|
|
debuggerLog_ = new OutputDebugStringLogListener();
|
|
|
|
#else
|
2017-01-25 15:04:24 +00:00
|
|
|
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
2013-10-17 22:06:45 +00:00
|
|
|
fileLog_ = new FileLogListener("");
|
2013-09-07 11:38:37 +00:00
|
|
|
consoleLog_ = new ConsoleListener();
|
2017-03-08 13:20:15 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
if (IsDebuggerPresent())
|
|
|
|
debuggerLog_ = new OutputDebugStringLogListener();
|
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
2015-01-05 00:23:03 +00:00
|
|
|
ringLog_ = new RingbufferLogListener();
|
2017-03-08 13:20:15 +00:00
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2017-01-25 15:04:24 +00:00
|
|
|
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
2017-03-17 16:57:32 +00:00
|
|
|
AddListener(fileLog_);
|
|
|
|
AddListener(consoleLog_);
|
2017-02-28 00:47:13 +00:00
|
|
|
#if defined(_MSC_VER) && (defined(USING_WIN_UI) || PPSSPP_PLATFORM(UWP))
|
2017-03-08 13:20:15 +00:00
|
|
|
if (IsDebuggerPresent() && debuggerLog_ && LOG_MSC_OUTPUTDEBUG)
|
2017-03-17 16:57:32 +00:00
|
|
|
AddListener(debuggerLog_);
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
2017-03-17 16:57:32 +00:00
|
|
|
AddListener(ringLog_);
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2013-09-07 11:38:37 +00:00
|
|
|
LogManager::~LogManager() {
|
|
|
|
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) {
|
2014-02-08 18:29:22 +00:00
|
|
|
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
2017-03-08 15:00:02 +00:00
|
|
|
RemoveListener(fileLog_);
|
2017-03-17 16:57:32 +00:00
|
|
|
RemoveListener(consoleLog_);
|
2016-01-03 23:10:50 +00:00
|
|
|
#if defined(_MSC_VER) && defined(USING_WIN_UI)
|
2017-03-17 16:57:32 +00:00
|
|
|
RemoveListener(debuggerLog_);
|
2013-02-20 03:12:03 +00:00
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2021-01-01 16:38:27 +00:00
|
|
|
// Make sure we don't shutdown while logging. RemoveListener locks too, but there are gaps.
|
|
|
|
std::lock_guard<std::mutex> listeners_lock(listeners_lock_);
|
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
if (fileLog_)
|
2013-09-07 11:38:37 +00:00
|
|
|
delete fileLog_;
|
2014-02-08 18:29:22 +00:00
|
|
|
#if !defined(MOBILE_DEVICE) || defined(_DEBUG)
|
2013-09-07 11:38:37 +00:00
|
|
|
delete consoleLog_;
|
|
|
|
delete debuggerLog_;
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
2016-02-10 14:22:28 +00:00
|
|
|
delete ringLog_;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-09-07 10:34:19 +00:00
|
|
|
void LogManager::ChangeFileLog(const char *filename) {
|
2017-03-18 09:47:10 +00:00
|
|
|
if (fileLog_) {
|
2017-03-17 16:57:32 +00:00
|
|
|
RemoveListener(fileLog_);
|
2013-09-07 11:38:37 +00:00
|
|
|
delete fileLog_;
|
2018-03-22 21:10:05 +00:00
|
|
|
fileLog_ = nullptr;
|
2012-12-22 17:49:29 +00:00
|
|
|
}
|
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
if (filename) {
|
2013-09-07 11:38:37 +00:00
|
|
|
fileLog_ = new FileLogListener(filename);
|
2017-03-17 16:57:32 +00:00
|
|
|
AddListener(fileLog_);
|
2012-12-22 17:49:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-10 13:53:52 +00:00
|
|
|
void LogManager::SaveConfig(Section *section) {
|
2013-09-07 10:34:19 +00:00
|
|
|
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) {
|
2017-03-18 09:47:10 +00:00
|
|
|
section->Set((std::string(log_[i].m_shortName) + "Enabled").c_str(), log_[i].enabled);
|
|
|
|
section->Set((std::string(log_[i].m_shortName) + "Level").c_str(), (int)log_[i].level);
|
2012-12-06 18:03:12 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2020-08-10 13:53:52 +00:00
|
|
|
void LogManager::LoadConfig(Section *section, bool debugDefaults) {
|
2013-09-07 10:34:19 +00:00
|
|
|
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) {
|
2017-03-06 10:44:35 +00:00
|
|
|
bool enabled = false;
|
|
|
|
int level = 0;
|
2017-03-18 09:47:10 +00:00
|
|
|
section->Get((std::string(log_[i].m_shortName) + "Enabled").c_str(), &enabled, true);
|
|
|
|
section->Get((std::string(log_[i].m_shortName) + "Level").c_str(), &level, debugDefaults ? (int)LogTypes::LDEBUG : (int)LogTypes::LERROR);
|
|
|
|
log_[i].enabled = enabled;
|
|
|
|
log_[i].level = (LogTypes::LOG_LEVELS)level;
|
2012-12-06 18:03:12 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-09-07 10:34:19 +00:00
|
|
|
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char *file, int line, const char *format, va_list args) {
|
2017-03-18 09:47:10 +00:00
|
|
|
const LogChannel &log = log_[type];
|
|
|
|
if (level > log.level || !log.enabled)
|
2012-11-01 15:19:01 +00:00
|
|
|
return;
|
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
LogMessage message;
|
|
|
|
message.level = level;
|
|
|
|
message.log = log.m_shortName;
|
2013-02-02 23:40:48 +00:00
|
|
|
|
2013-03-11 05:25:03 +00:00
|
|
|
#ifdef _WIN32
|
2013-03-11 09:27:28 +00:00
|
|
|
static const char sep = '\\';
|
2013-03-11 05:25:03 +00:00
|
|
|
#else
|
2013-03-11 09:27:28 +00:00
|
|
|
static const char sep = '/';
|
|
|
|
#endif
|
|
|
|
const char *fileshort = strrchr(file, sep);
|
|
|
|
if (fileshort != NULL) {
|
|
|
|
do
|
|
|
|
--fileshort;
|
|
|
|
while (fileshort > file && *fileshort != sep);
|
|
|
|
if (fileshort != file)
|
|
|
|
file = fileshort + 1;
|
|
|
|
}
|
2017-03-18 09:47:10 +00:00
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lk(log_lock_);
|
2020-10-05 18:58:33 +00:00
|
|
|
GetTimeFormatted(message.timestamp);
|
2017-03-18 09:47:10 +00:00
|
|
|
|
|
|
|
if (hleCurrentThreadName) {
|
2018-04-22 00:31:29 +00:00
|
|
|
snprintf(message.header, sizeof(message.header), "%-12.12s %c[%s]: %s:%d",
|
2013-03-11 05:25:03 +00:00
|
|
|
hleCurrentThreadName, level_to_char[(int)level],
|
2017-03-18 09:47:10 +00:00
|
|
|
log.m_shortName,
|
2013-03-11 05:25:03 +00:00
|
|
|
file, line);
|
2013-09-07 11:38:37 +00:00
|
|
|
} else {
|
2018-04-22 00:31:29 +00:00
|
|
|
snprintf(message.header, sizeof(message.header), "%s:%d %c[%s]:",
|
2013-03-11 05:25:03 +00:00
|
|
|
file, line, level_to_char[(int)level],
|
2017-03-18 09:47:10 +00:00
|
|
|
log.m_shortName);
|
2013-03-11 05:25:03 +00:00
|
|
|
}
|
2013-02-02 23:40:48 +00:00
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
char msgBuf[1024];
|
2018-03-22 21:04:49 +00:00
|
|
|
va_list args_copy;
|
|
|
|
|
|
|
|
va_copy(args_copy, args);
|
2017-03-18 09:47:10 +00:00
|
|
|
size_t neededBytes = vsnprintf(msgBuf, sizeof(msgBuf), format, args);
|
2018-04-22 00:31:29 +00:00
|
|
|
message.msg.resize(neededBytes + 1);
|
2017-03-18 09:47:10 +00:00
|
|
|
if (neededBytes > sizeof(msgBuf)) {
|
|
|
|
// Needed more space? Re-run vsnprintf.
|
2018-03-22 21:04:49 +00:00
|
|
|
vsnprintf(&message.msg[0], neededBytes + 1, format, args_copy);
|
2015-10-04 09:09:44 +00:00
|
|
|
} else {
|
2017-03-18 09:47:10 +00:00
|
|
|
memcpy(&message.msg[0], msgBuf, neededBytes);
|
2015-10-04 09:09:44 +00:00
|
|
|
}
|
2018-04-22 00:31:29 +00:00
|
|
|
message.msg[neededBytes] = '\n';
|
2018-03-22 21:04:49 +00:00
|
|
|
va_end(args_copy);
|
2017-03-17 16:57:32 +00:00
|
|
|
|
2017-03-17 17:00:24 +00:00
|
|
|
std::lock_guard<std::mutex> listeners_lock(listeners_lock_);
|
2017-03-18 09:47:10 +00:00
|
|
|
for (auto &iter : listeners_) {
|
|
|
|
iter->Log(message);
|
2017-03-17 17:00:24 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2015-03-22 07:12:08 +00:00
|
|
|
|
|
|
|
bool LogManager::IsEnabled(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type) {
|
2017-03-18 09:47:10 +00:00
|
|
|
LogChannel &log = log_[type];
|
|
|
|
if (level > log.level || !log.enabled)
|
2015-03-22 07:12:08 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2020-08-15 16:40:50 +00:00
|
|
|
void LogManager::Init(bool *enabledSetting) {
|
2021-01-01 16:38:27 +00:00
|
|
|
_assert_(logManager_ == nullptr);
|
2020-08-15 16:40:50 +00:00
|
|
|
logManager_ = new LogManager(enabledSetting);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-09-07 10:34:19 +00:00
|
|
|
void LogManager::Shutdown() {
|
2013-09-07 11:38:37 +00:00
|
|
|
delete logManager_;
|
|
|
|
logManager_ = NULL;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2017-03-17 16:57:32 +00:00
|
|
|
void LogManager::AddListener(LogListener *listener) {
|
2017-03-08 15:00:02 +00:00
|
|
|
if (!listener)
|
|
|
|
return;
|
2017-03-17 17:00:24 +00:00
|
|
|
std::lock_guard<std::mutex> lk(listeners_lock_);
|
2017-03-18 09:47:10 +00:00
|
|
|
listeners_.push_back(listener);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2017-03-17 16:57:32 +00:00
|
|
|
void LogManager::RemoveListener(LogListener *listener) {
|
2017-03-08 15:00:02 +00:00
|
|
|
if (!listener)
|
|
|
|
return;
|
2017-03-17 17:00:24 +00:00
|
|
|
std::lock_guard<std::mutex> lk(listeners_lock_);
|
2017-03-18 09:47:10 +00:00
|
|
|
auto iter = std::find(listeners_.begin(), listeners_.end(), listener);
|
|
|
|
if (iter != listeners_.end())
|
|
|
|
listeners_.erase(iter);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-09-07 10:34:19 +00:00
|
|
|
FileLogListener::FileLogListener(const char *filename) {
|
2017-08-29 20:24:20 +00:00
|
|
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
2013-09-07 10:34:19 +00:00
|
|
|
m_logfile.open(ConvertUTF8ToWString(filename).c_str(), std::ios::app);
|
|
|
|
#else
|
2012-11-01 15:19:01 +00:00
|
|
|
m_logfile.open(filename, std::ios::app);
|
2013-09-07 10:34:19 +00:00
|
|
|
#endif
|
2017-03-18 09:47:10 +00:00
|
|
|
SetEnabled(true);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
void FileLogListener::Log(const LogMessage &message) {
|
2012-11-01 15:19:01 +00:00
|
|
|
if (!IsEnabled() || !IsValid())
|
|
|
|
return;
|
|
|
|
|
2017-02-27 20:57:46 +00:00
|
|
|
std::lock_guard<std::mutex> lk(m_log_lock);
|
2018-04-22 00:31:29 +00:00
|
|
|
m_logfile << message.timestamp << " " << message.header << " " << message.msg << std::flush;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2017-03-08 13:20:15 +00:00
|
|
|
void OutputDebugStringLogListener::Log(const LogMessage &message) {
|
2020-12-20 11:36:32 +00:00
|
|
|
char buffer[4096];
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s %s %s", message.timestamp, message.header, message.msg.c_str());
|
2012-11-01 15:19:01 +00:00
|
|
|
#if _MSC_VER
|
2020-12-20 11:36:32 +00:00
|
|
|
OutputDebugStringUTF8(buffer);
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
}
|
2015-01-05 00:23:03 +00:00
|
|
|
|
2017-03-18 09:47:10 +00:00
|
|
|
void RingbufferLogListener::Log(const LogMessage &message) {
|
2015-01-05 00:23:03 +00:00
|
|
|
if (!enabled_)
|
|
|
|
return;
|
2017-03-18 09:47:10 +00:00
|
|
|
messages_[curMessage_] = message;
|
2015-01-05 00:23:03 +00:00
|
|
|
curMessage_++;
|
|
|
|
if (curMessage_ >= MAX_LOGS)
|
|
|
|
curMessage_ -= MAX_LOGS;
|
|
|
|
count_++;
|
|
|
|
}
|
2020-08-15 14:21:30 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
|
|
void OutputDebugStringUTF8(const char *p) {
|
|
|
|
wchar_t temp[4096];
|
|
|
|
|
|
|
|
int len = std::min(4095, (int)strlen(p));
|
|
|
|
int size = (int)MultiByteToWideChar(CP_UTF8, 0, p, len, NULL, 0);
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, p, len, temp, size);
|
|
|
|
temp[size] = 0;
|
|
|
|
|
|
|
|
OutputDebugString(temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
void OutputDebugStringUTF8(const char *p) {
|
|
|
|
INFO_LOG(SYSTEM, "%s", p);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|