rhel: openvswitch.spec.in: fix perms on logrotate and sysconfig.template
[sliver-openvswitch.git] / lib / vlog.c
index ddda266..11b2f7c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <syslog.h>
 #include <time.h>
 #include "dirs.h"
 #include "dynamic-string.h"
 #include "sat-math.h"
+#include "svec.h"
 #include "timeval.h"
 #include "unixctl.h"
 #include "util.h"
 
-VLOG_DEFINE_THIS_MODULE(vlog)
+VLOG_DEFINE_THIS_MODULE(vlog);
 
 /* Name for each logging level. */
 static const char *level_names[VLL_N_LEVELS] = {
@@ -98,7 +100,7 @@ static void format_log_message(const struct vlog_module *, enum vlog_level,
 /* Searches the 'n_names' in 'names'.  Returns the index of a match for
  * 'target', or 'n_names' if no name matches. */
 static size_t
-search_name_array(const char *target, const char **names, size_t n_names) 
+search_name_array(const char *target, const char **names, size_t n_names)
 {
     size_t i;
 
@@ -122,14 +124,14 @@ vlog_get_level_name(enum vlog_level level)
 /* Returns the logging level with the given 'name', or VLL_N_LEVELS if 'name'
  * is not the name of a logging level. */
 enum vlog_level
-vlog_get_level_val(const char *name) 
+vlog_get_level_val(const char *name)
 {
     return search_name_array(name, level_names, ARRAY_SIZE(level_names));
 }
 
 /* Returns the name for logging facility 'facility'. */
 const char *
-vlog_get_facility_name(enum vlog_facility facility) 
+vlog_get_facility_name(enum vlog_facility facility)
 {
     assert(facility < VLF_N_FACILITIES);
     return facilities[facility].name;
@@ -138,7 +140,7 @@ vlog_get_facility_name(enum vlog_facility facility)
 /* Returns the logging facility named 'name', or VLF_N_FACILITIES if 'name' is
  * not the name of a logging facility. */
 enum vlog_facility
-vlog_get_facility_val(const char *name) 
+vlog_get_facility_val(const char *name)
 {
     size_t i;
 
@@ -174,7 +176,7 @@ vlog_module_from_name(const char *name)
 
 /* Returns the current logging level for the given 'module' and 'facility'. */
 enum vlog_level
-vlog_get_level(const struct vlog_module *module, enum vlog_facility facility) 
+vlog_get_level(const struct vlog_module *module, enum vlog_facility facility)
 {
     assert(facility < VLF_N_FACILITIES);
     return module->levels[facility];
@@ -185,7 +187,7 @@ update_min_level(struct vlog_module *module)
 {
     enum vlog_facility facility;
 
-    module->min_level = VLL_EMER;
+    module->min_level = VLL_OFF;
     for (facility = 0; facility < VLF_N_FACILITIES; facility++) {
         if (log_file || facility != VLF_FILE) {
             enum vlog_level level = module->levels[facility];
@@ -221,7 +223,7 @@ set_facility_level(enum vlog_facility facility, struct vlog_module *module,
  * across all modules or facilities, respectively. */
 void
 vlog_set_levels(struct vlog_module *module, enum vlog_facility facility,
-                enum vlog_level level) 
+                enum vlog_level level)
 {
     assert(facility < VLF_N_FACILITIES || facility == VLF_ANY_FACILITY);
     if (facility == VLF_ANY_FACILITY) {
@@ -234,7 +236,7 @@ vlog_set_levels(struct vlog_module *module, enum vlog_facility facility,
 }
 
 static void
-do_set_pattern(enum vlog_facility facility, const char *pattern) 
+do_set_pattern(enum vlog_facility facility, const char *pattern)
 {
     struct facility *f = &facilities[facility];
     if (!f->default_pattern) {
@@ -291,7 +293,7 @@ vlog_set_log_file(const char *file_name)
     old_log_file_name = log_file_name;
     log_file_name = (file_name
                      ? xstrdup(file_name)
-                     : xasprintf("%s/%s.log", ovs_logdir, program_name));
+                     : xasprintf("%s/%s.log", ovs_logdir(), program_name));
     free(old_log_file_name);
     file_name = NULL;           /* Might have been freed. */
 
@@ -321,7 +323,25 @@ vlog_set_log_file(const char *file_name)
 int
 vlog_reopen_log_file(void)
 {
-    return log_file_name ? vlog_set_log_file(log_file_name) : 0;
+    struct stat old, new;
+
+    /* Skip re-opening if there's nothing to reopen. */
+    if (!log_file_name) {
+        return 0;
+    }
+
+    /* Skip re-opening if it would be a no-op because the old and new files are
+     * the same.  (This avoids writing "closing log file" followed immediately
+     * by "opened log file".) */
+    if (log_file
+        && !fstat(fileno(log_file), &old)
+        && !stat(log_file_name, &new)
+        && old.st_dev == new.st_dev
+        && old.st_ino == new.st_ino) {
+        return 0;
+    }
+
+    return vlog_set_log_file(log_file_name);
 }
 
 /* Set debugging levels:
@@ -345,7 +365,7 @@ vlog_set_levels_from_string(const char *s_)
 
         facility = strtok_r(NULL, ":", &save_ptr);
 
-        if (!facility || !strcmp(facility, "ANY")) {
+        if (!facility || !strcasecmp(facility, "ANY")) {
             e_facility = VLF_ANY_FACILITY;
         } else {
             e_facility = vlog_get_facility_val(facility);
@@ -356,14 +376,14 @@ vlog_set_levels_from_string(const char *s_)
             }
         }
 
-        if (!strcmp(module, "PATTERN")) {
+        if (!strcasecmp(module, "PATTERN")) {
             vlog_set_pattern(e_facility, save_ptr);
             break;
         } else {
             char *level;
             enum vlog_level e_level;
 
-            if (!strcmp(module, "ANY")) {
+            if (!strcasecmp(module, "ANY")) {
                 e_module = NULL;
             } else {
                 e_module = vlog_module_from_name(module);
@@ -438,9 +458,10 @@ vlog_unixctl_reopen(struct unixctl_conn *conn,
     }
 }
 
-/* Initializes the logging subsystem. */
+/* Initializes the logging subsystem and registers its unixctl server
+ * commands. */
 void
-vlog_init(void) 
+vlog_init(void)
 {
     time_t now;
 
@@ -462,14 +483,16 @@ vlog_init(void)
         VLOG_ERR("current time is negative: %s (%ld)", s, (long int) now);
     }
 
-    unixctl_command_register("vlog/set", vlog_unixctl_set, NULL);
-    unixctl_command_register("vlog/list", vlog_unixctl_list, NULL);
-    unixctl_command_register("vlog/reopen", vlog_unixctl_reopen, NULL);
+    unixctl_command_register("vlog/set",
+                   "{module[:facility[:level]] | PATTERN:facility:pattern}",
+                   vlog_unixctl_set, NULL);
+    unixctl_command_register("vlog/list", "", vlog_unixctl_list, NULL);
+    unixctl_command_register("vlog/reopen", "", vlog_unixctl_reopen, NULL);
 }
 
 /* Closes the logging subsystem. */
 void
-vlog_exit(void) 
+vlog_exit(void)
 {
     if (vlog_inited) {
         closelog();
@@ -483,18 +506,28 @@ vlog_get_levels(void)
 {
     struct ds s = DS_EMPTY_INITIALIZER;
     struct vlog_module **mp;
+    struct svec lines = SVEC_EMPTY_INITIALIZER;
+    char *line;
+    size_t i;
 
     ds_put_format(&s, "                 console    syslog    file\n");
     ds_put_format(&s, "                 -------    ------    ------\n");
 
     for (mp = vlog_modules; mp < &vlog_modules[n_vlog_modules]; mp++) {
-        ds_put_format(&s, "%-16s  %4s       %4s       %4s\n",
+        line = xasprintf("%-16s  %4s       %4s       %4s\n",
            vlog_get_module_name(*mp),
            vlog_get_level_name(vlog_get_level(*mp, VLF_CONSOLE)),
            vlog_get_level_name(vlog_get_level(*mp, VLF_SYSLOG)),
            vlog_get_level_name(vlog_get_level(*mp, VLF_FILE)));
+        svec_add_nocopy(&lines, line);
     }
 
+    svec_sort(&lines);
+    SVEC_FOR_EACH (i, line, &lines) {
+        ds_put_cstr(&s, line);
+    }
+    svec_destroy(&lines);
+
     return ds_cstr(&s);
 }
 
@@ -679,6 +712,30 @@ vlog(const struct vlog_module *module, enum vlog_level level,
     va_end(args);
 }
 
+void
+vlog_fatal_valist(const struct vlog_module *module_,
+                  const char *message, va_list args)
+{
+    struct vlog_module *module = (struct vlog_module *) module_;
+
+    /* Don't log this message to the console to avoid redundancy with the
+     * message written by the later ovs_fatal_valist(). */
+    module->levels[VLF_CONSOLE] = VLL_OFF;
+
+    vlog_valist(module, VLL_EMER, message, args);
+    ovs_fatal_valist(0, message, args);
+}
+
+void
+vlog_fatal(const struct vlog_module *module, const char *message, ...)
+{
+    va_list args;
+
+    va_start(args, message);
+    vlog_fatal_valist(module, message, args);
+    va_end(args);
+}
+
 bool
 vlog_should_drop(const struct vlog_module *module, enum vlog_level level,
                  struct vlog_rate_limit *rl)
@@ -703,6 +760,7 @@ vlog_should_drop(const struct vlog_module *module, enum vlog_level level,
             if (!rl->n_dropped) {
                 rl->first_dropped = now;
             }
+            rl->last_dropped = now;
             rl->n_dropped++;
             return true;
         }
@@ -710,10 +768,15 @@ vlog_should_drop(const struct vlog_module *module, enum vlog_level level,
     rl->tokens -= VLOG_MSG_TOKENS;
 
     if (rl->n_dropped) {
+        time_t now = time_now();
+        unsigned int first_dropped_elapsed = now - rl->first_dropped;
+        unsigned int last_dropped_elapsed = now - rl->last_dropped;
+
         vlog(module, level,
-             "Dropped %u log messages in last %u seconds "
-             "due to excessive rate",
-             rl->n_dropped, (unsigned int) (time_now() - rl->first_dropped));
+             "Dropped %u log messages in last %u seconds (most recently, "
+             "%u seconds ago) due to excessive rate",
+             rl->n_dropped, first_dropped_elapsed, last_dropped_elapsed);
+
         rl->n_dropped = 0;
     }
     return false;
@@ -733,12 +796,12 @@ vlog_rate_limit(const struct vlog_module *module, enum vlog_level level,
 }
 
 void
-vlog_usage(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",
-           ovs_logdir, program_name);
+           ovs_logdir(), program_name);
 }