This change allows vlog to export to a specified local udp syslog sink.
Signed-off-by: Henry Mai <[email protected]>
---
NEWS | 1 +
lib/vlog.c | 98
+++++++++++++++++++++++++++++++++++++++++++++--
lib/vlog.h | 26 ++++++++++---
utilities/ovs-appctl.8.in | 6 +++
4 files changed, 121 insertions(+), 10 deletions(-)
diff --git a/NEWS b/NEWS
index 38e3d9d..ede9338 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 local udp syslog sink.
v2.0.0 - 15 Oct 2013
diff --git a/lib/vlog.c b/lib/vlog.c
index b1ca158..2b11bc2 100644
--- a/lib/vlog.c
+++ b/lib/vlog.c
@@ -23,6 +23,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
@@ -32,8 +33,11 @@
#include "coverage.h"
#include "dirs.h"
#include "dynamic-string.h"
+#include "netdev.h"
#include "ofpbuf.h"
+#include "ovs-atomic.h"
#include "ovs-thread.h"
+#include "packets.h"
#include "sat-math.h"
#include "svec.h"
#include "timeval.h"
@@ -111,11 +115,17 @@ 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);
+static atomic_int udp_syslog_target_port = ATOMIC_VAR_INIT(0);
+
static void format_log_message(const struct vlog_module *, enum vlog_level,
enum vlog_facility,
const char *message, va_list, struct ds *)
PRINTF_FORMAT(4, 0) OVS_REQ_RDLOCK(&pattern_rwlock);
+static int loopback_mtu_size = 1500;
+static int syslog_sink_fd = -1;
+
+
/* Searches the 'n_names' in 'names'. Returns the index of a match for
* 'target', or 'n_names' if no name matches. */
static size_t
@@ -480,6 +490,16 @@ vlog_set_verbosity(const char *arg)
}
}
+void vlog_set_syslog_target(const char *target)
+{
+ int value;
+ if (!str_to_int(target, 10, &value) || value < 0) {
+ value = 0;
+ }
+ atomic_store(&udp_syslog_target_port, value);
+}
+
+
static void
vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
void *aux OVS_UNUSED)
@@ -582,6 +602,9 @@ vlog_init__(void)
{
static char *program_name_copy;
long long int now;
+ struct netdev *netdev;
+ int error = 0;
+ int mtu = 0;
/* openlog() is allowed to keep the pointer passed in, without making a
* copy. The daemonize code sometimes frees and replaces
'program_name',
@@ -598,6 +621,9 @@ vlog_init__(void)
free(s);
}
+ // Ignore socket open failures, nothing else we can do about it
+ syslog_sink_fd = socket(AF_INET, SOCK_DGRAM, 0);
+
unixctl_command_register(
"vlog/set", "{spec | PATTERN:facility:pattern}",
1, INT_MAX, vlog_unixctl_set, NULL);
@@ -608,6 +634,16 @@ vlog_init__(void)
0, INT_MAX, vlog_disable_rate_limit, NULL);
unixctl_command_register("vlog/reopen", "", 0, 0,
vlog_unixctl_reopen, NULL);
+
+ error = netdev_open("lo", "system", &netdev);
+ if (error) {
+ // Ignore errors, just leave the mtu at default (1500)
+ return;
+ }
+ error = netdev_get_mtu(netdev, &mtu);
+ if (!error) {
+ loopback_mtu_size = mtu;
+ } // else it's just the default (1500)
}
/* Initializes the logging subsystem and registers its unixctl server
@@ -703,9 +739,13 @@ 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)
{
+ static const int local0_facility = 16;
+
char tmp[128];
+ char hostname[255];
va_list args;
const char *p;
+ int syslog_severity = syslog_levels[level];
ds_clear(s);
for (p = facilities[facility].pattern; *p != '\0'; ) {
@@ -739,6 +779,10 @@ 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",
+ ((local0_facility << 3) + syslog_severity));
+ break;
case 'c':
p = fetch_braces(p, "", tmp, sizeof tmp);
ds_put_cstr(s, vlog_get_module_name(module));
@@ -751,6 +795,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':
+ memset(hostname, 0, 255);
+ gethostname(hostname, 255);
+ ds_put_cstr(s, hostname);
+ break;
case 'm':
/* Format user-supplied log message and trim trailing
new-lines. */
length = s->length;
@@ -804,6 +853,41 @@ format_log_message(const struct vlog_module *module,
enum vlog_level level,
}
}
+static void
+export_to_udp_syslog_target(struct ds *syslog_message)
+{
+ static const int ipv4_udp_header_size = IP_HEADER_LEN + UDP_HEADER_LEN;
+ int max_payload_size;
+ int target_udp_port;
+ struct sockaddr_in ipaddr;
+
+ // Don't do anything if the target port is invalid
+ atomic_read(&udp_syslog_target_port, &target_udp_port);
+ if (target_udp_port <= 0) {
+ return;
+ }
+
+ if (syslog_sink_fd < 0) {
+ // Socket unavailable, just return
+ return;
+ }
+
+ memset(&ipaddr, 0, sizeof ipaddr);
+
+ ipaddr.sin_family = AF_INET;
+ ipaddr.sin_port = htons(target_udp_port);
+ inet_pton(AF_INET, "127.0.0.1", &ipaddr.sin_addr);
+
+ max_payload_size = loopback_mtu_size - ipv4_udp_header_size;
+ sendto(
+ syslog_sink_fd,
+ ds_cstr_ro(syslog_message),
+ MIN(syslog_message->length, max_payload_size),
+ 0,
+ &ipaddr,
+ sizeof ipaddr);
+}
+
/* Writes 'message' to the log at the given 'level' and as coming from the
* given 'module'.
*
@@ -846,6 +930,9 @@ vlog_valist(const struct vlog_module *module, enum
vlog_level level,
line = strtok_r(NULL, "\n", &save_ptr)) {
syslog(syslog_level, "%s", line);
}
+
+ format_log_message(module, level, VLF_RFC5424, message, args,
&s);
+ export_to_udp_syslog_target(&s);
}
if (log_to_file) {
@@ -1013,9 +1100,12 @@ 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",
+ " -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"
+ " --syslog-target=[UDP_PORT] export syslog messages to the \n"
+ " local UDP_PORT in addition to \n"
+ " the system syslog\n",
ovs_logdir(), program_name);
}
diff --git a/lib/vlog.h b/lib/vlog.h
index d7d63bf..05c65a8 100644
--- a/lib/vlog.h
+++ b/lib/vlog.h
@@ -62,9 +62,11 @@ 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")
+ VLOG_FACILITY(FILE, "%D{%Y-%m-%dT%H:%M:%S.###Z}|%05N|%c%T|%p|%m") \
+ VLOG_FACILITY(RFC5424, \
+ "<%B>1 %D{%Y-%m-%dT%H:%M:%S.###Z} %E %A %P %c - \xEF\xBB\xBF%m")
enum vlog_facility {
#define VLOG_FACILITY(NAME, PATTERN) VLF_##NAME,
VLOG_FACILITIES
@@ -139,6 +141,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 +218,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/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.8.5.rc1.17.g0ecd94d
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev