/* Copyright (c) 2013-2016 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #define MAX_CATEGORY 64 static struct mLogger* _defaultLogger = NULL; struct mLogger* mLogGetContext(void) { struct mLogger* logger = NULL; #ifndef DISABLE_THREADING logger = mCoreThreadLogger(); #endif if (logger) { return logger; } return _defaultLogger; } void mLogSetDefaultLogger(struct mLogger* logger) { _defaultLogger = logger; } static int _category = 0; static const char* _categoryNames[MAX_CATEGORY]; static const char* _categoryIds[MAX_CATEGORY]; int mLogGenerateCategory(const char* name, const char* id) { if (_category < MAX_CATEGORY) { _categoryNames[_category] = name; _categoryIds[_category] = id; } ++_category; return _category - 1; } const char* mLogCategoryName(int category) { if (category < MAX_CATEGORY) { return _categoryNames[category]; } return NULL; } const char* mLogCategoryId(int category) { if (category < MAX_CATEGORY) { return _categoryIds[category]; } return NULL; } int mLogCategoryById(const char* id) { int i; for (i = 0; i < _category; ++i) { if (strcmp(_categoryIds[i], id) == 0) { return i; } } return -1; } void mLog(int category, enum mLogLevel level, const char* format, ...) { struct mLogger* context = mLogGetContext(); va_list args; va_start(args, format); if (context) { if (!context->filter || mLogFilterTest(context->filter, category, level)) { context->log(context, category, level, format, args); } } else { printf("%s: ", mLogCategoryName(category)); vprintf(format, args); printf("\n"); } 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 = 0x80; // Zero is reserved } if (!end) { return; } mLogFilterSet(filter, key, ivalue); } void mLogFilterLoad(struct mLogFilter* filter, const struct mCoreConfig* config) { HashTableClear(&filter->categories); TableClear(&filter->levels); mCoreConfigEnumerate(config, "logLevel.", _setFilterLevel, filter); filter->defaultLevels = mLOG_ALL; mCoreConfigGetIntValue(config, "logLevel", &filter->defaultLevels); } void mLogFilterSave(const struct mLogFilter* filter, struct mCoreConfig* config) { mCoreConfigSetIntValue(config, "logLevel", filter->defaultLevels); int i; for (i = 0; i < _category; ++i) { char configName[128] = {0}; snprintf(configName, sizeof(configName) - 1, "logLevel.%s", mLogCategoryId(i)); int levels = mLogFilterLevels(filter, i); if (levels) { mCoreConfigSetIntValue(config, configName, levels & ~0x80); } else { mCoreConfigSetValue(config, configName, NULL); } } } void mLogFilterSet(struct mLogFilter* filter, const char* category, int levels) { levels |= 0x80; 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); } } void mLogFilterReset(struct mLogFilter* filter, const char* category) { HashTableRemove(&filter->categories, category); // Can't do this eagerly because not all categories are initialized immediately int cat = mLogCategoryById(category); if (cat >= 0) { TableRemove(&filter->levels, cat); } } bool mLogFilterTest(const struct mLogFilter* filter, int category, enum mLogLevel level) { int value = mLogFilterLevels(filter, category); if (value) { return value & level; } return level & filter->defaultLevels; } int mLogFilterLevels(const struct mLogFilter* filter , int category) { int value = (intptr_t) TableLookup(&filter->levels, category); if (value) { return value; } const char* cat = mLogCategoryId(category); if (cat) { value = (intptr_t) HashTableLookup(&filter->categories, cat); } return value; } mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")