Make facility and level optional in -v, --verbose options.
[openvswitch] / lib / vlog.c
index 66d57101417a1a40768e916c6f7dea34cea8bcc3..6b3d871f5197f402425863b3156780e298383a1a 100644 (file)
@@ -1,22 +1,34 @@
-/* Copyright (C) 2007, 2008 Board of Trustees, Leland Stanford Jr. University.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
+/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford
+ * Junior University
+ * 
+ * We are making the OpenFlow specification and associated documentation
+ * (Software) available for public use and benefit with the expectation
+ * that others will use, modify and enhance the Software and contribute
+ * those enhancements back to the community. However, since we would
+ * like to make the Software available for broadest use, with as few
+ * restrictions as possible permission is hereby granted, free of
+ * charge, to any person obtaining a copy of this Software to deal in
+ * the Software under the copyrights without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * 
+ * The name and trademarks of copyright holder(s) may NOT be used in
+ * advertising or publicity pertaining to the Software or any
+ * derivatives without specific, written prior permission.
  */
 
 #include "vlog.h"
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <syslog.h>
+#include <time.h>
 #include "dynamic-string.h"
 #include "util.h"
 
+#define THIS_MODULE VLM_vlog
+
 /* Name for each logging level. */
 static const char *level_names[VLL_N_LEVELS] = {
     [VLL_EMER] = "EMER",
@@ -159,7 +174,7 @@ vlog_set_levels(enum vlog_module module, enum vlog_facility facility,
 
 /* Set debugging levels:
  *
- *  mod:facility:level mod2:facility:level ...
+ *  mod[:facility[:level]] mod2[:facility[:level]] ...
  *
  * Return null if successful, otherwise an error message that the caller must
  * free().
@@ -179,10 +194,6 @@ vlog_set_levels_from_string(const char *s_)
 
         facility = strtok_r(NULL, ":", &save_ptr);
         level = strtok_r(NULL, ":", &save_ptr);
-        if (level == NULL || facility == NULL) {
-            free(s);
-            return xstrdup("syntax error in level string");
-        }
 
         if (!strcmp(module, "ANY")) {
             e_module = VLM_ANY_MODULE;
@@ -195,7 +206,7 @@ vlog_set_levels_from_string(const char *s_)
             }
         }
 
-        if (!strcmp(facility, "ANY")) {
+        if (!facility || !strcmp(facility, "ANY")) {
             e_facility = VLF_ANY_FACILITY;
         } else {
             e_facility = vlog_get_facility_val(facility);
@@ -206,7 +217,7 @@ vlog_set_levels_from_string(const char *s_)
             }
         }
 
-        e_level = vlog_get_level_val(level);
+        e_level = level ? vlog_get_level_val(level) : VLL_DBG;
         if (e_level >= VLL_N_LEVELS) {
             char *msg = xasprintf("unknown level \"%s\"", level);
             free(s);
@@ -220,13 +231,17 @@ vlog_set_levels_from_string(const char *s_)
 }
 
 /* If 'arg' is null, configure maximum verbosity.  Otherwise, sets
- * configuration according to 'arg' (see vlog_set_levels_from_string()).  If
- * parsing fails, default to maximum verbosity. */
+ * configuration according to 'arg' (see vlog_set_levels_from_string()). */
 void
 vlog_set_verbosity(const char *arg)
 {
-    if (arg == NULL || !vlog_set_levels_from_string(arg)) {
-        vlog_set_levels(VLM_ANY_MODULE, VLF_CONSOLE, VLL_DBG);
+    if (arg) {
+        char *msg = vlog_set_levels_from_string(arg);
+        if (msg) {
+            fatal(0, "processing \"%s\": %s", arg, msg);
+        }
+    } else {
+        vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_DBG);
     }
 }
 
@@ -234,8 +249,20 @@ vlog_set_verbosity(const char *arg)
 void
 vlog_init(void) 
 {
+    time_t now;
+
     openlog(program_name, LOG_NDELAY, LOG_DAEMON);
-    vlog_set_levels(VLM_ANY_MODULE, VLF_CONSOLE, VLL_WARN);
+    vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_WARN);
+
+    now = time(0);
+    if (now < 0) {
+        struct tm tm;
+        char s[128];
+
+        localtime_r(&now, &tm);
+        strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S %z", &tm);
+        VLOG_ERR("current time is negative: %s (%ld)", s, (long int) now);
+    }
 }
 
 /* Closes the logging subsystem. */
@@ -265,22 +292,42 @@ vlog_get_levels(void)
     return ds_cstr(&s);
 }
 
+/* Returns true if a log message emitted for the given 'module' and 'level'
+ * would cause some log output, false if that module and level are completely
+ * disabled. */
+bool
+vlog_is_enabled(enum vlog_module module, enum vlog_level level)
+{
+    return (levels[module][VLF_CONSOLE] >= level
+            || levels[module][VLF_SYSLOG] >= level);
+}
+
 /* Writes 'message' to the log at the given 'level' and as coming from the
- * given 'module'. */
+ * given 'module'.
+ *
+ * Guaranteed to preserve errno. */
 void
 vlog(enum vlog_module module, enum vlog_level level, const char *message, ...)
 {
     bool log_console = levels[module][VLF_CONSOLE] >= level;
     bool log_syslog = levels[module][VLF_SYSLOG] >= level;
     if (log_console || log_syslog) {
+        int save_errno = errno;
         static int msg_num;
         const char *module_name = vlog_get_module_name(module);
         const char *level_name = vlog_get_level_name(level);
+        time_t now;
+        struct tm tm;
         va_list args;
         char s[1024];
-        size_t len;
+        size_t len, time_len;
+
+        now = time(0);
+        localtime_r(&now, &tm);
 
-        len = sprintf(s, "%05d|%s|%s:", ++msg_num, module_name, level_name);
+        len = time_len = strftime(s, sizeof s, "%b %d %H:%M:%S|", &tm);
+        len += sprintf(s + len, "%05d|%s|%s:",
+                       ++msg_num, module_name, level_name);
         va_start(args, message);
         len += vsnprintf(s + len, sizeof s - len, message, args);
         va_end(args);
@@ -303,7 +350,8 @@ vlog(enum vlog_module module, enum vlog_level level, const char *message, ...)
                 [VLL_DBG] = LOG_DEBUG,
             };
 
-            syslog(syslog_levels[level], "%s", s);
+            syslog(syslog_levels[level], "%s", s + time_len);
         }
+        errno = save_errno;
     }
 }