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