mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
vlog: Add option to send vlog syslog output to arbitrary UDP destination.
Signed-off-by: Henry Mai <henrymai@nicira.com> Co-authored-by: Ben Pfaff <blp@nicira.com> Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
parent
e34c447909
commit
afc9f54778
1
NEWS
1
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
|
||||
|
97
lib/vlog.c
97
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)
|
||||
@ -700,15 +732,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';
|
||||
@ -739,6 +771,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));
|
||||
@ -751,6 +786,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;
|
||||
@ -804,6 +844,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'.
|
||||
*
|
||||
@ -831,7 +885,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);
|
||||
}
|
||||
@ -841,15 +896,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);
|
||||
@ -1012,10 +1077,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);
|
||||
}
|
||||
|
36
lib/vlog.h
36
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. */
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
.
|
||||
|
Loading…
x
Reference in New Issue
Block a user