mirror of https://github.com/mgba-emu/mgba.git
Core: Add logging filters
This commit is contained in:
parent
3c0c8a8f54
commit
ad7cb650dc
|
@ -10,6 +10,8 @@
|
|||
|
||||
CXX_GUARD_START
|
||||
|
||||
#include <mgba-util/table.h>
|
||||
|
||||
enum mLogLevel {
|
||||
mLOG_FATAL = 0x01,
|
||||
mLOG_ERROR = 0x02,
|
||||
|
@ -22,8 +24,16 @@ enum mLogLevel {
|
|||
mLOG_ALL = 0x7F
|
||||
};
|
||||
|
||||
struct Table;
|
||||
struct mLogFilter {
|
||||
int defaultLevels;
|
||||
struct Table categories;
|
||||
struct Table levels;
|
||||
};
|
||||
|
||||
struct mLogger {
|
||||
void (*log)(struct mLogger*, int category, enum mLogLevel level, const char* format, va_list args);
|
||||
struct mLogFilter* filter;
|
||||
};
|
||||
|
||||
struct mLogger* mLogGetContext(void);
|
||||
|
@ -33,6 +43,13 @@ const char* mLogCategoryName(int);
|
|||
const char* mLogCategoryId(int);
|
||||
int mLogCategoryById(const char*);
|
||||
|
||||
struct mCoreConfig;
|
||||
void mLogFilterInit(struct mLogFilter*);
|
||||
void mLogFilterDeinit(struct mLogFilter*);
|
||||
void mLogFilterLoad(struct mLogFilter*, const struct mCoreConfig*);
|
||||
void mLogFilterSet(struct mLogFilter*, const char* category, int levels);
|
||||
bool mLogFilterTest(struct mLogFilter*, int category, enum mLogLevel level);
|
||||
|
||||
ATTRIBUTE_FORMAT(printf, 3, 4)
|
||||
void mLog(int category, enum mLogLevel level, const char* format, ...);
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ struct mCoreThread {
|
|||
bool frameWasOn;
|
||||
|
||||
struct mThreadLogger logger;
|
||||
enum mLogLevel logLevel;
|
||||
ThreadCallback startCallback;
|
||||
ThreadCallback resetCallback;
|
||||
ThreadCallback cleanCallback;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include <mgba/core/log.h>
|
||||
|
||||
#include <mgba/core/config.h>
|
||||
#include <mgba/core/thread.h>
|
||||
|
||||
#define MAX_CATEGORY 64
|
||||
|
@ -36,7 +37,7 @@ int mLogGenerateCategory(const char* name, const char* id) {
|
|||
_categoryIds[_category] = id;
|
||||
}
|
||||
++_category;
|
||||
return _category;
|
||||
return _category - 1;
|
||||
}
|
||||
|
||||
const char* mLogCategoryName(int category) {
|
||||
|
@ -68,7 +69,9 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) {
|
|||
va_list args;
|
||||
va_start(args, format);
|
||||
if (context) {
|
||||
context->log(context, category, level, format, args);
|
||||
if (!context->filter || mLogFilterTest(context->filter, category, level)) {
|
||||
context->log(context, category, level, format, args);
|
||||
}
|
||||
} else {
|
||||
printf("%s: ", mLogCategoryName(category));
|
||||
vprintf(format, args);
|
||||
|
@ -77,4 +80,67 @@ void mLog(int category, enum mLogLevel level, const char* format, ...) {
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void mLogFilterInit(struct mLogFilter* filter) {
|
||||
HashTableInit(&filter->categories, 8, NULL);
|
||||
TableInit(&filter->levels, 8, NULL);
|
||||
}
|
||||
|
||||
void mLogFilterDeinit(struct mLogFilter* filter) {
|
||||
HashTableDeinit(&filter->categories);
|
||||
TableDeinit(&filter->levels);
|
||||
}
|
||||
|
||||
static void _setFilterLevel(const char* key, const char* value, enum mCoreConfigLevel level, void* user) {
|
||||
UNUSED(level);
|
||||
struct mLogFilter* filter = user;
|
||||
key = strchr(key, '.');
|
||||
if (!key || !key[1]) {
|
||||
return;
|
||||
}
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
++key;
|
||||
char* end;
|
||||
int ivalue = strtol(value, &end, 10);
|
||||
if (ivalue == 0) {
|
||||
ivalue = INT_MIN; // Zero is reserved
|
||||
}
|
||||
if (!end) {
|
||||
return;
|
||||
}
|
||||
mLogFilterSet(filter, key, ivalue);
|
||||
}
|
||||
|
||||
void mLogFilterLoad(struct mLogFilter* filter, const struct mCoreConfig* config) {
|
||||
mCoreConfigEnumerate(config, "logLevel.", _setFilterLevel, filter);
|
||||
filter->defaultLevels = mLOG_ALL;
|
||||
mCoreConfigGetIntValue(config, "logLevel", &filter->defaultLevels);
|
||||
}
|
||||
|
||||
void mLogFilterSet(struct mLogFilter* filter, const char* category, int levels) {
|
||||
HashTableInsert(&filter->categories, category, (void*)(intptr_t) levels);
|
||||
// Can't do this eagerly because not all categories are initialized immediately
|
||||
int cat = mLogCategoryById(category);
|
||||
if (cat >= 0) {
|
||||
TableInsert(&filter->levels, cat, (void*)(intptr_t) levels);
|
||||
}
|
||||
|
||||
}
|
||||
bool mLogFilterTest(struct mLogFilter* filter, int category, enum mLogLevel level) {
|
||||
int value = (int) TableLookup(&filter->levels, category);
|
||||
if (value) {
|
||||
return value & level;
|
||||
}
|
||||
const char* cat = mLogCategoryId(category);
|
||||
if (cat) {
|
||||
value = (int) HashTableLookup(&filter->categories, cat);
|
||||
if (value) {
|
||||
TableInsert(&filter->levels, category, (void*)(intptr_t) value);
|
||||
return value & level;
|
||||
}
|
||||
}
|
||||
return level & filter->defaultLevels;
|
||||
}
|
||||
|
||||
mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")
|
||||
|
|
|
@ -36,6 +36,8 @@ static BOOL CALLBACK _createTLS(PINIT_ONCE once, PVOID param, PVOID* context) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args);
|
||||
|
||||
static void _changeState(struct mCoreThread* threadContext, enum mCoreThreadState newState, bool broadcast) {
|
||||
MutexLock(&threadContext->stateMutex);
|
||||
threadContext->state = newState;
|
||||
|
@ -147,6 +149,13 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
core->setSync(core, &threadContext->sync);
|
||||
core->reset(core);
|
||||
|
||||
struct mLogFilter filter;
|
||||
if (!threadContext->logger.d.filter) {
|
||||
threadContext->logger.d.filter = &filter;
|
||||
mLogFilterInit(threadContext->logger.d.filter);
|
||||
mLogFilterLoad(threadContext->logger.d.filter, &core->config);
|
||||
}
|
||||
|
||||
if (core->opts.rewindEnable && core->opts.rewindBufferCapacity > 0) {
|
||||
mCoreRewindContextInit(&threadContext->rewind, core->opts.rewindBufferCapacity);
|
||||
threadContext->rewind.stateFlags = core->opts.rewindSave ? SAVESTATE_SAVEDATA : 0;
|
||||
|
@ -225,13 +234,18 @@ static THREAD_ENTRY _mCoreThreadRun(void* context) {
|
|||
}
|
||||
core->clearCoreCallbacks(core);
|
||||
|
||||
threadContext->logger.d.filter = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool mCoreThreadStart(struct mCoreThread* threadContext) {
|
||||
threadContext->state = THREAD_INITIALIZED;
|
||||
threadContext->logger.p = threadContext;
|
||||
threadContext->logLevel = threadContext->core->opts.logLevel;
|
||||
if (!threadContext->logger.d.log) {
|
||||
threadContext->logger.d.log = _mCoreLog;
|
||||
threadContext->logger.d.filter = NULL;
|
||||
}
|
||||
|
||||
if (!threadContext->sync.fpsTarget) {
|
||||
threadContext->sync.fpsTarget = _defaultFPSTarget;
|
||||
|
@ -544,10 +558,7 @@ struct mCoreThread* mCoreThreadGet(void) {
|
|||
|
||||
static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level, const char* format, va_list args) {
|
||||
UNUSED(logger);
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
if (thread && !(thread->logLevel & level)) {
|
||||
return;
|
||||
}
|
||||
UNUSED(level);
|
||||
printf("%s: ", mLogCategoryName(category));
|
||||
vprintf(format, args);
|
||||
printf("\n");
|
||||
|
@ -556,9 +567,6 @@ static void _mCoreLog(struct mLogger* logger, int category, enum mLogLevel level
|
|||
struct mLogger* mCoreThreadLogger(void) {
|
||||
struct mCoreThread* thread = mCoreThreadGet();
|
||||
if (thread) {
|
||||
if (!thread->logger.d.log) {
|
||||
thread->logger.d.log = _mCoreLog;
|
||||
}
|
||||
return &thread->logger.d;
|
||||
}
|
||||
return NULL;
|
||||
|
|
Loading…
Reference in New Issue