Core: Add logging filters

This commit is contained in:
Vicki Pfau 2017-03-05 17:25:35 -08:00
parent 3c0c8a8f54
commit ad7cb650dc
4 changed files with 101 additions and 11 deletions

View File

@ -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, ...);

View File

@ -58,7 +58,6 @@ struct mCoreThread {
bool frameWasOn;
struct mThreadLogger logger;
enum mLogLevel logLevel;
ThreadCallback startCallback;
ThreadCallback resetCallback;
ThreadCallback cleanCallback;

View File

@ -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")

View File

@ -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;