Signed-off-by: Henry Mai <henry...@nicira.com>
Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 NEWS                      |    1 +
 lib/vlog.c                |   97 ++++++++++++++++++++++++++++++++++++++-------
 lib/vlog.h                |   36 +++++++++++------
 lib/vlog.man              |    5 +++
 utilities/ovs-appctl.8.in |    6 +++
 5 files changed, 118 insertions(+), 27 deletions(-)

diff --git a/NEWS b/NEWS
index 38e3d9d..8556083 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,7 @@ Post-v2.0.0
      packaged or installed by default, because too many users assumed
      incorrectly that ovs-controller was a necessary or desirable part
      of an Open vSwitch deployment.
+   - Added vlog option to export to a UDP syslog sink.
 
 
 v2.0.0 - 15 Oct 2013
diff --git a/lib/vlog.c b/lib/vlog.c
index 3be6785..b7defe6 100644
--- a/lib/vlog.c
+++ b/lib/vlog.c
@@ -35,6 +35,7 @@
 #include "ofpbuf.h"
 #include "ovs-thread.h"
 #include "sat-math.h"
+#include "socket-util.h"
 #include "svec.h"
 #include "timeval.h"
 #include "unixctl.h"
@@ -49,18 +50,30 @@ VLOG_DEFINE_THIS_MODULE(vlog);
 
 /* Name for each logging level. */
 static const char *const level_names[VLL_N_LEVELS] = {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) #NAME,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) #NAME,
     VLOG_LEVELS
 #undef VLOG_LEVEL
 };
 
 /* Syslog value for each logging level. */
 static const int syslog_levels[VLL_N_LEVELS] = {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) SYSLOG_LEVEL,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) SYSLOG_LEVEL,
     VLOG_LEVELS
 #undef VLOG_LEVEL
 };
 
+/* RFC 5424 defines specific values for each syslog level.  Normally LOG_* use
+ * the same values.  Verify that in fact they're the same.  If we get assertion
+ * failures here then we need to define a separate rfc5424_levels[] array. */
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) \
+    BUILD_ASSERT_DECL(SYSLOG_LEVEL == RFC5424);
+VLOG_LEVELS
+#undef VLOG_LEVELS
+
+/* Similarly, RFC 5424 defines the local0 facility with the value ordinarily
+ * used for LOG_LOCAL0. */
+BUILD_ASSERT_DECL(LOG_LOCAL0 == (16 << 3));
+
 /* The log modules. */
 #if USE_LINKER_SECTIONS
 extern struct vlog_module *__start_vlog_modules[];
@@ -111,10 +124,13 @@ static int log_fd OVS_GUARDED_BY(log_file_mutex) = -1;
 static struct async_append *log_writer OVS_GUARDED_BY(log_file_mutex);
 static bool log_async OVS_GUARDED_BY(log_file_mutex);
 
+/* Syslog export configuration. */
+static int syslog_fd OVS_GUARDED_BY(pattern_rwlock) = -1;
+
 static void format_log_message(const struct vlog_module *, enum vlog_level,
-                               enum vlog_facility,
+                               const char *pattern,
                                const char *message, va_list, struct ds *)
-    PRINTF_FORMAT(4, 0) OVS_REQ_RDLOCK(&pattern_rwlock);
+    PRINTF_FORMAT(4, 0);
 
 /* Searches the 'n_names' in 'names'.  Returns the index of a match for
  * 'target', or 'n_names' if no name matches. */
@@ -480,6 +496,22 @@ vlog_set_verbosity(const char *arg)
     }
 }
 
+/* Set the vlog udp syslog target. */
+void
+vlog_set_syslog_target(const char *target)
+{
+    int new_fd;
+
+    inet_open_active(SOCK_DGRAM, target, 0, NULL, &new_fd, 0);
+
+    ovs_rwlock_wrlock(&pattern_rwlock);
+    if (syslog_fd >= 0) {
+        close(syslog_fd);
+    }
+    syslog_fd = new_fd;
+    ovs_rwlock_unlock(&pattern_rwlock);
+}
+
 static void
 vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
                  void *aux OVS_UNUSED)
@@ -706,15 +738,15 @@ fetch_braces(const char *p, const char *def, char *out, 
size_t out_size)
 
 static void
 format_log_message(const struct vlog_module *module, enum vlog_level level,
-                   enum vlog_facility facility,
-                   const char *message, va_list args_, struct ds *s)
+                   const char *pattern, const char *message,
+                   va_list args_, struct ds *s)
 {
     char tmp[128];
     va_list args;
     const char *p;
 
     ds_clear(s);
-    for (p = facilities[facility].pattern; *p != '\0'; ) {
+    for (p = pattern; *p != '\0'; ) {
         const char *subprogram_name;
         enum { LEFT, RIGHT } justify = RIGHT;
         int pad = '0';
@@ -745,6 +777,9 @@ format_log_message(const struct vlog_module *module, enum 
vlog_level level,
         case 'A':
             ds_put_cstr(s, program_name);
             break;
+        case 'B':
+            ds_put_format(s, "%d", LOG_LOCAL0 + syslog_levels[level]);
+            break;
         case 'c':
             p = fetch_braces(p, "", tmp, sizeof tmp);
             ds_put_cstr(s, vlog_get_module_name(module));
@@ -757,6 +792,11 @@ format_log_message(const struct vlog_module *module, enum 
vlog_level level,
             p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
             ds_put_strftime_msec(s, tmp, time_wall_msec(), true);
             break;
+        case 'E':
+            gethostname(tmp, sizeof tmp);
+            tmp[sizeof tmp - 1] = '\0';
+            ds_put_cstr(s, tmp);
+            break;
         case 'm':
             /* Format user-supplied log message and trim trailing new-lines. */
             length = s->length;
@@ -810,6 +850,20 @@ format_log_message(const struct vlog_module *module, enum 
vlog_level level,
     }
 }
 
+/* Exports the given 'syslog_message' to the configured udp syslog sink. */
+static void
+send_to_syslog_fd(const char *s, size_t length)
+    OVS_REQ_RDLOCK(pattern_rwlock)
+{
+    static size_t max_length = SIZE_MAX;
+    size_t send_len = MIN(length, max_length);
+
+    while (write(syslog_fd, s, send_len) < 0 && errno == EMSGSIZE) {
+        send_len -= send_len / 20;
+        max_length = send_len;
+    }
+}
+
 /* Writes 'message' to the log at the given 'level' and as coming from the
  * given 'module'.
  *
@@ -837,7 +891,8 @@ vlog_valist(const struct vlog_module *module, enum 
vlog_level level,
 
         ovs_rwlock_rdlock(&pattern_rwlock);
         if (log_to_console) {
-            format_log_message(module, level, VLF_CONSOLE, message, args, &s);
+            format_log_message(module, level, facilities[VLF_CONSOLE].pattern,
+                               message, args, &s);
             ds_put_char(&s, '\n');
             fputs(ds_cstr(&s), stderr);
         }
@@ -847,15 +902,25 @@ vlog_valist(const struct vlog_module *module, enum 
vlog_level level,
             char *save_ptr = NULL;
             char *line;
 
-            format_log_message(module, level, VLF_SYSLOG, message, args, &s);
+            format_log_message(module, level, facilities[VLF_SYSLOG].pattern,
+                               message, args, &s);
             for (line = strtok_r(s.string, "\n", &save_ptr); line;
                  line = strtok_r(NULL, "\n", &save_ptr)) {
                 syslog(syslog_level, "%s", line);
             }
+
+            if (syslog_fd >= 0) {
+                format_log_message(module, level,
+                                   "<%B>1 %D{%Y-%m-%dT%H:%M:%S.###Z} "
+                                   "%E %A %P %c - \xef\xbb\xbf%m",
+                                   message, args, &s);
+                send_to_syslog_fd(ds_cstr(&s), s.length);
+            }
         }
 
         if (log_to_file) {
-            format_log_message(module, level, VLF_FILE, message, args, &s);
+            format_log_message(module, level, facilities[VLF_FILE].pattern,
+                               message, args, &s);
             ds_put_char(&s, '\n');
 
             ovs_mutex_lock(&log_file_mutex);
@@ -1018,10 +1083,12 @@ vlog_rate_limit(const struct vlog_module *module, enum 
vlog_level level,
 void
 vlog_usage(void)
 {
-    printf("\nLogging options:\n"
-           "  -v, --verbose=[SPEC]    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",
+    printf("\n\
+Logging options:\n\
+  -vSPEC, --verbose=SPEC   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\
+  --syslog-target=HOST:PORT  also send syslog msgs to HOST:PORT via UDP\n",
            ovs_logdir(), program_name);
 }
diff --git a/lib/vlog.h b/lib/vlog.h
index d7d63bf..da55405 100644
--- a/lib/vlog.h
+++ b/lib/vlog.h
@@ -44,14 +44,14 @@ extern "C" {
  *
  * ovs-appctl(8) defines each of the log levels. */
 #define VLOG_LEVELS                             \
-    VLOG_LEVEL(OFF, LOG_ALERT)                  \
-    VLOG_LEVEL(EMER, LOG_ALERT)                 \
-    VLOG_LEVEL(ERR, LOG_ERR)                    \
-    VLOG_LEVEL(WARN, LOG_WARNING)               \
-    VLOG_LEVEL(INFO, LOG_NOTICE)                \
-    VLOG_LEVEL(DBG, LOG_DEBUG)
+    VLOG_LEVEL(OFF,  LOG_ALERT,   1)            \
+    VLOG_LEVEL(EMER, LOG_ALERT,   1)            \
+    VLOG_LEVEL(ERR,  LOG_ERR,     3)            \
+    VLOG_LEVEL(WARN, LOG_WARNING, 4)            \
+    VLOG_LEVEL(INFO, LOG_NOTICE,  5)            \
+    VLOG_LEVEL(DBG,  LOG_DEBUG,   7)
 enum vlog_level {
-#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) VLL_##NAME,
+#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424_LEVEL) VLL_##NAME,
     VLOG_LEVELS
 #undef VLOG_LEVEL
     VLL_N_LEVELS
@@ -62,7 +62,7 @@ enum vlog_level vlog_get_level_val(const char *name);
 
 /* Facilities that we can log to. */
 #define VLOG_FACILITIES                                                 \
-    VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m")                            \
+    VLOG_FACILITY(SYSLOG, "ovs|%05N|%c%T|%p|%m")                        \
     VLOG_FACILITY(CONSOLE, "%D{%Y-%m-%dT%H:%M:%SZ}|%05N|%c%T|%p|%m")    \
     VLOG_FACILITY(FILE, "%D{%Y-%m-%dT%H:%M:%S.###Z}|%05N|%c%T|%p|%m")
 enum vlog_facility {
@@ -139,6 +139,9 @@ void vlog_set_pattern(enum vlog_facility, const char 
*pattern);
 int vlog_set_log_file(const char *file_name);
 int vlog_reopen_log_file(void);
 
+/* Configure syslog target. */
+void vlog_set_syslog_target(const char *target);
+
 /* Initialization. */
 void vlog_init(void);
 void vlog_enable_async(void);
@@ -213,17 +216,26 @@ void vlog_rate_limit(const struct vlog_module *, enum 
vlog_level,
 #define VLOG_DBG_ONCE(...) VLOG_ONCE(VLL_DBG, __VA_ARGS__)
 
 /* Command line processing. */
-#define VLOG_OPTION_ENUMS OPT_LOG_FILE
-#define VLOG_LONG_OPTIONS                                   \
-        {"verbose",     optional_argument, NULL, 'v'},         \
-        {"log-file",    optional_argument, NULL, OPT_LOG_FILE}
+#define VLOG_OPTION_ENUMS                       \
+        OPT_LOG_FILE,                           \
+        OPT_SYSLOG_TARGET
+
+#define VLOG_LONG_OPTIONS                                               \
+        {"verbose",       optional_argument, NULL, 'v'},                \
+        {"log-file",      optional_argument, NULL, OPT_LOG_FILE},       \
+        {"syslog-target", optional_argument, NULL, OPT_SYSLOG_TARGET}
+
 #define VLOG_OPTION_HANDLERS                    \
         case 'v':                               \
             vlog_set_verbosity(optarg);         \
             break;                              \
         case OPT_LOG_FILE:                      \
             vlog_set_log_file(optarg);          \
+            break;                              \
+        case OPT_SYSLOG_TARGET:                 \
+            vlog_set_syslog_target(optarg);     \
             break;
+
 void vlog_usage(void);
 
 /* Implementation details. */
diff --git a/lib/vlog.man b/lib/vlog.man
index 39edaee..f675a4b 100644
--- a/lib/vlog.man
+++ b/lib/vlog.man
@@ -60,3 +60,8 @@ Sets the log pattern for \fIfacility\fR to \fIpattern\fR.  
Refer to
 Enables logging to a file.  If \fIfile\fR is specified, then it is
 used as the exact name for the log file.  The default log file name
 used if \fIfile\fR is omitted is \fB@LOGDIR@/\*(PN.log\fR.
+.
+.IP "\fB\-\-syslog\-target=\fIhost\fB:\fIport\fR"
+Send syslog messages to UDP \fIport\fR on \fIhost\fR, in addition to
+the system syslog.  The \fIhost\fR must be a numerical IP address, not
+a hostname.
diff --git a/utilities/ovs-appctl.8.in b/utilities/ovs-appctl.8.in
index 1cf888d..e381b2b 100644
--- a/utilities/ovs-appctl.8.in
+++ b/utilities/ovs-appctl.8.in
@@ -148,6 +148,9 @@ expanded as follows:
 .IP \fB%A\fR
 The name of the application logging the message, e.g. \fBovs\-vswitchd\fR.
 .
+.IP \fB%B\fR
+The RFC5424 syslog PRI of the message.
+.
 .IP \fB%c\fR
 The name of the module (as shown by \fBovs\-appctl \-\-list\fR) logging
 the message.
@@ -173,6 +176,9 @@ takes the same format as the \fItemplate\fR argument to
 \fBstrftime\fR(3).  Supports the same extension for sub-second
 resolution as \fB%d{\fR...\fB}\fR.
 .
+.IP \fB%E\fR
+The hostname of the node running the application.
+.
 .IP \fB%m\fR
 The message being logged.
 .
-- 
1.7.10.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to