Implement setting log mask string on a destination.

Improve logging docs
This commit is contained in:
Nils O. Selåsdal
2013-06-12 21:50:59 +02:00
parent 504ee1315b
commit 74b59a3a38
4 changed files with 194 additions and 17 deletions
+51 -2
View File
@@ -58,6 +58,13 @@
* And the resulting log line will include the short_name * And the resulting log line will include the short_name
* modules[DB].short_name * modules[DB].short_name
* *
* Log levels of the messages logged are checked first
* by the log_level of the uc_log_destination, and then
* by the log_level of the module for that destination.
*
* Thus for a message to actually be logged the level
* must be above the overall log level for the destination and
* the log level of the module.
*/ */
#ifdef __cplusplus #ifdef __cplusplus
@@ -93,7 +100,11 @@ enum UC_LOG_DESTINATION {
struct uc_log_module { struct uc_log_module {
/** The id of the log module. /** The id of the log module.
* This is the id one specifies in the various log * This is the id one specifies in the various log
* functions/macros*/ * functions/macros.
* Within the struct uc_log_modules, this id must start
* at 0 and be incremented consecutively, being equal
* to the index within struct uc_log_modules.mods
*/
int id; int id;
/** A short name for the module. /** A short name for the module.
@@ -103,7 +114,8 @@ struct uc_log_module {
const char *long_name; const char *long_name;
/** The log level of this module. Only /** The log level of this module. Only
* log statements with a level >= the log_level * log statements with a level >= the log_level
* are actually logged */ * are actually logged, but the log_level of a destination
* can restrict the logging further*/
int log_level; int log_level;
}; };
@@ -202,6 +214,43 @@ void uc_log_destination_set_log_location(struct uc_log_destination *dest, int lo
void uc_log_delete_destination(struct uc_log_destination *dest); void uc_log_delete_destination(struct uc_log_destination *dest);
/** Set the log level for a particular module on this destination
*
* @param dest destination to chang
* @param moudle the module id to change
* @param log_level new log level to set for the module
*/
void uc_log_destination_set_module_loglevel(
struct uc_log_destination *dest,
int module,
enum UC_LOG_LEVEL log_level
);
/** Set the log mask for the given destination.
* The log_mask is a string specifying the log levels for
* the modules logged by this destination.
* The log_level of the destination itself takes priority
* over the log_level of the modules.
* The format of the log_mask string is.
*
* SHORT_NAME_1=LEVEL:SHORT_NAME_2=LEVEL:SHORT_NAME_N=LEVEL
*
* The SHORT_NAME_N is the .short_name within a struct uc_log_module
* LEVEL is one of DEBUG,INFO, WARNING or ERROR
* Example:
* DB=DEBUG:IO=ERROR:POLLER=INFO
*
* Modules not mentioned in the string retain their default value.
* No whitespaces must be specifed before/after the : or = character
*
* @param dest destination to set the log mask on
* @parama log_mask the log mask as described above to set.
*/
void uc_log_destination_set_mask(
struct uc_log_destination *dest,
const char *log_mask
);
/** Closes and re-opens all the UC_LDEST_FILE log destinations. /** Closes and re-opens all the UC_LDEST_FILE log destinations.
* Intended for use when a log file is rotated externally. * Intended for use when a log file is rotated externally.
* *
+80 -8
View File
@@ -67,12 +67,12 @@ static const struct uc_log_module g_unknown_module = {
static SLIST_HEAD(, uc_log_destination) g_destinations; static SLIST_HEAD(, uc_log_destination) g_destinations;
static int uc_log_reopen_file(struct uc_log_destination *dest); static int uc_log_reopen_file(struct uc_log_destination *dest);
//Uses enum UC_LOG_LEVEL as index //Uses enum UC_LOG_LEVEL as index
static const char *const g_debug_levels[] = { static const char *const g_log_levels[] = {
"NONE", "NONE",
"DEBUG", "DEBUG",
"UNKNOWN_2", "UNKNOWN_2",
"INFO", "INFO",
"UNKNOWN_4" "UNKNOWN_4",
"WARNING", "WARNING",
"UNKNOWN_6", "UNKNOWN_6",
"ERROR" "ERROR"
@@ -80,20 +80,20 @@ static const char *const g_debug_levels[] = {
inline const char *uc_ll_2_str(enum UC_LOG_LEVEL l) inline const char *uc_ll_2_str(enum UC_LOG_LEVEL l)
{ {
if (l < ARRAY_SIZE(g_debug_levels)) { if (l < ARRAY_SIZE(g_log_levels)) {
return g_debug_levels[l]; return g_log_levels[l];
} else { } else {
return "???"; return "???";
} }
} }
//returns if the string is not a known log level //returns if the string is not a known log level
static int uc_str_2_ll(const char *str) static int uc_str_2_ll(const char *str, size_t len)
{ {
size_t i; size_t i;
for (i = 0; i < ARRAY_SIZE(g_debug_levels); i++) { for (i = 0; i < ARRAY_SIZE(g_log_levels); i++) {
if (strcmp(str, g_debug_levels[i]) == 0) { if (strncasecmp(str, g_log_levels[i], len) == 0) {
return (int)i; return (int)i;
} }
} }
@@ -411,7 +411,6 @@ static inline void uc_vlog_file(const struct uc_log_args *args, const char *fmt,
time_buf[sizeof time_buf -1] = 0; time_buf[sizeof time_buf -1] = 0;
if (dest->log_location) { if (dest->log_location) {
fprintf(dest->type.file.file, "[%-7s] %s %s:%d [%s] : ", fprintf(dest->type.file.file, "[%-7s] %s %s:%d [%s] : ",
uc_ll_2_str(args->log_level), time_buf, args->file, uc_ll_2_str(args->log_level), time_buf, args->file,
@@ -467,6 +466,79 @@ log:
} }
} }
void uc_log_destination_set_module_loglevel(
struct uc_log_destination *dest,
int module,
enum UC_LOG_LEVEL log_level
)
{
if (dest == NULL)
return;
pthread_mutex_lock(&g_log_lock);
if (module >= 0 && module < g_modules.cnt)
dest->module_settings[module].log_level = log_level;
pthread_mutex_unlock(&g_log_lock);
}
void uc_log_destination_set_mask(
struct uc_log_destination *dest,
const char *log_mask
)
{
size_t module_len;
if (dest == NULL || log_mask == NULL)
return;
pthread_mutex_lock(&g_log_lock);
while ((module_len = strcspn(log_mask, "=")) != 0) {
int i;
int level_len;
const char *level_str;
int log_level;
const char *module_str = log_mask;
log_mask += module_len;
if (log_mask[0] == '=')
log_mask++;
level_len = strcspn(log_mask, ":");
if (level_len == 0)
continue;
level_str = log_mask;
log_mask += level_len;
if (log_mask[0] == ':')
log_mask++;
log_level = uc_str_2_ll(level_str, level_len);
if (log_level == -1)
continue;
for (i = 0; i < g_modules.cnt; i++) {
size_t short_name_len;;
if (g_modules.mods[i].short_name == NULL)
continue;
short_name_len = strlen(g_modules.mods[i].short_name);
module_len = UC_MAX(module_len, short_name_len);
if (strncasecmp(g_modules.mods[i].short_name,
module_str, module_len) == 0) {
dest->module_settings[i].log_level = log_level;
}
}
}
pthread_mutex_unlock(&g_log_lock);
}
void uc_logf(int log_level, int module, int raw, void uc_logf(int log_level, int module, int raw,
const char *file, int line, const char *fmt, ...) const char *file, int line, const char *fmt, ...)
{ {
+10 -4
View File
@@ -37,25 +37,31 @@ int main(int argc, char *argv[])
{ {
struct uc_log_destination *dest; struct uc_log_destination *dest;
uc_log_init(&modules); uc_log_init(&modules);
dest = uc_log_new_stderr(UC_LL_INFO, 0);
uc_log_add_destination(dest);
dest = uc_log_new_file("test.log", UC_LL_INFO, 1); dest = uc_log_new_file("test.log", UC_LL_INFO, 1);
uc_log_add_destination(dest); uc_log_add_destination(dest);
dest = uc_log_new_syslog("log.test", LOG_DAEMON, UC_LL_INFO, 0); dest = uc_log_new_syslog("log.test", LOG_DAEMON, UC_LL_INFO, 0);
uc_log_add_destination(dest); uc_log_add_destination(dest);
dest = uc_log_new_stderr(UC_LL_INFO, 0);
uc_log_add_destination(dest);
UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 2); UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 2);
UC_LOGF( UC_LL_WARNING, HO, "Test HO warning%d\n", 2); UC_LOGF( UC_LL_WARNING, HO, "Test HO warning%d\n", 2);
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN info \n" ); UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN info \n" );
UC_LOGF( UC_LL_WARNING, MAIN, "Test MAIN warning\n" ); UC_LOGF( UC_LL_WARNING, MAIN, "Test MAIN warning\n" );
uc_log_module_set_loglevel(MAIN, UC_LL_INFO); uc_log_destination_set_module_loglevel(dest, MAIN, UC_LL_INFO);
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN INFO 2\n" ); UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN INFO 2\n" );
UC_LOGFR(UC_LL_INFO, MAIN, "Test RAW logging 1\n" ); UC_LOGFR(UC_LL_INFO, MAIN, "Test RAW logging 1\n" );
uc_log_module_set_loglevel(MAIN, UC_LL_WARNING); uc_log_destination_set_module_loglevel(dest,MAIN, UC_LL_WARNING);
UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN INFO 3\n" ); UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN INFO 3\n" );
uc_log_destination_set_loglevel(dest, UC_LL_DEBUG);
UC_LOGF( UC_LL_DEBUG, MAIN, "Test MAIN DEBUG SHOULD NOT SHOW\n" );
//uc_log_destination_set_module_loglevel(dest, MAIN, UC_LL_INFO);
uc_log_destination_set_mask(dest, "HO=ERROR:MAIN=DEBUG:HO=DEBUG");
UC_LOGF( UC_LL_DEBUG, MAIN, "Test MAIN DEBUG SHOULD SHOW\n" );
uc_log_delete_destination(dest); uc_log_delete_destination(dest);
+51 -1
View File
@@ -53,10 +53,13 @@ START_TEST (test_logfile_location)
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n"); UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n");
UC_LOGF(UC_LL_INFO, 0, "Lorum ipson 3\n");
UC_LOGF(UC_LL_WARNING, 0, "Lorum ipson 4\n");
UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5\n");
rc = stat(FILE_NAME, &st); rc = stat(FILE_NAME, &st);
fail_if(rc != 0, "stat failed: %s\n", strerror(errno)); fail_if(rc != 0, "stat failed: %s\n", strerror(errno));
fail_if(st.st_size != 76*2, "was %ld\n", (long)st.st_size); fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size);
END_TEST END_TEST
START_TEST (test_logfile_no_location) START_TEST (test_logfile_no_location)
@@ -361,6 +364,52 @@ START_TEST (test_logfile_raw)
fail_if(st.st_size != 14*2, "was %ld\n", (long)st.st_size); fail_if(st.st_size != 14*2, "was %ld\n", (long)st.st_size);
END_TEST END_TEST
START_TEST (test_logfile_dest_mask)
struct uc_log_module m[] = {
{
.id = 0,
.short_name = "MOD1",
.long_name = "Module 1",
.log_level = UC_LL_WARNING,
},
{
.id = 1,
.short_name = "MOD2",
.long_name = "Module 2",
.log_level = UC_LL_WARNING,
}
};
struct uc_log_modules mods = {
.mods = m,
.cnt = 2,
};
struct stat st;
struct uc_log_destination *dest;
int rc;
uc_log_init(&mods);
dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1);
fail_if(dest == NULL);
uc_log_add_destination(dest);
UC_LOGFR(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
UC_LOGFR(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
rc = stat(FILE_NAME, &st);
fail_if(rc != 0, "stat failed: %s\n", strerror(errno));
fail_if(st.st_size != 0, "was %ld\n", (long)st.st_size);
uc_log_destination_set_mask(dest, "MOD1=DEBUG:mod2=Debug");
UC_LOGFR(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1);
UC_LOGFR(UC_LL_DEBUG, 1, "Lorum ipson %d\n", 1);
rc = stat(FILE_NAME, &st);
fail_if(rc != 0, "stat failed: %s\n", strerror(errno));
fail_if(st.st_size != 14*2, "was %ld\n", (long)st.st_size);
END_TEST
Suite *logging_suite(void) Suite *logging_suite(void)
{ {
@@ -374,6 +423,7 @@ Suite *logging_suite(void)
tcase_add_test(tc1, test_logfile_loglevel_surpressed_module); tcase_add_test(tc1, test_logfile_loglevel_surpressed_module);
tcase_add_test(tc1, test_logfile_reopen_files); tcase_add_test(tc1, test_logfile_reopen_files);
tcase_add_test(tc1, test_logfile_remove_dest); tcase_add_test(tc1, test_logfile_remove_dest);
tcase_add_test(tc1, test_logfile_dest_mask);
if (access("/dev/full", R_OK) == 0) { if (access("/dev/full", R_OK) == 0) {
tcase_add_test(tc1, test_logfile_full_filesystem); tcase_add_test(tc1, test_logfile_full_filesystem);