vlog: Add ability to log to an arbitrary file, and following related changes:

* New command-line options for configuring log files, hence:
  - Centralized vlog usage messages.
* New vlogconf action for reopening log files.
* New vlogconf support for specifying a target by pidfile.
This commit is contained in:
Ben Pfaff
2008-10-23 10:45:39 -07:00
parent 278ae88d5f
commit b6eb6bc746
14 changed files with 288 additions and 112 deletions
+4 -8
View File
@@ -239,13 +239,13 @@ parse_options(int argc, char *argv[])
{
enum {
OPT_MAX_IDLE = UCHAR_MAX + 1,
OPT_PEER_CA_CERT
OPT_PEER_CA_CERT,
VLOG_OPTION_ENUMS
};
static struct option long_options[] = {
{"hub", no_argument, 0, 'H'},
{"noflow", no_argument, 0, 'n'},
{"max-idle", required_argument, 0, OPT_MAX_IDLE},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
DAEMON_LONG_OPTIONS,
@@ -294,10 +294,7 @@ parse_options(int argc, char *argv[])
printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
exit(EXIT_SUCCESS);
case 'v':
vlog_set_verbosity(optarg);
break;
VLOG_OPTION_HANDLERS
DAEMON_OPTION_HANDLERS
#ifdef HAVE_OPENSSL
@@ -327,12 +324,11 @@ usage(void)
program_name, program_name);
vconn_usage(true, true, false);
daemon_usage();
vlog_usage();
printf("\nOther options:\n"
" -H, --hub act as hub instead of learning switch\n"
" -n, --noflow pass traffic, but don't add flows\n"
" --max-idle=SECS max idle time for new flows\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
exit(EXIT_SUCCESS);
+2
View File
@@ -35,6 +35,7 @@
#define DAEMON_H 1
#include <stdbool.h>
#include <sys/types.h>
#define DAEMON_LONG_OPTIONS \
{"detach", no_argument, 0, 'D'}, \
@@ -62,5 +63,6 @@ void daemonize(void);
void die_if_already_running(void);
void ignore_existing_pidfile(void);
void daemon_usage(void);
pid_t read_pidfile(const char *name);
#endif /* daemon.h */
+1
View File
@@ -29,6 +29,7 @@ VLOG_MODULE(vconn_stream)
VLOG_MODULE(vconn_unix)
VLOG_MODULE(vconn)
VLOG_MODULE(vlog)
VLOG_MODULE(vlog_socket)
#ifdef HAVE_EXT
#include "ext/vlogext-modules.def"
+23 -2
View File
@@ -59,7 +59,8 @@ enum vlog_level vlog_get_level_val(const char *name);
/* Facilities that we can log to. */
#define VLOG_FACILITIES \
VLOG_FACILITY(SYSLOG, "%05N|%c|%p|%m") \
VLOG_FACILITY(CONSOLE, "%d{%b %d %H:%M:%S}|%05N|%c|%p|%m")
VLOG_FACILITY(CONSOLE, "%d{%b %d %H:%M:%S}|%05N|%c|%p|%m") \
VLOG_FACILITY(FILE, "%d{%b %d %H:%M:%S}|%05N|%c|%p|%m")
enum vlog_facility {
#define VLOG_FACILITY(NAME, PATTERN) VLF_##NAME,
VLOG_FACILITIES
@@ -115,12 +116,17 @@ struct vlog_rate_limit {
/* Configuring how each module logs messages. */
enum vlog_level vlog_get_level(enum vlog_module, enum vlog_facility);
void vlog_set_levels(enum vlog_module, enum vlog_facility, enum vlog_level);
void vlog_set_pattern(enum vlog_facility, const char *pattern);
char *vlog_set_levels_from_string(const char *);
char *vlog_get_levels(void);
bool vlog_is_enabled(enum vlog_module, enum vlog_level);
void vlog_set_verbosity(const char *arg);
/* Configuring log facilities. */
void vlog_set_pattern(enum vlog_facility, const char *pattern);
const char *vlog_get_log_file(void);
int vlog_set_log_file(const char *file_name);
int vlog_reopen_log_file(void);
/* Function for actual logging. */
void vlog_init(void);
void vlog_exit(void);
@@ -164,6 +170,20 @@ void vlog_rate_limit(enum vlog_module, enum vlog_level,
#define VLOG_DBG_RL(RL, ...) \
vlog_rate_limit(THIS_MODULE, VLL_DBG, RL, __VA_ARGS__)
/* Command line processing. */
#define VLOG_OPTION_ENUMS OPT_LOG_FILE
#define VLOG_LONG_OPTIONS \
{"verbose", optional_argument, 0, 'v'}, \
{"log-file", optional_argument, 0, OPT_LOG_FILE}
#define VLOG_OPTION_HANDLERS \
case 'v': \
vlog_set_verbosity(optarg); \
break; \
case OPT_LOG_FILE: \
vlog_set_log_file(optarg); \
break;
void vlog_usage(void);
/* Implementation details. */
#define VLOG(LEVEL, ...) \
do { \
@@ -173,4 +193,5 @@ void vlog_rate_limit(enum vlog_module, enum vlog_level,
} while (0)
extern enum vlog_level min_vlog_levels[VLM_N_MODULES];
#endif /* vlog.h */
+48
View File
@@ -246,3 +246,51 @@ daemon_usage(void)
" -f, --force with -P, start even if already running\n",
ofp_rundir, program_name);
}
/* Opens and reads a PID from 'pidfile'. Returns the nonnegative PID if
* successful, otherwise a negative errno value. */
pid_t
read_pidfile(const char *pidfile)
{
char line[128];
struct flock lck;
FILE *file;
int error;
file = fopen(pidfile, "r");
if (!file) {
error = errno;
VLOG_WARN("%s: open: %s", pidfile, strerror(error));
goto error;
}
lck.l_type = F_WRLCK;
lck.l_whence = SEEK_SET;
lck.l_start = 0;
lck.l_len = 0;
if (fcntl(fileno(file), F_GETLK, &lck)) {
error = errno;
VLOG_WARN("%s: fcntl: %s", pidfile, strerror(error));
goto error;
}
if (!fgets(line, sizeof line, file)) {
error = errno;
VLOG_WARN("%s: read: %s", pidfile, strerror(error));
goto error;
}
if (lck.l_pid != strtoul(line, NULL, 10)) {
error = ESRCH;
VLOG_WARN("l_pid (%ld) != %s pid (%s)",
(long int) lck.l_pid, pidfile, line);
goto error;
}
fclose(file);
return lck.l_pid;
error:
fclose(file);
return -error;
}
+63 -23
View File
@@ -33,6 +33,7 @@
#include <config.h>
#include "vlog-socket.h"
#include <ctype.h>
#include <errno.h>
#include <sys/un.h>
#include <fcntl.h>
@@ -43,16 +44,19 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "daemon.h"
#include "fatal-signal.h"
#include "poll-loop.h"
#include "socket-util.h"
#include "timeval.h"
#include "util.h"
#include "vlog.h"
#ifndef SCM_CREDENTIALS
#include <time.h>
#endif
#define THIS_MODULE VLM_vlog_socket
#include "vlog.h"
/* Server for Vlog control connection. */
struct vlog_server {
@@ -256,6 +260,12 @@ poll_server(int fd UNUSED, short int events, void *server_)
reply = msg ? msg : xstrdup("ack");
} else if (!strcmp(cmd_buf, "list")) {
reply = vlog_get_levels();
} else if (!strcmp(cmd_buf, "reopen")) {
int error = vlog_reopen_log_file();
reply = (error
? xasprintf("could not reopen log file \"%s\": %s",
vlog_get_log_file(), strerror(error))
: xstrdup("ack"));
} else {
reply = xstrdup("nak");
}
@@ -274,11 +284,18 @@ struct vlog_client {
int fd;
};
/* Connects to a Vlog server socket. If 'path' does not start with '/', then
* it start with a PID as a string. If a non-null, non-absolute name was
* passed to Vlog_server_socket::listen(), then it must follow the PID in
* 'path'. If 'path' starts with '/', then it must be an absolute path that
* gives the exact name of the Unix domain socket to connect to.
/* Connects to a Vlog server socket. 'path' may be:
*
* - A string that starts with a PID. If a non-null, non-absolute name
* was passed to Vlog_server_socket::listen(), then it must follow the
* PID in 'path'.
*
* - An absolute path (starting with '/') to a Vlog server socket or a
* pidfile. If it is a pidfile, the pidfile will be read and translated
* into a Vlog server socket file name.
*
* - A relative path, which is translated into a pidfile name and then
* treated as above.
*
* Returns 0 if successful, otherwise a positive errno value. If successful,
* sets '*clientp' to the new vlog_client, otherwise to NULL. */
@@ -287,29 +304,52 @@ vlog_client_connect(const char *path, struct vlog_client **clientp)
{
static int counter;
struct vlog_client *client;
int fd;
struct stat s;
int error;
client = xmalloc(sizeof *client);
client->connect_path = (path[0] == '/'
? xstrdup(path)
: xasprintf("/tmp/vlogs.%s", path));
if (path[0] == '/') {
client->connect_path = xstrdup(path);
} else if (isdigit((unsigned char) path[0])) {
client->connect_path = xasprintf("/tmp/vlogs.%s", path);
} else {
client->connect_path = make_pidfile_name(path);
}
client->bind_path = NULL;
if (stat(client->connect_path, &s)) {
error = errno;
VLOG_WARN("could not stat \"%s\": %s",
client->connect_path, strerror(error));
goto error;
} else if (S_ISREG(s.st_mode)) {
pid_t pid = read_pidfile(client->connect_path);
if (pid < 0) {
error = -pid;
VLOG_WARN("could not read pidfile \"%s\": %s",
client->connect_path, strerror(error));
goto error;
}
free(client->connect_path);
client->connect_path = xasprintf("/tmp/vlogs.%ld", (long int) pid);
}
client->bind_path = xasprintf("/tmp/vlog.%ld.%d",
(long int) getpid(), counter++);
fd = make_unix_socket(SOCK_DGRAM, false, false,
client->bind_path, client->connect_path);
if (fd >= 0) {
client->fd = fd;
*clientp = client;
return 0;
} else {
free(client->connect_path);
free(client->bind_path);
free(client);
*clientp = NULL;
return errno;
client->fd = make_unix_socket(SOCK_DGRAM, false, false,
client->bind_path, client->connect_path);
if (client->fd < 0) {
error = -client->fd;
goto error;
}
*clientp = client;
return 0;
error:
free(client->connect_path);
free(client->bind_path);
free(client);
*clientp = NULL;
return error;
}
/* Destroys 'client'. */
+103 -10
View File
@@ -43,6 +43,7 @@
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include "dirs.h"
#include "dynamic-string.h"
#include "sat-math.h"
#include "timeval.h"
@@ -93,6 +94,10 @@ enum vlog_level min_vlog_levels[VLM_N_MODULES];
/* Time at which vlog was initialized, in milliseconds. */
static long long int boot_time;
/* VLF_FILE configuration. */
static char *log_file_name;
static FILE *log_file;
/* Searches the 'n_names' in 'names'. Returns the index of a match for
* 'target', or 'n_names' if no name matches. */
static size_t
@@ -179,7 +184,9 @@ update_min_level(enum vlog_module module)
enum vlog_facility facility;
for (facility = 0; facility < VLF_N_FACILITIES; facility++) {
min_level = MAX(min_level, levels[module][facility]);
if (log_file || facility != VLF_FILE) {
min_level = MAX(min_level, levels[module][facility]);
}
}
min_vlog_levels[module] = min_level;
}
@@ -243,6 +250,71 @@ vlog_set_pattern(enum vlog_facility facility, const char *pattern)
}
}
/* Returns the name of the log file used by VLF_FILE, or a null pointer if no
* log file has been set. (A non-null return value does not assert that the
* named log file is in use: if vlog_set_log_file() or vlog_reopen_log_file()
* fails, it still sets the log file name.) */
const char *
vlog_get_log_file(void)
{
return log_file_name;
}
/* Sets the name of the log file used by VLF_FILE to 'file_name', or to the
* default file name if 'file_name' is null. Returns 0 if successful,
* otherwise a positive errno value. */
int
vlog_set_log_file(const char *file_name)
{
char *old_log_file_name;
enum vlog_module module;
int error;
/* Close old log file. */
if (log_file) {
VLOG_WARN("closing log file");
fclose(log_file);
log_file = NULL;
}
/* Update log file name and free old name. The ordering is important
* because 'file_name' might be 'log_file_name' or some suffix of it. */
old_log_file_name = log_file_name;
log_file_name = (file_name
? xstrdup(file_name)
: xasprintf("%s/%s.log", ofp_logdir, program_name));
free(old_log_file_name);
file_name = NULL; /* Might have been freed. */
/* Open new log file and update min_levels[] to reflect whether we actually
* have a log_file. */
log_file = fopen(log_file_name, "a");
for (module = 0; module < VLM_N_MODULES; module++) {
update_min_level(module);
}
/* Log success or failure. */
if (!log_file) {
VLOG_WARN("failed to open %s for logging: %s",
log_file_name, strerror(errno));
error = errno;
} else {
VLOG_WARN("opened log file %s", log_file_name);
error = 0;
}
return error;
}
/* Closes and then attempts to re-open the current log file. (This is useful
* just after log rotation, to ensure that the new log file starts being used.)
* Returns 0 if successful, otherwise a positive errno value. */
int
vlog_reopen_log_file(void)
{
return vlog_set_log_file(log_file_name);
}
/* Set debugging levels:
*
* mod[:facility[:level]] mod2[:facility[:level]] ...
@@ -358,14 +430,15 @@ vlog_get_levels(void)
struct ds s = DS_EMPTY_INITIALIZER;
enum vlog_module module;
ds_put_format(&s, " console syslog\n");
ds_put_format(&s, " ------- ------\n");
ds_put_format(&s, " console syslog file\n");
ds_put_format(&s, " ------- ------ ------\n");
for (module = 0; module < VLM_N_MODULES; module++) {
ds_put_format(&s, "%-16s %4s %4s\n",
ds_put_format(&s, "%-16s %4s %4s %4s\n",
vlog_get_module_name(module),
vlog_get_level_name(vlog_get_level(module, VLF_CONSOLE)),
vlog_get_level_name(vlog_get_level(module, VLF_SYSLOG)));
vlog_get_level_name(vlog_get_level(module, VLF_SYSLOG)),
vlog_get_level_name(vlog_get_level(module, VLF_FILE)));
}
return ds_cstr(&s);
@@ -489,9 +562,10 @@ void
vlog_valist(enum vlog_module module, enum vlog_level level,
const char *message, va_list args)
{
bool log_console = levels[module][VLF_CONSOLE] >= level;
bool log_syslog = levels[module][VLF_SYSLOG] >= level;
if (log_console || log_syslog) {
bool log_to_console = levels[module][VLF_CONSOLE] >= level;
bool log_to_syslog = levels[module][VLF_SYSLOG] >= level;
bool log_to_file = levels[module][VLF_FILE] >= level && log_file;
if (log_to_console || log_to_syslog || log_to_file) {
int save_errno = errno;
static unsigned int msg_num;
struct ds s;
@@ -500,14 +574,14 @@ vlog_valist(enum vlog_module module, enum vlog_level level,
ds_reserve(&s, 1024);
msg_num++;
if (log_console) {
if (log_to_console) {
format_log_message(module, level, VLF_CONSOLE, msg_num,
message, args, &s);
ds_put_char(&s, '\n');
fputs(ds_cstr(&s), stderr);
}
if (log_syslog) {
if (log_to_syslog) {
int syslog_level = syslog_levels[level];
char *save_ptr = NULL;
char *line;
@@ -520,6 +594,14 @@ vlog_valist(enum vlog_module module, enum vlog_level level,
}
}
if (log_to_file) {
format_log_message(module, level, VLF_FILE, msg_num,
message, args, &s);
ds_put_char(&s, '\n');
fputs(ds_cstr(&s), log_file);
fflush(log_file);
}
ds_destroy(&s);
errno = save_errno;
}
@@ -578,3 +660,14 @@ vlog_rate_limit(enum vlog_module module, enum vlog_level level,
rl->n_dropped = 0;
}
}
void
vlog_usage(void)
{
printf("\nLogging options:\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] 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",
ofp_logdir, program_name);
}
+6 -7
View File
@@ -2514,7 +2514,8 @@ parse_options(int argc, char *argv[], struct settings *s)
OPT_STP,
OPT_NO_STP,
OPT_OUT_OF_BAND,
OPT_IN_BAND
OPT_IN_BAND,
VLOG_OPTION_ENUMS
};
static struct option long_options[] = {
{"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
@@ -2535,6 +2536,7 @@ parse_options(int argc, char *argv[], struct settings *s)
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
DAEMON_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
#ifdef HAVE_OPENSSL
VCONN_SSL_LONG_OPTIONS
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
@@ -2670,12 +2672,10 @@ parse_options(int argc, char *argv[], struct settings *s)
printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
exit(EXIT_SUCCESS);
case 'v':
vlog_set_verbosity(optarg);
break;
DAEMON_OPTION_HANDLERS
VLOG_OPTION_HANDLERS
#ifdef HAVE_OPENSSL
VCONN_SSL_OPTION_HANDLERS
@@ -2770,9 +2770,8 @@ usage(void)
" --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n"
" --burst-limit=BURST limit on packet credit for idle time\n");
daemon_usage();
vlog_usage();
printf("\nOther options:\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
exit(EXIT_SUCCESS);
+1 -2
View File
@@ -299,9 +299,8 @@ usage(void)
" -l, --listen=METHOD allow management connections on METHOD\n"
" (a passive OpenFlow connection method)\n");
daemon_usage();
vlog_usage();
printf("\nOther options:\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
exit(EXIT_SUCCESS);
+5 -6
View File
@@ -194,13 +194,12 @@ usage(void)
" do not request a specific IP)\n"
" --vendor-class=STRING use STRING as vendor class (default:\n"
" none); use OpenFlow to imitate secchan\n"
" --no-resolv-conf do not update /etc/resolv.conf\n"
"\nOther options:\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n",
" --no-resolv-conf do not update /etc/resolv.conf\n",
program_name, program_name);
vlog_usage();
printf("\nOther options:\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
exit(EXIT_SUCCESS);
}
+2 -3
View File
@@ -238,11 +238,10 @@ usage(void)
"where each SWITCH is an active OpenFlow connection method.\n",
program_name, program_name);
vconn_usage(true, false, false);
printf("\nOptions:\n"
vlog_usage();
printf("\nOther options:\n"
" --strict use strict match for flow commands\n"
" -t, --timeout=SECS give up after SECS seconds\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
exit(EXIT_SUCCESS);
+5 -5
View File
@@ -405,15 +405,15 @@ usage(void)
" --accept-vconn=REGEX accept matching discovered controllers\n"
" --exit-without-bind exit after discovery, without binding\n"
" --exit-after-bind exit after discovery, after binding\n"
" --no-detach do not detach after discovery\n"
"\nOther options:\n"
" --no-detach do not detach after discovery\n",
program_name, program_name);
vlog_usage();
printf("\nOther options:\n"
" -t, --timeout=SECS give up discovery after SECS seconds\n"
" -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n"
" -f, --force with -P, start even if already running\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
" -h, --help display this help message\n"
" -V, --version display version information\n",
program_name, program_name, ofp_rundir, program_name);
ofp_rundir, program_name);
exit(EXIT_SUCCESS);
}
+9 -42
View File
@@ -43,6 +43,7 @@
#include "daemon.h"
#include "timeval.h"
#include "util.h"
#include "vlog.h"
/* -s, --signal: signal to send. */
static int sig_nr = SIGTERM;
@@ -51,7 +52,6 @@ static int sig_nr = SIGTERM;
static bool force;
static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3);
static bool kill_pidfile(const char *pidfile, FILE *);
static void parse_options(int argc, char *argv[]);
static void usage(void);
@@ -64,6 +64,7 @@ main(int argc, char *argv[])
set_program_name(argv[0]);
time_init();
vlog_init();
parse_options(argc, argv);
argc -= optind;
@@ -77,16 +78,16 @@ main(int argc, char *argv[])
for (i = 0; i < argc; i++) {
char *pidfile;
FILE *file;
pid_t pid;
pidfile = make_pidfile_name(argv[i]);
file = fopen(pidfile, "r");
if (!file) {
ok = false;
cond_error(errno, "%s: open", pidfile);
pid = read_pidfile(pidfile);
if (pid >= 0) {
if (kill(pid, sig_nr) < 0) {
cond_error(errno, "%s: kill(%ld)", pidfile, (long int) pid);
}
} else {
ok = kill_pidfile(argv[i], file) && ok;
fclose(file);
cond_error(-pid, "could not read %s", pidfile);
}
free(pidfile);
}
@@ -94,40 +95,6 @@ main(int argc, char *argv[])
return ok || force ? EXIT_SUCCESS : EXIT_FAILURE;
}
static bool
kill_pidfile(const char *pidfile, FILE *file)
{
char line[128];
struct flock lck;
lck.l_type = F_WRLCK;
lck.l_whence = SEEK_SET;
lck.l_start = 0;
lck.l_len = 0;
if (fcntl(fileno(file), F_GETLK, &lck)) {
cond_error(errno, "%s: fcntl", pidfile);
return false;
}
if (!fgets(line, sizeof line, file)) {
cond_error(errno, "%s: read", pidfile);
return false;
}
if (lck.l_pid != strtoul(line, NULL, 10)) {
cond_error(errno, "l_pid (%ld) != %s pid (%s)",
(long int) lck.l_pid, pidfile, line);
return false;
}
if (kill(lck.l_pid, sig_nr) < 0) {
cond_error(errno, "%s: kill(%ld)", pidfile, (long int) lck.l_pid);
return false;
}
return true;
}
static void
parse_options(int argc, char *argv[])
{
+16 -4
View File
@@ -53,15 +53,17 @@ usage(char *prog_name, int exit_code)
printf("Usage: %s [TARGET] [ACTION...]\n"
"Targets:\n"
" -a, --all Apply to all targets (default)\n"
" -t, --target=TARGET Specify target program, as a pid or an\n"
" absolute path to a Unix domain socket\n"
" -t, --target=TARGET Specify target program, as a pid, a\n"
" pidfile, or an absolute path to a Unix\n"
" domain socket\n"
"Actions:\n"
" -l, --list List current settings\n"
" -s, --set=MODULE[:FACILITY[:LEVEL]]\n"
" Set MODULE and FACILITY log level to LEVEL\n"
" MODULE may be any valid module name or 'ANY'\n"
" FACILITY may be 'syslog' or 'console' or 'ANY' (default)\n"
" LEVEL may be 'emer', 'err', 'warn', or 'dbg (default)'\n"
" FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n"
" LEVEL may be 'emer', 'err', 'warn', or 'dbg' (default)\n"
" -r, --reopen Make the program reopen its log file\n"
" -h, --help Print this helpful information\n",
prog_name);
exit(exit_code);
@@ -147,6 +149,7 @@ int main(int argc, char *argv[])
/* Action options come afterward. */
{"list", no_argument, NULL, 'l'},
{"set", required_argument, NULL, 's'},
{"reopen", no_argument, NULL, 'r'},
{0, 0, 0, 0},
};
char *short_options;
@@ -204,6 +207,15 @@ int main(int argc, char *argv[])
}
break;
case 'r':
for (i = 0; i < n_clients; i++) {
struct vlog_client *client = clients[i];
char *request = xasprintf("reopen");
transact_ack(client, request, &ok);
free(request);
}
break;
case 'h':
usage(argv[0], EXIT_SUCCESS);
break;