X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fvlog.c;h=ddfab7614b37bbfa53a6931e949ab74112fd5b5e;hb=b6eb6bc746ebeee6027929e142f00b72fef57656;hp=756433ca3f096e216f403dc1123fe584503742ba;hpb=278ae88d5f49249f247db3ad890bf1e97123f51c;p=sliver-openvswitch.git diff --git a/lib/vlog.c b/lib/vlog.c index 756433ca3..ddfab7614 100644 --- a/lib/vlog.c +++ b/lib/vlog.c @@ -43,6 +43,7 @@ #include #include #include +#include "dirs.h" #include "dynamic-string.h" #include "sat-math.h" #include "timeval.h" @@ -93,6 +94,10 @@ enum vlog_level min_vlog_levels[VLM_N_MODULES]; /* Time at which vlog was initialized, in milliseconds. */ static long long int boot_time; +/* VLF_FILE configuration. */ +static char *log_file_name; +static FILE *log_file; + /* Searches the 'n_names' in 'names'. Returns the index of a match for * 'target', or 'n_names' if no name matches. */ static size_t @@ -179,7 +184,9 @@ update_min_level(enum vlog_module module) enum vlog_facility facility; for (facility = 0; facility < VLF_N_FACILITIES; facility++) { - min_level = MAX(min_level, levels[module][facility]); + if (log_file || facility != VLF_FILE) { + min_level = MAX(min_level, levels[module][facility]); + } } min_vlog_levels[module] = min_level; } @@ -243,6 +250,71 @@ vlog_set_pattern(enum vlog_facility facility, const char *pattern) } } +/* Returns the name of the log file used by VLF_FILE, or a null pointer if no + * log file has been set. (A non-null return value does not assert that the + * named log file is in use: if vlog_set_log_file() or vlog_reopen_log_file() + * fails, it still sets the log file name.) */ +const char * +vlog_get_log_file(void) +{ + return log_file_name; +} + +/* Sets the name of the log file used by VLF_FILE to 'file_name', or to the + * default file name if 'file_name' is null. Returns 0 if successful, + * otherwise a positive errno value. */ +int +vlog_set_log_file(const char *file_name) +{ + char *old_log_file_name; + enum vlog_module module; + int error; + + /* Close old log file. */ + if (log_file) { + VLOG_WARN("closing log file"); + fclose(log_file); + log_file = NULL; + } + + /* Update log file name and free old name. The ordering is important + * because 'file_name' might be 'log_file_name' or some suffix of it. */ + old_log_file_name = log_file_name; + log_file_name = (file_name + ? xstrdup(file_name) + : xasprintf("%s/%s.log", ofp_logdir, program_name)); + free(old_log_file_name); + file_name = NULL; /* Might have been freed. */ + + /* Open new log file and update min_levels[] to reflect whether we actually + * have a log_file. */ + log_file = fopen(log_file_name, "a"); + for (module = 0; module < VLM_N_MODULES; module++) { + update_min_level(module); + } + + /* Log success or failure. */ + if (!log_file) { + VLOG_WARN("failed to open %s for logging: %s", + log_file_name, strerror(errno)); + error = errno; + } else { + VLOG_WARN("opened log file %s", log_file_name); + error = 0; + } + + return error; +} + +/* Closes and then attempts to re-open the current log file. (This is useful + * just after log rotation, to ensure that the new log file starts being used.) + * Returns 0 if successful, otherwise a positive errno value. */ +int +vlog_reopen_log_file(void) +{ + return vlog_set_log_file(log_file_name); +} + /* Set debugging levels: * * mod[:facility[:level]] mod2[:facility[:level]] ... @@ -358,14 +430,15 @@ vlog_get_levels(void) struct ds s = DS_EMPTY_INITIALIZER; enum vlog_module module; - ds_put_format(&s, " console syslog\n"); - ds_put_format(&s, " ------- ------\n"); + ds_put_format(&s, " console syslog file\n"); + ds_put_format(&s, " ------- ------ ------\n"); for (module = 0; module < VLM_N_MODULES; module++) { - ds_put_format(&s, "%-16s %4s %4s\n", + ds_put_format(&s, "%-16s %4s %4s %4s\n", vlog_get_module_name(module), vlog_get_level_name(vlog_get_level(module, VLF_CONSOLE)), - vlog_get_level_name(vlog_get_level(module, VLF_SYSLOG))); + vlog_get_level_name(vlog_get_level(module, VLF_SYSLOG)), + vlog_get_level_name(vlog_get_level(module, VLF_FILE))); } return ds_cstr(&s); @@ -489,9 +562,10 @@ void vlog_valist(enum vlog_module module, enum vlog_level level, const char *message, va_list args) { - bool log_console = levels[module][VLF_CONSOLE] >= level; - bool log_syslog = levels[module][VLF_SYSLOG] >= level; - if (log_console || log_syslog) { + bool log_to_console = levels[module][VLF_CONSOLE] >= level; + bool log_to_syslog = levels[module][VLF_SYSLOG] >= level; + bool log_to_file = levels[module][VLF_FILE] >= level && log_file; + if (log_to_console || log_to_syslog || log_to_file) { int save_errno = errno; static unsigned int msg_num; struct ds s; @@ -500,14 +574,14 @@ vlog_valist(enum vlog_module module, enum vlog_level level, ds_reserve(&s, 1024); msg_num++; - if (log_console) { + if (log_to_console) { format_log_message(module, level, VLF_CONSOLE, msg_num, message, args, &s); ds_put_char(&s, '\n'); fputs(ds_cstr(&s), stderr); } - if (log_syslog) { + if (log_to_syslog) { int syslog_level = syslog_levels[level]; char *save_ptr = NULL; char *line; @@ -520,6 +594,14 @@ vlog_valist(enum vlog_module module, enum vlog_level level, } } + if (log_to_file) { + format_log_message(module, level, VLF_FILE, msg_num, + message, args, &s); + ds_put_char(&s, '\n'); + fputs(ds_cstr(&s), log_file); + fflush(log_file); + } + ds_destroy(&s); errno = save_errno; } @@ -578,3 +660,14 @@ vlog_rate_limit(enum vlog_module module, enum vlog_level level, rl->n_dropped = 0; } } + +void +vlog_usage(void) +{ + printf("\nLogging options:\n" + " -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n" + " -v, --verbose set maximum verbosity level\n" + " --log-file[=FILE] enable logging to specified FILE\n" + " (default: %s/%s.log)\n", + ofp_logdir, program_name); +}