ppsspp/Common/LogManager.cpp

279 lines
7.9 KiB
C++
Raw Normal View History

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
// 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
// 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/
#include <algorithm>
#include "base/logging.h"
2013-09-07 10:34:19 +00:00
#include "util/text/utf8.h"
2012-11-01 15:19:01 +00:00
#include "LogManager.h"
#include "ConsoleListener.h"
#include "Timer.h"
#include "Thread.h"
#include "FileUtil.h"
#include "../Core/Config.h"
#ifdef __SYMBIAN32__
#include <e32debug.h>
#endif
2012-11-01 15:19:01 +00:00
// Don't need to savestate this.
const char *hleCurrentThreadName = NULL;
// Unfortunately this is quite slow.
2013-02-27 16:52:51 +00:00
#define LOG_MSC_OUTPUTDEBUG false
// #define LOG_MSC_OUTPUTDEBUG true
2012-11-01 15:19:01 +00:00
void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
2013-09-07 10:34:19 +00:00
const char *file, int line, const char* fmt, ...) {
if (!g_Config.bEnableLogging) return;
2012-11-01 15:19:01 +00:00
va_list args;
va_start(args, fmt);
if (LogManager::GetInstance())
LogManager::GetInstance()->Log(level, type,
file, line, fmt, args);
va_end(args);
}
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;
const char *longName;
};
static const LogNameTableEntry logTable[] = {
{LogTypes::MASTER_LOG, "*", "Master Log"},
{LogTypes::BOOT ,"BOOT", "Boot"},
{LogTypes::COMMON ,"COMMON", "Common"},
{LogTypes::CPU ,"CPU", "CPU"},
{LogTypes::LOADER ,"LOAD", "Loader"},
{LogTypes::IO ,"IO", "IO"},
{LogTypes::PAD ,"PAD", "Pad"},
{LogTypes::FILESYS ,"FileSys", "File System"},
{LogTypes::DISCIO ,"DIO", "DiscIO"},
2013-09-07 10:34:19 +00:00
{LogTypes::G3D ,"G3D", "3D Graphics"},
{LogTypes::DMA ,"DMA", "DMA"},
{LogTypes::INTC ,"INTC", "Interrupts"},
{LogTypes::MEMMAP ,"MM", "Memory Map"},
{LogTypes::SOUND ,"SND", "Sound"},
{LogTypes::SASMIX ,"SAS", "Sound Mixer (Sas)"},
{LogTypes::HLE ,"HLE", "HLE"},
{LogTypes::TIMER ,"TMR", "Timer"},
{LogTypes::VIDEO ,"VID", "Video"},
{LogTypes::DYNA_REC ,"Jit", "JIT compiler"},
{LogTypes::NETPLAY ,"NET", "Net play"},
{LogTypes::ME ,"ME", "Media Engine"},
};
LogManager::LogManager() {
for (size_t i = 0; i < ARRAY_SIZE(logTable); i++) {
if (i != logTable[i].logType) {
FLOG("Bad logtable at %i", i);
}
log_[logTable[i].logType] = new LogChannel(logTable[i].name, logTable[i].longName);
2013-09-07 10:34:19 +00:00
}
2012-11-01 15:19:01 +00:00
// Remove file logging on small devices
#if !defined(USING_GLES2) || defined(_DEBUG)
fileLog_ = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
consoleLog_ = new ConsoleListener();
debuggerLog_ = new DebuggerLogListener();
#else
fileLog_ = NULL;
consoleLog_ = NULL;
debuggerLog_ = NULL;
2012-11-01 15:19:01 +00:00
#endif
2013-09-07 10:34:19 +00:00
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) {
log_[i]->SetEnable(true);
#if !defined(USING_GLES2) || defined(_DEBUG)
log_[i]->AddListener(fileLog_);
log_[i]->AddListener(consoleLog_);
2012-11-01 15:19:01 +00:00
#ifdef _MSC_VER
if (IsDebuggerPresent() && debuggerLog_ != NULL && LOG_MSC_OUTPUTDEBUG)
log_[i]->AddListener(debuggerLog_);
2012-11-01 15:19:01 +00:00
#endif
#endif
}
}
LogManager::~LogManager() {
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) {
#if !defined(USING_GLES2) || defined(_DEBUG)
if (fileLog_ != NULL)
logManager_->RemoveListener((LogTypes::LOG_TYPE)i, fileLog_);
logManager_->RemoveListener((LogTypes::LOG_TYPE)i, consoleLog_);
#ifdef _MSC_VER
logManager_->RemoveListener((LogTypes::LOG_TYPE)i, debuggerLog_);
#endif
2012-11-01 15:19:01 +00:00
#endif
}
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
delete log_[i];
if (fileLog_ != NULL)
delete fileLog_;
#if !defined(USING_GLES2) || defined(_DEBUG)
delete consoleLog_;
delete debuggerLog_;
2012-11-01 15:19:01 +00:00
#endif
}
2013-09-07 10:34:19 +00:00
void LogManager::ChangeFileLog(const char *filename) {
if (fileLog_ != NULL) {
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
logManager_->RemoveListener((LogTypes::LOG_TYPE)i, fileLog_);
delete fileLog_;
}
2013-09-07 10:34:19 +00:00
if (filename != NULL) {
fileLog_ = new FileLogListener(filename);
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
log_[i]->AddListener(fileLog_);
}
}
2013-09-07 10:34:19 +00:00
void LogManager::SaveConfig(IniFile::Section *section) {
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) {
section->Set((std::string(log_[i]->GetShortName()) + "Enabled").c_str(), log_[i]->IsEnabled());
section->Set((std::string(log_[i]->GetShortName()) + "Level").c_str(), (int)log_[i]->GetLevel());
}
2012-11-01 15:19:01 +00:00
}
2013-09-07 10:34:19 +00:00
void LogManager::LoadConfig(IniFile::Section *section) {
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++) {
bool enabled;
int level;
section->Get((std::string(log_[i]->GetShortName()) + "Enabled").c_str(), &enabled, true);
section->Get((std::string(log_[i]->GetShortName()) + "Level").c_str(), &level, 0);
log_[i]->SetEnable(enabled);
log_[i]->SetLevel((LogTypes::LOG_LEVELS)level);
}
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) {
std::lock_guard<std::mutex> lk(log_lock_);
2013-01-08 20:24:42 +00:00
2012-11-01 15:19:01 +00:00
char msg[MAX_MSGLEN * 2];
LogChannel *log = log_[type];
2012-11-01 15:19:01 +00:00
if (!log || !log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
return;
static const char level_to_char[8] = "-NEWIDV";
char formattedTime[13];
Common::Timer::GetTimeFormatted(formattedTime);
#ifdef _DEBUG
#ifdef _WIN32
static const char sep = '\\';
#else
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;
}
#endif
char *msgPos = msg;
if (hleCurrentThreadName != NULL) {
msgPos += sprintf(msgPos, "%s %-12.12s %c[%s]: %s:%d ",
formattedTime,
hleCurrentThreadName, level_to_char[(int)level],
log->GetShortName(),
file, line);
} else {
msgPos += sprintf(msgPos, "%s %s:%d %c[%s]: ",
formattedTime,
file, line, level_to_char[(int)level],
log->GetShortName());
}
msgPos += vsnprintf(msgPos, MAX_MSGLEN, format, args);
// This will include the null terminator.
memcpy(msgPos, "\n", sizeof("\n"));
2012-11-01 15:19:01 +00:00
log->Trigger(level, msg);
}
2013-09-07 10:34:19 +00:00
void LogManager::Init() {
logManager_ = new LogManager();
2012-11-01 15:19:01 +00:00
}
2013-09-07 10:34:19 +00:00
void LogManager::Shutdown() {
delete logManager_;
logManager_ = NULL;
2012-11-01 15:19:01 +00:00
}
LogChannel::LogChannel(const char* shortName, const char* fullName, bool enable)
: enable_(enable) {
2012-11-01 15:19:01 +00:00
strncpy(m_fullName, fullName, 128);
strncpy(m_shortName, shortName, 32);
level_ = LogTypes::LDEBUG;
2012-11-01 15:19:01 +00:00
}
// LogContainer
void LogChannel::AddListener(LogListener *listener) {
2012-11-01 15:19:01 +00:00
std::lock_guard<std::mutex> lk(m_listeners_lock);
m_listeners.insert(listener);
}
void LogChannel::RemoveListener(LogListener *listener) {
2012-11-01 15:19:01 +00:00
std::lock_guard<std::mutex> lk(m_listeners_lock);
m_listeners.erase(listener);
}
void LogChannel::Trigger(LogTypes::LOG_LEVELS level, const char *msg) {
#ifdef __SYMBIAN32__
RDebug::Printf("%s",msg);
#else
2012-11-01 15:19:01 +00:00
std::lock_guard<std::mutex> lk(m_listeners_lock);
std::set<LogListener*>::const_iterator i;
2013-09-07 10:34:19 +00:00
for (i = m_listeners.begin(); i != m_listeners.end(); ++i) {
2012-11-01 15:19:01 +00:00
(*i)->Log(level, msg);
}
#endif
2012-11-01 15:19:01 +00:00
}
2013-09-07 10:34:19 +00:00
FileLogListener::FileLogListener(const char *filename) {
#ifdef _WIN32
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
2012-11-01 15:19:01 +00:00
SetEnable(true);
}
2013-09-07 10:34:19 +00:00
void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) {
2012-11-01 15:19:01 +00:00
if (!IsEnabled() || !IsValid())
return;
std::lock_guard<std::mutex> lk(m_log_lock);
m_logfile << msg << std::flush;
}
2013-09-07 10:34:19 +00:00
void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) {
2012-11-01 15:19:01 +00:00
#if _MSC_VER
OutputDebugStringUTF8(msg);
2012-11-01 15:19:01 +00:00
#endif
}