[ovs-dev] [PATCH] vlog: add local udp syslog export target option
Ben Pfaff
blp at nicira.com
Fri Dec 6 01:02:35 UTC 2013
I sent out a revised version:
http://openvswitch.org/pipermail/dev/2013-December/034644.html
Will you look at it?
On Tue, Dec 03, 2013 at 09:59:19PM -0800, Henry Mai wrote:
> Sorry, found another violation where I had an extra newline before a function.
>
> On Tue, Dec 3, 2013 at 8:30 PM, Henry Mai <henrymai at nicira.com> wrote:
> > Another patch to address style issues
> >
> > On Tue, Dec 3, 2013 at 3:19 PM, Henry Mai <henrymai at nicira.com> wrote:
> >> Here's an updated patch.
> >>
> >> On Mon, Dec 2, 2013 at 2:06 PM, Ben Pfaff <blp at nicira.com> wrote:
> >>> On Mon, Nov 25, 2013 at 11:08:15PM -0800, Henry Mai wrote:
> >>>> Last patch got sent word wrapped, trying again.
> >>>
> >>>> This change allows vlog to export to a specified local udp syslog sink.
> >>>>
> >>>> Signed-off-by: Henry Mai <henrymai at nicira.com>
> >>>
> >>> "sparse" says:
> >>>
> >>> ../lib/vlog.c:887:10: warning: incorrect type in argument 5 (different base types)
> >>> ../lib/vlog.c:887:10: expected struct sockaddr const *<noident>
> >>> ../lib/vlog.c:887:10: got struct sockaddr_in *<noident>
> >>>
> >>> lib/vlog.man should document the new option.
> >>>
> >>> Lots of stuff mentioned in CodingStyle should be changed:
> >>>
> >>> - Use /**/ not // for comments.
> >>>
> >>> - Write comments as complete sentences that end in periods.
> >>>
> >>> - Each function, and each variable declared outside a function
> >>> should be preceded by a comment.
> >>>
> >>> - Put one blank line between top-level definitions of
> >>> functions and global variables.
> >>>
> >>> - Put the return type, function name, and the braces that
> >>> surround the function's code on separate lines, all starting
> >>> in column 0.
> >>>
> >>> Please group the new static vars together rather than putting a
> >>> prototype between them.
> >>>
> >>> This looks odd in our tree:
> >>> if (!error) {
> >>> loopback_mtu_size = mtu;
> >>> } // else it's just the default (1500)
> >>> I'd be inclined to write it as:
> >>> if (!error) {
> >>> loopback_mtu_size = mtu;
> >>> } else {
> >>> /* Else it's just the default (1500). */
> >>> }
> >>> or just:
> >>> loopback_mtu_size = !error ? mtu : 1500;
> >>>
> >>> Actually here's how I'd probably write the whole thing (you forgot to
> >>> close the netdev, by the way):
> >>> error = netdev_open("lo", "system", &netdev);
> >>> if (!error) {
> >>> error = netdev_get_mtu(netdev, &mtu);
> >>> netdev_close(netdev);
> >>> }
> >>> loopback_mtu_size = !error ? mtu : 1500;
> >>>
> >>> This code looks expensive due to the big memset:
> >>> memset(hostname, 0, 255);
> >>> gethostname(hostname, 255);
> >>> ds_put_cstr(s, hostname);
> >>> I know that gethostname() might not null-terminate if the hostname is
> >>> too long but I think that the following is sufficent:
> >>> gethostname(hostname, sizeof hostname);
> >>> hostname[sizeof hostname - 1] = '\0';
> >>> ds_put_cstr(s, hostname);
> >>>
> >>> I am a little nervous about assuming that LOG_* has the same values
> >>> required by RFC 5424. I guess that the values will be correct for all
> >>> Unix-like systems, but I am not sure that this assumption is warranted
> >>> generally.
> >>>
> >>> This is indented funny:
> >>> + sendto(
> >>> + syslog_sink_fd,
> >>> + ds_cstr_ro(syslog_message),
> >>> + MIN(syslog_message->length, max_payload_size),
> >>> + 0,
> >>> + &ipaddr,
> >>> + sizeof ipaddr);
> >>> I would write it as:
> >>> sendto(syslog_sink_fd, ds_cstr_ro(syslog_message),
> >>> MIN(syslog_message->length, max_payload_size), 0,
> >>> &ipaddr, sizeof ipaddr);
> >>>
> >>> In vlog_valist(), it seems wasteful to format the message even if the
> >>> formatted message will not be used (the common case).
> >>>
> >>> Thanks,
> >>>
> >>> Ben.
> This change allows vlog to export to a specified local udp syslog sink.
>
> Signed-off-by: Henry Mai <henrymai at nicira.com>
> ---
> NEWS | 1 +
> lib/vlog.c | 114 ++++++++++++++++++++++++++++++++++++++++++++--
> lib/vlog.h | 26 ++++++++---
> lib/vlog.man | 4 ++
> utilities/ovs-appctl.8.in | 6 +++
> 5 files changed, 141 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..61d427d 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,29 @@ 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 atomic_int udp_syslog_target_port = ATOMIC_VAR_INIT(0);
> +static int loopback_mtu_size = 1500;
> +static int syslog_sink_fd = -1;
> +
> 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);
>
> +/* Returns the equivalent rfc 5424 severity level. */
> +static inline int
> +get_5424_level(enum vlog_level level) {
> + switch (level) {
> + case VLL_EMER: return 0;
> + case VLL_ERR: return 3;
> + case VLL_WARN: return 4;
> + case VLL_INFO: return 6;
> + case VLL_DBG: return 7;
> + default: return 0;
> + }
> +}
> +
> /* 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 +502,17 @@ vlog_set_verbosity(const char *arg)
> }
> }
>
> +/* Set the vlog udp syslog target port. */
> +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 +615,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 +634,10 @@ vlog_init__(void)
> free(s);
> }
>
> + /* Ignore socket open failures, there is 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 +648,13 @@ 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) {
> + error = netdev_get_mtu(netdev, &mtu);
> + netdev_close(netdev);
> + }
> + loopback_mtu_size = !error ? mtu : 1500;
> }
>
> /* Initializes the logging subsystem and registers its unixctl server
> @@ -703,7 +750,10 @@ 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;
>
> @@ -739,6 +789,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) + get_5424_level(level)));
> + break;
> case 'c':
> p = fetch_braces(p, "", tmp, sizeof tmp);
> ds_put_cstr(s, vlog_get_module_name(module));
> @@ -751,6 +805,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(hostname, 255);
> + hostname[sizeof hostname - 1] = '\0';
> + ds_put_cstr(s, hostname);
> + break;
> case 'm':
> /* Format user-supplied log message and trim trailing new-lines. */
> length = s->length;
> @@ -804,6 +863,43 @@ format_log_message(const struct vlog_module *module, enum vlog_level level,
> }
> }
>
> +/* Returns whether or not udp syslog export is enabled.
> + * Sets the 'target_udp_port_out' parameter with the target udp port
> + * if enabled. */
> +static bool
> +udp_syslog_export_enabled(int *target_udp_port_out)
> +{
> + bool enabled = false;
> + int target_udp_port;
> + atomic_read(&udp_syslog_target_port, &target_udp_port);
> + enabled = ((target_udp_port > 0 ) && (syslog_sink_fd >= 0));
> + if (enabled) {
> + *target_udp_port_out = target_udp_port;
> + }
> + return enabled;
> +}
> +
> +/* Exports the given 'syslog_message' to the configured local udp syslog
> + * sink. */
> +static void
> +export_to_udp_syslog_target(struct ds *syslog_message, int target_udp_port)
> +{
> + static const int ipv4_udp_header_size = IP_HEADER_LEN + UDP_HEADER_LEN;
> + int max_payload_size;
> + struct sockaddr_in ipaddr;
> +
> + 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,
> + (struct sockaddr *)(&ipaddr), sizeof ipaddr);
> +}
> +
> /* Writes 'message' to the log at the given 'level' and as coming from the
> * given 'module'.
> *
> @@ -837,6 +933,7 @@ vlog_valist(const struct vlog_module *module, enum vlog_level level,
> }
>
> if (log_to_syslog) {
> + int target_udp_port = 0;
> int syslog_level = syslog_levels[level];
> char *save_ptr = NULL;
> char *line;
> @@ -846,6 +943,12 @@ vlog_valist(const struct vlog_module *module, enum vlog_level level,
> line = strtok_r(NULL, "\n", &save_ptr)) {
> syslog(syslog_level, "%s", line);
> }
> +
> + if (udp_syslog_export_enabled(&target_udp_port)) {
> + format_log_message(
> + module, level, VLF_RFC5424, message, args, &s);
> + export_to_udp_syslog_target(&s, target_udp_port);
> + }
> }
>
> if (log_to_file) {
> @@ -1013,9 +1116,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/lib/vlog.man b/lib/vlog.man
> index 39edaee..1410394 100644
> --- a/lib/vlog.man
> +++ b/lib/vlog.man
> @@ -60,3 +60,7 @@ 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 at LOGDIR@/\*(PN.log\fR.
> +.TP
> +\fB\-\-syslog\-target\fR[\fB=\fIudp_port\fR]
> +export syslog messages to the local \fIudp_port\fR in addition to the
> +system syslog.
> 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
>
More information about the dev
mailing list