Core: Migrate SDL logging enhancements into core
This commit is contained in:
parent
f4f5521b9b
commit
8997055fc0
@ -36,6 +36,12 @@ struct mLogger {
|
|||||||
struct mLogFilter* filter;
|
struct mLogFilter* filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mStandardLogger {
|
||||||
|
struct mLogger d;
|
||||||
|
bool logToStdout;
|
||||||
|
struct VFile* logFile;
|
||||||
|
};
|
||||||
|
|
||||||
struct mLogger* mLogGetContext(void);
|
struct mLogger* mLogGetContext(void);
|
||||||
void mLogSetDefaultLogger(struct mLogger*);
|
void mLogSetDefaultLogger(struct mLogger*);
|
||||||
int mLogGenerateCategory(const char*, const char*);
|
int mLogGenerateCategory(const char*, const char*);
|
||||||
@ -44,6 +50,10 @@ const char* mLogCategoryId(int);
|
|||||||
int mLogCategoryById(const char*);
|
int mLogCategoryById(const char*);
|
||||||
|
|
||||||
struct mCoreConfig;
|
struct mCoreConfig;
|
||||||
|
void mStandardLoggerInit(struct mStandardLogger*);
|
||||||
|
void mStandardLoggerDeinit(struct mStandardLogger*);
|
||||||
|
void mStandardLoggerConfig(struct mStandardLogger*, struct mCoreConfig* config);
|
||||||
|
|
||||||
void mLogFilterInit(struct mLogFilter*);
|
void mLogFilterInit(struct mLogFilter*);
|
||||||
void mLogFilterDeinit(struct mLogFilter*);
|
void mLogFilterDeinit(struct mLogFilter*);
|
||||||
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);
|
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);
|
||||||
|
@ -21,6 +21,7 @@ struct mCoreThread;
|
|||||||
struct mThreadLogger {
|
struct mThreadLogger {
|
||||||
struct mLogger d;
|
struct mLogger d;
|
||||||
struct mCoreThread* p;
|
struct mCoreThread* p;
|
||||||
|
struct mLogger* logger;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
|
|
||||||
#include <mgba/core/config.h>
|
#include <mgba/core/config.h>
|
||||||
#include <mgba/core/thread.h>
|
#include <mgba/core/thread.h>
|
||||||
|
#include <mgba-util/vfs.h>
|
||||||
|
|
||||||
#define MAX_CATEGORY 64
|
#define MAX_CATEGORY 64
|
||||||
|
#define MAX_LOG_BUF 1024
|
||||||
|
|
||||||
static struct mLogger* _defaultLogger = NULL;
|
static struct mLogger* _defaultLogger = NULL;
|
||||||
|
|
||||||
@ -183,4 +185,63 @@ int mLogFilterLevels(const struct mLogFilter* filter , int category) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _mCoreStandardLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||||
|
struct mStandardLogger* stdlog = (struct mStandardLogger*) logger;
|
||||||
|
|
||||||
|
if (!mLogFilterTest(logger->filter, category, level)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[MAX_LOG_BUF];
|
||||||
|
|
||||||
|
// Prepare the string
|
||||||
|
size_t length = snprintf(buffer, sizeof(buffer), "%s: ", mLogCategoryName(category));
|
||||||
|
if (length < sizeof(buffer)) {
|
||||||
|
length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
|
||||||
|
}
|
||||||
|
if (length < sizeof(buffer)) {
|
||||||
|
length += snprintf(buffer + length, sizeof(buffer) - length, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the length doesn't exceed the size of the buffer when actually writing
|
||||||
|
if (length > sizeof(buffer)) {
|
||||||
|
length = sizeof(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdlog->logToStdout) {
|
||||||
|
printf("%s", buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stdlog->logFile) {
|
||||||
|
stdlog->logFile->write(stdlog->logFile, buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mStandardLoggerInit(struct mStandardLogger* logger) {
|
||||||
|
logger->d.log = _mCoreStandardLog;
|
||||||
|
logger->d.filter = malloc(sizeof(struct mLogFilter));
|
||||||
|
mLogFilterInit(logger->d.filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mStandardLoggerDeinit(struct mStandardLogger* logger) {
|
||||||
|
if (logger->d.filter) {
|
||||||
|
mLogFilterDeinit(logger->d.filter);
|
||||||
|
free(logger->d.filter);
|
||||||
|
logger->d.filter = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mStandardLoggerConfig(struct mStandardLogger* logger, struct mCoreConfig* config) {
|
||||||
|
bool logToFile = false;
|
||||||
|
const char* logFile = mCoreConfigGetValue(config, "logFile");
|
||||||
|
mCoreConfigGetBoolValue(config, "logToStdout", &logger->logToStdout);
|
||||||
|
mCoreConfigGetBoolValue(config, "logToFile", &logToFile);
|
||||||
|
|
||||||
|
if (logToFile && logFile) {
|
||||||
|
logger->logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
mLogFilterLoad(logger->d.filter, config);
|
||||||
|
}
|
||||||
|
|
||||||
mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")
|
mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")
|
||||||
|
@ -253,10 +253,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||||||
core->setSync(core, &threadContext->impl->sync);
|
core->setSync(core, &threadContext->impl->sync);
|
||||||
|
|
||||||
struct mLogFilter filter;
|
struct mLogFilter filter;
|
||||||
if (!threadContext->logger.d.filter) {
|
struct mLogger* logger = &threadContext->logger.d;
|
||||||
threadContext->logger.d.filter = &filter;
|
if (threadContext->logger.logger) {
|
||||||
mLogFilterInit(threadContext->logger.d.filter);
|
logger->filter = threadContext->logger.logger->filter;
|
||||||
mLogFilterLoad(threadContext->logger.d.filter, &core->config);
|
} else {
|
||||||
|
logger->filter = &filter;
|
||||||
|
mLogFilterInit(logger->filter);
|
||||||
|
mLogFilterLoad(logger->filter, &core->config);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_SCRIPTING
|
#ifdef ENABLE_SCRIPTING
|
||||||
@ -431,10 +434,10 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||||||
#endif
|
#endif
|
||||||
core->clearCoreCallbacks(core);
|
core->clearCoreCallbacks(core);
|
||||||
|
|
||||||
if (threadContext->logger.d.filter == &filter) {
|
if (logger->filter == &filter) {
|
||||||
mLogFilterDeinit(&filter);
|
mLogFilterDeinit(&filter);
|
||||||
}
|
}
|
||||||
threadContext->logger.d.filter = NULL;
|
logger->filter = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -444,10 +447,8 @@ bool mCoreThreadStart(struct mCoreThread* threadContext) {
|
|||||||
threadContext->impl->state = mTHREAD_INITIALIZED;
|
threadContext->impl->state = mTHREAD_INITIALIZED;
|
||||||
threadContext->impl->requested = 0;
|
threadContext->impl->requested = 0;
|
||||||
threadContext->logger.p = threadContext;
|
threadContext->logger.p = threadContext;
|
||||||
if (!threadContext->logger.d.log) {
|
threadContext->logger.d.log = _mCoreLog;
|
||||||
threadContext->logger.d.log = _mCoreLog;
|
threadContext->logger.d.filter = NULL;
|
||||||
threadContext->logger.d.filter = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!threadContext->impl->sync.fpsTarget) {
|
if (!threadContext->impl->sync.fpsTarget) {
|
||||||
threadContext->impl->sync.fpsTarget = _defaultFPSTarget;
|
threadContext->impl->sync.fpsTarget = _defaultFPSTarget;
|
||||||
@ -718,14 +719,17 @@ struct mCoreThread* mCoreThreadGet(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||||
UNUSED(logger);
|
struct mThreadLogger* threadLogger = (struct mThreadLogger*) logger;
|
||||||
UNUSED(level);
|
if (level == mLOG_FATAL) {
|
||||||
printf("%s: ", mLogCategoryName(category));
|
mCoreThreadMarkCrashed(threadLogger->p);
|
||||||
vprintf(format, args);
|
}
|
||||||
printf("\n");
|
if (!threadLogger->p->logger.logger) {
|
||||||
struct mCoreThread* thread = mCoreThreadGet();
|
printf("%s: ", mLogCategoryName(category));
|
||||||
if (thread && level == mLOG_FATAL) {
|
vprintf(format, args);
|
||||||
mCoreThreadMarkCrashed(thread);
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
logger = threadLogger->p->logger.logger;
|
||||||
|
logger->log(logger, category, level, format, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -144,19 +144,19 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
|||||||
QMetaObject::invokeMethod(controller, "unpaused");
|
QMetaObject::invokeMethod(controller, "unpaused");
|
||||||
};
|
};
|
||||||
|
|
||||||
m_threadContext.logger.d.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
m_logger.self = this;
|
||||||
mThreadLogger* logContext = reinterpret_cast<mThreadLogger*>(logger);
|
m_logger.log = [](mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||||
mCoreThread* context = logContext->p;
|
CoreLogger* logContext = static_cast<CoreLogger*>(logger);
|
||||||
|
|
||||||
static const char* savestateMessage = "State %i saved";
|
static const char* savestateMessage = "State %i saved";
|
||||||
static const char* loadstateMessage = "State %i loaded";
|
static const char* loadstateMessage = "State %i loaded";
|
||||||
static const char* savestateFailedMessage = "State %i failed to load";
|
static const char* savestateFailedMessage = "State %i failed to load";
|
||||||
static int biosCat = -1;
|
static int biosCat = -1;
|
||||||
static int statusCat = -1;
|
static int statusCat = -1;
|
||||||
if (!context) {
|
if (!logContext) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CoreController* controller = static_cast<CoreController*>(context->userData);
|
CoreController* controller = logContext->self;
|
||||||
QString message;
|
QString message;
|
||||||
if (biosCat < 0) {
|
if (biosCat < 0) {
|
||||||
biosCat = mLogCategoryById("gba.bios");
|
biosCat = mLogCategoryById("gba.bios");
|
||||||
@ -201,10 +201,10 @@ CoreController::CoreController(mCore* core, QObject* parent)
|
|||||||
message = QString::vasprintf(format, args);
|
message = QString::vasprintf(format, args);
|
||||||
QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message));
|
QMetaObject::invokeMethod(controller, "logPosted", Q_ARG(int, level), Q_ARG(int, category), Q_ARG(const QString&, message));
|
||||||
if (level == mLOG_FATAL) {
|
if (level == mLOG_FATAL) {
|
||||||
mCoreThreadMarkCrashed(controller->thread());
|
|
||||||
QMetaObject::invokeMethod(controller, "crashed", Q_ARG(const QString&, message));
|
QMetaObject::invokeMethod(controller, "crashed", Q_ARG(const QString&, message));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
m_threadContext.logger.logger = &m_logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoreController::~CoreController() {
|
CoreController::~CoreController() {
|
||||||
@ -424,7 +424,7 @@ void CoreController::setInputController(InputController* inputController) {
|
|||||||
void CoreController::setLogger(LogController* logger) {
|
void CoreController::setLogger(LogController* logger) {
|
||||||
disconnect(m_log);
|
disconnect(m_log);
|
||||||
m_log = logger;
|
m_log = logger;
|
||||||
m_threadContext.logger.d.filter = logger->filter();
|
m_logger.filter = logger->filter();
|
||||||
connect(this, &CoreController::logPosted, m_log, &LogController::postLog);
|
connect(this, &CoreController::logPosted, m_log, &LogController::postLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +241,9 @@ private:
|
|||||||
void updateROMInfo();
|
void updateROMInfo();
|
||||||
|
|
||||||
mCoreThread m_threadContext{};
|
mCoreThread m_threadContext{};
|
||||||
|
struct CoreLogger : public mLogger {
|
||||||
|
CoreController* self;
|
||||||
|
} m_logger{};
|
||||||
|
|
||||||
bool m_patched = false;
|
bool m_patched = false;
|
||||||
bool m_preload = false;
|
bool m_preload = false;
|
||||||
|
@ -38,19 +38,12 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#define PORT "sdl"
|
#define PORT "sdl"
|
||||||
#define MAX_LOG_BUF 1024
|
|
||||||
|
|
||||||
static void mSDLDeinit(struct mSDLRenderer* renderer);
|
static void mSDLDeinit(struct mSDLRenderer* renderer);
|
||||||
|
|
||||||
static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args);
|
static int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args);
|
||||||
|
|
||||||
static void _setLogger(struct mCore* core);
|
static struct mStandardLogger _logger;
|
||||||
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args);
|
|
||||||
|
|
||||||
static bool _logToStdout = true;
|
|
||||||
static struct VFile* _logFile = NULL;
|
|
||||||
static struct mLogFilter _filter;
|
|
||||||
static struct mLogger _logger;
|
|
||||||
|
|
||||||
static struct VFile* _state = NULL;
|
static struct VFile* _state = NULL;
|
||||||
|
|
||||||
@ -136,6 +129,7 @@ int main(int argc, char** argv) {
|
|||||||
mCoreInitConfig(renderer.core, PORT);
|
mCoreInitConfig(renderer.core, PORT);
|
||||||
mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
|
mArgumentsApply(&args, &subparser, 1, &renderer.core->config);
|
||||||
|
|
||||||
|
mCoreConfigSetDefaultIntValue(&renderer.core->config, "logToStdout", true);
|
||||||
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
|
mCoreConfigLoadDefaults(&renderer.core->config, &opts);
|
||||||
mCoreLoadConfig(renderer.core);
|
mCoreLoadConfig(renderer.core);
|
||||||
|
|
||||||
@ -188,7 +182,8 @@ int main(int argc, char** argv) {
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
// TODO: Use opts and config
|
// TODO: Use opts and config
|
||||||
_setLogger(renderer.core);
|
mStandardLoggerInit(&_logger);
|
||||||
|
mStandardLoggerConfig(&_logger, &renderer.core->config);
|
||||||
ret = mSDLRun(&renderer, &args);
|
ret = mSDLRun(&renderer, &args);
|
||||||
mSDLDetachPlayer(&renderer.events, &renderer.player);
|
mSDLDetachPlayer(&renderer.events, &renderer.player);
|
||||||
mInputMapDeinit(&renderer.core->inputMap);
|
mInputMapDeinit(&renderer.core->inputMap);
|
||||||
@ -198,6 +193,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mSDLDeinit(&renderer);
|
mSDLDeinit(&renderer);
|
||||||
|
mStandardLoggerDeinit(&_logger);
|
||||||
|
|
||||||
mArgumentsDeinit(&args);
|
mArgumentsDeinit(&args);
|
||||||
mCoreConfigFreeOpts(&opts);
|
mCoreConfigFreeOpts(&opts);
|
||||||
@ -273,12 +269,8 @@ int mSDLRun(struct mSDLRenderer* renderer, struct mArguments* args) {
|
|||||||
|
|
||||||
renderer->audio.samples = renderer->core->opts.audioBuffers;
|
renderer->audio.samples = renderer->core->opts.audioBuffers;
|
||||||
renderer->audio.sampleRate = 44100;
|
renderer->audio.sampleRate = 44100;
|
||||||
|
thread.logger.logger = &_logger.d;
|
||||||
struct mThreadLogger threadLogger;
|
|
||||||
threadLogger.d = _logger;
|
|
||||||
threadLogger.p = &thread;
|
|
||||||
thread.logger = threadLogger;
|
|
||||||
|
|
||||||
bool didFail = !mCoreThreadStart(&thread);
|
bool didFail = !mCoreThreadStart(&thread);
|
||||||
|
|
||||||
if (!didFail) {
|
if (!didFail) {
|
||||||
@ -342,63 +334,3 @@ static void mSDLDeinit(struct mSDLRenderer* renderer) {
|
|||||||
|
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _setLogger(struct mCore* core) {
|
|
||||||
int fakeBool = 0;
|
|
||||||
bool logToFile = false;
|
|
||||||
|
|
||||||
if (mCoreConfigGetIntValue(&core->config, "logToStdout", &fakeBool)) {
|
|
||||||
_logToStdout = fakeBool;
|
|
||||||
}
|
|
||||||
if (mCoreConfigGetIntValue(&core->config, "logToFile", &fakeBool)) {
|
|
||||||
logToFile = fakeBool;
|
|
||||||
}
|
|
||||||
const char* logFile = mCoreConfigGetValue(&core->config, "logFile");
|
|
||||||
|
|
||||||
if (logToFile && logFile) {
|
|
||||||
_logFile = VFileOpen(logFile, O_WRONLY | O_CREAT | O_APPEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the filter
|
|
||||||
mLogFilterInit(&_filter);
|
|
||||||
mLogFilterLoad(&_filter, &core->config);
|
|
||||||
|
|
||||||
// Fill the logger
|
|
||||||
_logger.log = _mCoreLog;
|
|
||||||
_logger.filter = &_filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
|
||||||
struct mCoreThread* thread = mCoreThreadGet();
|
|
||||||
if (thread && level == mLOG_FATAL) {
|
|
||||||
mCoreThreadMarkCrashed(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mLogFilterTest(logger->filter, category, level)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[MAX_LOG_BUF];
|
|
||||||
|
|
||||||
// Prepare the string
|
|
||||||
size_t length = snprintf(buffer, sizeof(buffer), "%s: ", mLogCategoryName(category));
|
|
||||||
if (length < sizeof(buffer)) {
|
|
||||||
length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
|
|
||||||
}
|
|
||||||
if (length < sizeof(buffer)) {
|
|
||||||
length += snprintf(buffer + length, sizeof(buffer) - length, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the length doesn't exceed the size of the buffer when actually writing
|
|
||||||
if (length > sizeof(buffer)) {
|
|
||||||
length = sizeof(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_logToStdout) {
|
|
||||||
printf("%s", buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_logFile) {
|
|
||||||
_logFile->write(_logFile, buffer, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user