This change allows vlog to export to a specified local udp syslog sink. Signed-off-by: Henry Mai <henry...@nicira.com> --- 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 dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev