#define LOG_NDELAY 8 /* don't delay open */
#define LOG_DAEMON 24 /* system daemons */
+#define LOG_KERN (0<<3) /* kernel messages */
+#define LOG_USER (1<<3) /* user-level messages */
+#define LOG_MAIL (2<<3) /* mail system */
+#define LOG_DAEMON (3<<3) /* system daemons */
+#define LOG_AUTH (4<<3) /* security/authorization messages */
+#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
+#define LOG_LPR (6<<3) /* line printer subsystem */
+#define LOG_NEWS (7<<3) /* network news subsystem */
+#define LOG_UUCP (8<<3) /* UUCP subsystem */
+#define LOG_CRON (9<<3) /* clock daemon */
+#define LOG_AUTHPRIV (10<<3) /* security/authorization messages */
+#define LOG_FTP (11<<3) /* FTP daemon */
+
#define LOG_LOCAL0 (16<<3) /* reserved for local use */
#define LOG_LOCAL1 (17<<3) /* reserved for local use */
#define LOG_LOCAL2 (18<<3) /* reserved for local use */
/* Syslog export configuration. */
static int syslog_fd OVS_GUARDED_BY(pattern_rwlock) = -1;
+/* Log facility configuration. */
+static atomic_int log_facility = ATOMIC_VAR_INIT(0);
+
+/* Facility name and its value. */
+struct vlog_facility {
+ char *name; /* Name. */
+ unsigned int value; /* Facility associated with 'name'. */
+};
+static struct vlog_facility vlog_facilities[] = {
+ {"kern", LOG_KERN},
+ {"user", LOG_USER},
+ {"mail", LOG_MAIL},
+ {"daemon", LOG_DAEMON},
+ {"auth", LOG_AUTH},
+ {"syslog", LOG_SYSLOG},
+ {"lpr", LOG_LPR},
+ {"news", LOG_NEWS},
+ {"uucp", LOG_UUCP},
+ {"clock", LOG_CRON},
+ {"ftp", LOG_FTP},
+ {"ntp", 12<<3},
+ {"audit", 13<<3},
+ {"alert", 14<<3},
+ {"clock2", 15<<3},
+ {"local0", LOG_LOCAL0},
+ {"local1", LOG_LOCAL1},
+ {"local2", LOG_LOCAL2},
+ {"local3", LOG_LOCAL3},
+ {"local4", LOG_LOCAL4},
+ {"local5", LOG_LOCAL5},
+ {"local6", LOG_LOCAL6},
+ {"local7", LOG_LOCAL7}
+};
+static bool vlog_facility_exists(const char* facility, int *value);
+
static void format_log_message(const struct vlog_module *, enum vlog_level,
const char *pattern,
const char *message, va_list, struct ds *)
goto exit;
}
vlog_set_pattern(destination, save_ptr);
+ } else if (word && !strcasecmp(word, "FACILITY")) {
+ int value;
+
+ if (!vlog_facility_exists(save_ptr, &value)) {
+ msg = xstrdup("invalid facility");
+ goto exit;
+ }
+ atomic_store_explicit(&log_facility, value, memory_order_relaxed);
} else {
struct vlog_module *module = NULL;
enum vlog_level level = VLL_N_LEVELS;
ovs_rwlock_unlock(&pattern_rwlock);
}
+/* Returns 'false' if 'facility' is not a valid string. If 'facility'
+ * is a valid string, sets 'value' with the integer value of 'facility'
+ * and returns 'true'. */
+static bool
+vlog_facility_exists(const char* facility, int *value)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(vlog_facilities); i++) {
+ if (!strcasecmp(vlog_facilities[i].name, facility)) {
+ *value = vlog_facilities[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
static void
vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
void *aux OVS_UNUSED)
if (ovsthread_once_start(&once)) {
static char *program_name_copy;
long long int now;
+ int facility;
/* Do initialization work that needs to be done before any logging
* occurs. We want to keep this really minimal because any attempt to
* a pointer to the private copy to suppress memory leak warnings in
* case openlog() does make its own copy.) */
program_name_copy = program_name ? xstrdup(program_name) : NULL;
- openlog(program_name_copy, LOG_NDELAY, LOG_DAEMON);
+ atomic_read_explicit(&log_facility, &facility, memory_order_relaxed);
+ openlog(program_name_copy, LOG_NDELAY,
+ facility ? facility : LOG_DAEMON);
ovsthread_once_done(&once);
/* Now do anything that we want to happen only once but doesn't have to
char tmp[128];
va_list args;
const char *p;
+ int facility;
ds_clear(s);
for (p = pattern; *p != '\0'; ) {
ds_put_cstr(s, program_name);
break;
case 'B':
- ds_put_format(s, "%d", LOG_LOCAL0 + syslog_levels[level]);
+ atomic_read_explicit(&log_facility, &facility,
+ memory_order_relaxed);
+ facility = facility ? facility : LOG_LOCAL0;
+ ds_put_format(s, "%d", facility + syslog_levels[level]);
break;
case 'c':
p = fetch_braces(p, "", tmp, sizeof tmp);
int syslog_level = syslog_levels[level];
char *save_ptr = NULL;
char *line;
+ int facility;
format_log_message(module, level, destinations[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);
+ atomic_read_explicit(&log_facility, &facility,
+ memory_order_relaxed);
+ syslog(syslog_level|facility, "%s", line);
}
if (syslog_fd >= 0) {
Sets the log pattern for \fIdestination\fR to \fIpattern\fR. Refer to
\fBovs\-appctl\fR(8) for a description of the valid syntax for \fIpattern\fR.
.
+.IP "\fB\-vFACILITY:\fIfacility\fR"
+.IQ "\fB\-\-verbose=FACILITY:\fIfacility\fR"
+Sets the RFC5424 facility of the log message. \fIfacility\fR can be one of
+\fBkern\fR, \fBuser\fR, \fBmail\fR, \fBdaemon\fR, \fBauth\fR, \fBsyslog\fR,
+\fBlpr\fR, \fBnews\fR, \fBuucp\fR, \fBclock\fR, \fBftp\fR, \fBntp\fR,
+\fBaudit\fR, \fBalert\fR, \fBclock2\fR, \fBlocal0\fR, \fBlocal1\fR,
+\fBlocal2\fR, \fBlocal3\fR, \fBlocal4\fR, \fBlocal5\fR, \fBlocal6\fR or
+\fBlocal7\fR. If this option is not specified, \fBdaemon\fR is used as
+the default for the local system syslog and \fBlocal0\fR is used while sending
+a message to the target provided via the \fB\-\-syslog\-target\fR option.
+.
.TP
\fB\-\-log\-file\fR[\fB=\fIfile\fR]
Enables logging to a file. If \fIfile\fR is specified, then it is
"emer": logging.CRITICAL,
"off": logging.CRITICAL
}
+FACILITIES = ['auth', 'authpriv', 'cron', 'daemon', 'ftp', 'kern', 'lpr',
+ 'mail', 'news', 'syslog', 'user', 'uucp', 'local0', 'local1',
+ 'local2', 'local3', 'local4', 'local5', 'local6', 'local7']
+syslog_facility = "daemon"
+syslog_handler = ''
def get_level(level_str):
if f == "console":
logger.addHandler(logging.StreamHandler(sys.stderr))
elif f == "syslog":
- logger.addHandler(logging.handlers.SysLogHandler(
- address="/dev/log",
- facility=logging.handlers.SysLogHandler.LOG_DAEMON))
+ Vlog.add_syslog_handler()
elif f == "file" and Vlog.__log_file:
Vlog.__file_handler = logging.FileHandler(Vlog.__log_file)
logger.addHandler(Vlog.__file_handler)
destination = destination.lower()
Vlog.__log_patterns[destination] = pattern
+ @staticmethod
+ def add_syslog_handler(facility=None):
+ global syslog_facility, syslog_handler
+
+ # If handler is already added and there is no change in 'facility',
+ # there is nothing to do.
+ if (not facility or facility == syslog_facility) and syslog_handler:
+ return
+
+ if facility:
+ syslog_facility = facility
+
+ logger = logging.getLogger('syslog')
+ if syslog_handler:
+ logger.removeHandler(syslog_handler)
+ syslog_handler = logging.handlers.SysLogHandler(address="/dev/log",
+ facility=syslog_facility)
+ logger.addHandler(syslog_handler)
+ return
+
@staticmethod
def set_levels_from_string(s):
module = None
return "Destination %s does not exist" % words[1]
except IndexError:
return "Please supply a valid pattern and destination"
+ elif words[0] == "FACILITY":
+ if words[1] in FACILITIES:
+ Vlog.add_syslog_handler(words[1])
+ return
+ else:
+ return "Facility %s is invalid" % words[1]
for word in [w.lower() for w in words]:
if word == "any":
AT_CHECK([APPCTL -t test-unixctl.py log patterntest])
AT_CHECK([grep -q 'I<3OVS' log])
AT_CLEANUP
+
+AT_SETUP([vlog - RFC5424 facility])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+OVS_DBDIR=`pwd`; export OVS_DBDIR
+OVS_SYSCONFDIR=`pwd`; export OVS_SYSCONFDIR
+ON_EXIT([kill `cat ovsdb-server.pid`])
+
+dnl Create database.
+touch .conf.db.~lock~
+AT_CHECK([ovsdb-tool create conf.db $abs_top_srcdir/vswitchd/vswitch.ovsschema])
+
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile \
+ --remote=punix:$OVS_RUNDIR/db.sock -vPATTERN:file:"<%B>1 %A %m" \
+ --log-file], [0], [], [stderr])
+AT_CHECK([ovs-appctl -t ovsdb-server exit])
+
+# A default facility of LOG_LOCAL0 while writing to file.
+AT_CHECK([cat ovsdb-server.log | head -1 | awk '{print $1}'], [0], [<133>1
+])
+rm ovsdb-server.log
+
+AT_CHECK([ovsdb-server --detach --no-chdir --pidfile \
+ --remote=punix:$OVS_RUNDIR/db.sock -vPATTERN:file:"<%B>1 %A %m" \
+ -vFACILITY:daemon --log-file], [0], [], [stderr])
+
+AT_CHECK([cat ovsdb-server.log | head -1 | awk '{print $1}'], [0], [<29>1
+])
+
+AT_CHECK([ovs-appctl -t ovsdb-server vlog/set FACILITY:invalid], [2], [],
+[invalid facility
+ovs-appctl: ovsdb-server: server returned an error
+])
+
+AT_CHECK([ovs-appctl -t ovsdb-server vlog/set FACILITY:local7])
+AT_CHECK([ovs-appctl -t ovsdb-server vlog/set ANY:file:DBG])
+AT_CHECK([ovs-appctl -t ovsdb-server exit])
+
+AT_CHECK([cat ovsdb-server.log | tail -1 | awk '{print $1}'], [0], [<191>1
+])
+AT_CLEANUP
+
+AT_SETUP([vlog - RFC5424 facility - Python])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+OVS_LOGDIR=`pwd`; export OVS_LOGDIR
+OVS_DBDIR=`pwd`; export OVS_DBDIR
+OVS_SYSCONFDIR=`pwd`; export OVS_SYSCONFDIR
+ON_EXIT([kill `cat test-unixctl.py.pid`])
+
+AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile \
+-vFACILITY:invalid --detach], [1], [], [test-unixctl.py: processing "FACILITY:invalid": Facility invalid is invalid
+])
+
+AT_CHECK([$PYTHON $srcdir/test-unixctl.py --log-file=`pwd`/log --pidfile \
+-vFACILITY:daemon --detach])
+
+AT_CHECK([ovs-appctl -t test-unixctl.py vlog/set FACILITY:invalid], [0],
+[Facility invalid is invalid
+])
+
+AT_CHECK([ovs-appctl -t test-unixctl.py vlog/set FACILITY:local0])
+AT_CLEANUP
Daemons written in Python (e.g. \fBovs\-xapi\-sync\fR,
\fBovs\-monitor\-ipsec) do not allow control over the log pattern.
.
+.IP "\fBvlog/set\fR FACILITY:\fIfacility\fR"
+Sets the RFC5424 facility of the log message. \fIfacility\fR can be one of
+\fBkern\fR, \fBuser\fR, \fBmail\fR, \fBdaemon\fR, \fBauth\fR, \fBsyslog\fR,
+\fBlpr\fR, \fBnews\fR, \fBuucp\fR, \fBclock\fR, \fBftp\fR, \fBntp\fR,
+\fBaudit\fR, \fBalert\fR, \fBclock2\fR, \fBlocal0\fR, \fBlocal1\fR,
+\fBlocal2\fR, \fBlocal3\fR, \fBlocal4\fR, \fBlocal5\fR, \fBlocal6\fR or
+\fBlocal7\fR.
+.
.IP "\fBvlog/reopen\fR"
Causes the daemon to close and reopen its log file. (This
is useful after rotating log files, to cause a new log file to be