]> git.proxmox.com Git - ovs.git/blame - lib/vlog.c
test-sha1: Remove unneeded casts.
[ovs.git] / lib / vlog.c
CommitLineData
064af421 1/*
e0edde6f 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
064af421 3 *
a14bc59f
BP
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
064af421
BP
15 */
16
17#include <config.h>
18#include "vlog.h"
19#include <assert.h>
20#include <ctype.h>
21#include <errno.h>
9eb94563 22#include <fcntl.h>
064af421
BP
23#include <stdarg.h>
24#include <stdlib.h>
25#include <string.h>
68cb8aaf 26#include <sys/stat.h>
064af421
BP
27#include <sys/types.h>
28#include <syslog.h>
29#include <time.h>
30#include <unistd.h>
31#include "dirs.h"
32#include "dynamic-string.h"
cbb13e8e 33#include "ofpbuf.h"
064af421 34#include "sat-math.h"
8628b0b7 35#include "svec.h"
064af421
BP
36#include "timeval.h"
37#include "unixctl.h"
38#include "util.h"
cbb13e8e 39#include "worker.h"
064af421 40
d98e6007 41VLOG_DEFINE_THIS_MODULE(vlog);
064af421
BP
42
43/* Name for each logging level. */
44static const char *level_names[VLL_N_LEVELS] = {
45#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) #NAME,
46 VLOG_LEVELS
47#undef VLOG_LEVEL
48};
49
50/* Syslog value for each logging level. */
51static int syslog_levels[VLL_N_LEVELS] = {
52#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) SYSLOG_LEVEL,
53 VLOG_LEVELS
54#undef VLOG_LEVEL
55};
56
480ce8ab
BP
57/* The log modules. */
58#if USE_LINKER_SECTIONS
59extern struct vlog_module *__start_vlog_modules[];
60extern struct vlog_module *__stop_vlog_modules[];
61#define vlog_modules __start_vlog_modules
62#define n_vlog_modules (__stop_vlog_modules - __start_vlog_modules)
63#else
64#define VLOG_MODULE VLOG_DEFINE_MODULE__
65#include "vlog-modules.def"
66#undef VLOG_MODULE
67
68struct vlog_module *vlog_modules[] = {
69#define VLOG_MODULE(NAME) &VLM_##NAME,
064af421
BP
70#include "vlog-modules.def"
71#undef VLOG_MODULE
72};
480ce8ab
BP
73#define n_vlog_modules ARRAY_SIZE(vlog_modules)
74#endif
064af421
BP
75
76/* Information about each facility. */
77struct facility {
78 const char *name; /* Name. */
79 char *pattern; /* Current pattern. */
80 bool default_pattern; /* Whether current pattern is the default. */
81};
82static struct facility facilities[VLF_N_FACILITIES] = {
83#define VLOG_FACILITY(NAME, PATTERN) {#NAME, PATTERN, true},
84 VLOG_FACILITIES
85#undef VLOG_FACILITY
86};
87
064af421
BP
88/* VLF_FILE configuration. */
89static char *log_file_name;
9eb94563 90static int log_fd = -1;
064af421 91
1e8cf0f7
BP
92/* vlog initialized? */
93static bool vlog_inited;
94
480ce8ab 95static void format_log_message(const struct vlog_module *, enum vlog_level,
064af421
BP
96 enum vlog_facility, unsigned int msg_num,
97 const char *message, va_list, struct ds *)
98 PRINTF_FORMAT(5, 0);
cbb13e8e
BP
99static void vlog_write_file(struct ds *);
100static void vlog_update_async_log_fd(void);
064af421
BP
101
102/* Searches the 'n_names' in 'names'. Returns the index of a match for
103 * 'target', or 'n_names' if no name matches. */
104static size_t
d295e8e9 105search_name_array(const char *target, const char **names, size_t n_names)
064af421
BP
106{
107 size_t i;
108
109 for (i = 0; i < n_names; i++) {
110 assert(names[i]);
111 if (!strcasecmp(names[i], target)) {
112 break;
113 }
114 }
115 return i;
116}
117
118/* Returns the name for logging level 'level'. */
119const char *
120vlog_get_level_name(enum vlog_level level)
121{
122 assert(level < VLL_N_LEVELS);
123 return level_names[level];
124}
125
126/* Returns the logging level with the given 'name', or VLL_N_LEVELS if 'name'
127 * is not the name of a logging level. */
128enum vlog_level
d295e8e9 129vlog_get_level_val(const char *name)
064af421
BP
130{
131 return search_name_array(name, level_names, ARRAY_SIZE(level_names));
132}
133
134/* Returns the name for logging facility 'facility'. */
135const char *
d295e8e9 136vlog_get_facility_name(enum vlog_facility facility)
064af421
BP
137{
138 assert(facility < VLF_N_FACILITIES);
139 return facilities[facility].name;
140}
141
142/* Returns the logging facility named 'name', or VLF_N_FACILITIES if 'name' is
143 * not the name of a logging facility. */
144enum vlog_facility
d295e8e9 145vlog_get_facility_val(const char *name)
064af421
BP
146{
147 size_t i;
148
149 for (i = 0; i < VLF_N_FACILITIES; i++) {
150 if (!strcasecmp(facilities[i].name, name)) {
151 break;
152 }
153 }
154 return i;
155}
156
157/* Returns the name for logging module 'module'. */
480ce8ab
BP
158const char *
159vlog_get_module_name(const struct vlog_module *module)
064af421 160{
480ce8ab 161 return module->name;
064af421
BP
162}
163
480ce8ab
BP
164/* Returns the logging module named 'name', or NULL if 'name' is not the name
165 * of a logging module. */
166struct vlog_module *
167vlog_module_from_name(const char *name)
064af421 168{
480ce8ab
BP
169 struct vlog_module **mp;
170
171 for (mp = vlog_modules; mp < &vlog_modules[n_vlog_modules]; mp++) {
172 if (!strcasecmp(name, (*mp)->name)) {
173 return *mp;
174 }
175 }
176 return NULL;
064af421
BP
177}
178
179/* Returns the current logging level for the given 'module' and 'facility'. */
180enum vlog_level
d295e8e9 181vlog_get_level(const struct vlog_module *module, enum vlog_facility facility)
064af421 182{
064af421 183 assert(facility < VLF_N_FACILITIES);
480ce8ab 184 return module->levels[facility];
064af421
BP
185}
186
187static void
480ce8ab 188update_min_level(struct vlog_module *module)
064af421 189{
064af421
BP
190 enum vlog_facility facility;
191
c1a543a8 192 module->min_level = VLL_OFF;
064af421 193 for (facility = 0; facility < VLF_N_FACILITIES; facility++) {
9eb94563 194 if (log_fd >= 0 || facility != VLF_FILE) {
480ce8ab 195 enum vlog_level level = module->levels[facility];
56cee53b 196 if (level > module->min_level) {
480ce8ab
BP
197 module->min_level = level;
198 }
064af421
BP
199 }
200 }
064af421
BP
201}
202
203static void
480ce8ab 204set_facility_level(enum vlog_facility facility, struct vlog_module *module,
064af421
BP
205 enum vlog_level level)
206{
207 assert(facility >= 0 && facility < VLF_N_FACILITIES);
208 assert(level < VLL_N_LEVELS);
209
480ce8ab
BP
210 if (!module) {
211 struct vlog_module **mp;
212
213 for (mp = vlog_modules; mp < &vlog_modules[n_vlog_modules]; mp++) {
214 (*mp)->levels[facility] = level;
215 update_min_level(*mp);
064af421
BP
216 }
217 } else {
480ce8ab 218 module->levels[facility] = level;
064af421
BP
219 update_min_level(module);
220 }
221}
222
480ce8ab
BP
223/* Sets the logging level for the given 'module' and 'facility' to 'level'. A
224 * null 'module' or a 'facility' of VLF_ANY_FACILITY is treated as a wildcard
225 * across all modules or facilities, respectively. */
064af421 226void
480ce8ab 227vlog_set_levels(struct vlog_module *module, enum vlog_facility facility,
d295e8e9 228 enum vlog_level level)
064af421
BP
229{
230 assert(facility < VLF_N_FACILITIES || facility == VLF_ANY_FACILITY);
231 if (facility == VLF_ANY_FACILITY) {
232 for (facility = 0; facility < VLF_N_FACILITIES; facility++) {
233 set_facility_level(facility, module, level);
234 }
235 } else {
236 set_facility_level(facility, module, level);
237 }
238}
239
240static void
d295e8e9 241do_set_pattern(enum vlog_facility facility, const char *pattern)
064af421
BP
242{
243 struct facility *f = &facilities[facility];
244 if (!f->default_pattern) {
245 free(f->pattern);
246 } else {
247 f->default_pattern = false;
248 }
249 f->pattern = xstrdup(pattern);
250}
251
252/* Sets the pattern for the given 'facility' to 'pattern'. */
253void
254vlog_set_pattern(enum vlog_facility facility, const char *pattern)
255{
256 assert(facility < VLF_N_FACILITIES || facility == VLF_ANY_FACILITY);
257 if (facility == VLF_ANY_FACILITY) {
258 for (facility = 0; facility < VLF_N_FACILITIES; facility++) {
259 do_set_pattern(facility, pattern);
260 }
261 } else {
262 do_set_pattern(facility, pattern);
263 }
264}
265
266/* Returns the name of the log file used by VLF_FILE, or a null pointer if no
267 * log file has been set. (A non-null return value does not assert that the
268 * named log file is in use: if vlog_set_log_file() or vlog_reopen_log_file()
269 * fails, it still sets the log file name.) */
270const char *
271vlog_get_log_file(void)
272{
273 return log_file_name;
274}
275
276/* Sets the name of the log file used by VLF_FILE to 'file_name', or to the
277 * default file name if 'file_name' is null. Returns 0 if successful,
278 * otherwise a positive errno value. */
279int
280vlog_set_log_file(const char *file_name)
281{
282 char *old_log_file_name;
480ce8ab 283 struct vlog_module **mp;
064af421
BP
284 int error;
285
286 /* Close old log file. */
9eb94563 287 if (log_fd >= 0) {
064af421 288 VLOG_INFO("closing log file");
9eb94563
BP
289 close(log_fd);
290 log_fd = -1;
064af421
BP
291 }
292
293 /* Update log file name and free old name. The ordering is important
294 * because 'file_name' might be 'log_file_name' or some suffix of it. */
295 old_log_file_name = log_file_name;
296 log_file_name = (file_name
297 ? xstrdup(file_name)
b43c6fe2 298 : xasprintf("%s/%s.log", ovs_logdir(), program_name));
064af421
BP
299 free(old_log_file_name);
300 file_name = NULL; /* Might have been freed. */
301
302 /* Open new log file and update min_levels[] to reflect whether we actually
303 * have a log_file. */
9eb94563 304 log_fd = open(log_file_name, O_WRONLY | O_CREAT | O_APPEND, 0666);
cbb13e8e
BP
305 if (log_fd >= 0) {
306 vlog_update_async_log_fd();
307 }
480ce8ab
BP
308 for (mp = vlog_modules; mp < &vlog_modules[n_vlog_modules]; mp++) {
309 update_min_level(*mp);
064af421
BP
310 }
311
312 /* Log success or failure. */
9eb94563 313 if (log_fd < 0) {
064af421
BP
314 VLOG_WARN("failed to open %s for logging: %s",
315 log_file_name, strerror(errno));
316 error = errno;
317 } else {
318 VLOG_INFO("opened log file %s", log_file_name);
319 error = 0;
320 }
321
322 return error;
323}
324
325/* Closes and then attempts to re-open the current log file. (This is useful
326 * just after log rotation, to ensure that the new log file starts being used.)
327 * Returns 0 if successful, otherwise a positive errno value. */
328int
329vlog_reopen_log_file(void)
330{
68cb8aaf
BP
331 struct stat old, new;
332
333 /* Skip re-opening if there's nothing to reopen. */
334 if (!log_file_name) {
335 return 0;
336 }
337
338 /* Skip re-opening if it would be a no-op because the old and new files are
339 * the same. (This avoids writing "closing log file" followed immediately
340 * by "opened log file".) */
9eb94563
BP
341 if (log_fd >= 0
342 && !fstat(log_fd, &old)
68cb8aaf
BP
343 && !stat(log_file_name, &new)
344 && old.st_dev == new.st_dev
345 && old.st_ino == new.st_ino) {
346 return 0;
347 }
348
349 return vlog_set_log_file(log_file_name);
064af421
BP
350}
351
2a3e30b2
BP
352/* Set debugging levels. Returns null if successful, otherwise an error
353 * message that the caller must free(). */
064af421
BP
354char *
355vlog_set_levels_from_string(const char *s_)
356{
064af421 357 char *s = xstrdup(s_);
2a3e30b2
BP
358 char *save_ptr = NULL;
359 char *msg = NULL;
360 char *word;
064af421 361
2a3e30b2
BP
362 word = strtok_r(s, " ,:\t", &save_ptr);
363 if (word && !strcasecmp(word, "PATTERN")) {
364 enum vlog_facility facility;
064af421 365
2a3e30b2
BP
366 word = strtok_r(NULL, " ,:\t", &save_ptr);
367 if (!word) {
368 msg = xstrdup("missing facility");
369 goto exit;
064af421
BP
370 }
371
2a3e30b2
BP
372 facility = (!strcasecmp(word, "ANY")
373 ? VLF_ANY_FACILITY
374 : vlog_get_facility_val(word));
375 if (facility == VLF_N_FACILITIES) {
376 msg = xasprintf("unknown facility \"%s\"", word);
377 goto exit;
378 }
379 vlog_set_pattern(facility, save_ptr);
380 } else {
381 struct vlog_module *module = NULL;
382 enum vlog_level level = VLL_N_LEVELS;
383 enum vlog_facility facility = VLF_N_FACILITIES;
384
385 for (; word != NULL; word = strtok_r(NULL, " ,:\t", &save_ptr)) {
386 if (!strcasecmp(word, "ANY")) {
387 continue;
388 } else if (vlog_get_facility_val(word) != VLF_N_FACILITIES) {
389 if (facility != VLF_N_FACILITIES) {
390 msg = xstrdup("cannot specify multiple facilities");
391 goto exit;
064af421 392 }
2a3e30b2
BP
393 facility = vlog_get_facility_val(word);
394 } else if (vlog_get_level_val(word) != VLL_N_LEVELS) {
395 if (level != VLL_N_LEVELS) {
396 msg = xstrdup("cannot specify multiple levels");
397 goto exit;
398 }
399 level = vlog_get_level_val(word);
400 } else if (vlog_module_from_name(word)) {
401 if (module) {
402 msg = xstrdup("cannot specify multiple modules");
403 goto exit;
404 }
405 module = vlog_module_from_name(word);
406 } else {
407 msg = xasprintf("no facility, level, or module \"%s\"", word);
408 goto exit;
064af421 409 }
2a3e30b2 410 }
064af421 411
2a3e30b2
BP
412 if (facility == VLF_N_FACILITIES) {
413 facility = VLF_ANY_FACILITY;
414 }
415 if (level == VLL_N_LEVELS) {
416 level = VLL_DBG;
064af421 417 }
2a3e30b2 418 vlog_set_levels(module, facility, level);
064af421 419 }
2a3e30b2
BP
420
421exit:
064af421 422 free(s);
2a3e30b2 423 return msg;
064af421
BP
424}
425
426/* If 'arg' is null, configure maximum verbosity. Otherwise, sets
427 * configuration according to 'arg' (see vlog_set_levels_from_string()). */
428void
429vlog_set_verbosity(const char *arg)
430{
431 if (arg) {
432 char *msg = vlog_set_levels_from_string(arg);
433 if (msg) {
434 ovs_fatal(0, "processing \"%s\": %s", arg, msg);
435 }
436 } else {
480ce8ab 437 vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_DBG);
064af421
BP
438 }
439}
440
441static void
0e15264f
BP
442vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
443 void *aux OVS_UNUSED)
064af421 444{
0e15264f
BP
445 int i;
446
447 for (i = 1; i < argc; i++) {
448 char *msg = vlog_set_levels_from_string(argv[i]);
449 if (msg) {
bde9f75d 450 unixctl_command_reply_error(conn, msg);
0e15264f
BP
451 free(msg);
452 return;
453 }
454 }
bde9f75d 455 unixctl_command_reply(conn, NULL);
064af421
BP
456}
457
458static void
0e15264f
BP
459vlog_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
460 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
064af421
BP
461{
462 char *msg = vlog_get_levels();
bde9f75d 463 unixctl_command_reply(conn, msg);
064af421
BP
464 free(msg);
465}
466
467static void
0e15264f
BP
468vlog_unixctl_reopen(struct unixctl_conn *conn, int argc OVS_UNUSED,
469 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
064af421
BP
470{
471 if (log_file_name) {
472 int error = vlog_reopen_log_file();
473 if (error) {
bde9f75d 474 unixctl_command_reply_error(conn, strerror(errno));
064af421 475 } else {
bde9f75d 476 unixctl_command_reply(conn, NULL);
064af421
BP
477 }
478 } else {
bde9f75d 479 unixctl_command_reply_error(conn, "Logging to file not configured");
064af421
BP
480 }
481}
482
df5d2ed9
BP
483/* Initializes the logging subsystem and registers its unixctl server
484 * commands. */
064af421 485void
d295e8e9 486vlog_init(void)
064af421 487{
487657b2 488 static char *program_name_copy;
064af421
BP
489 time_t now;
490
1e8cf0f7
BP
491 if (vlog_inited) {
492 return;
493 }
494 vlog_inited = true;
495
487657b2
BP
496 /* openlog() is allowed to keep the pointer passed in, without making a
497 * copy. The daemonize code sometimes frees and replaces 'program_name',
498 * so make a private copy just for openlog(). (We keep a pointer to the
499 * private copy to suppress memory leak warnings in case openlog() does
500 * make its own copy.) */
501 program_name_copy = program_name ? xstrdup(program_name) : NULL;
502 openlog(program_name_copy, LOG_NDELAY, LOG_DAEMON);
064af421 503
c73814a3 504 now = time_wall();
064af421
BP
505 if (now < 0) {
506 struct tm tm;
507 char s[128];
508
3123c8fd
BP
509 gmtime_r(&now, &tm);
510 strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S", &tm);
064af421
BP
511 VLOG_ERR("current time is negative: %s (%ld)", s, (long int) now);
512 }
513
0e15264f 514 unixctl_command_register(
2a3e30b2 515 "vlog/set", "{spec | PATTERN:facility:pattern}",
0e15264f
BP
516 1, INT_MAX, vlog_unixctl_set, NULL);
517 unixctl_command_register("vlog/list", "", 0, 0, vlog_unixctl_list, NULL);
518 unixctl_command_register("vlog/reopen", "", 0, 0,
519 vlog_unixctl_reopen, NULL);
064af421
BP
520}
521
522/* Closes the logging subsystem. */
523void
d295e8e9 524vlog_exit(void)
064af421 525{
1e8cf0f7
BP
526 if (vlog_inited) {
527 closelog();
528 vlog_inited = false;
529 }
064af421
BP
530}
531
532/* Print the current logging level for each module. */
533char *
534vlog_get_levels(void)
535{
536 struct ds s = DS_EMPTY_INITIALIZER;
480ce8ab 537 struct vlog_module **mp;
8628b0b7
JP
538 struct svec lines = SVEC_EMPTY_INITIALIZER;
539 char *line;
540 size_t i;
064af421
BP
541
542 ds_put_format(&s, " console syslog file\n");
543 ds_put_format(&s, " ------- ------ ------\n");
544
480ce8ab 545 for (mp = vlog_modules; mp < &vlog_modules[n_vlog_modules]; mp++) {
8628b0b7 546 line = xasprintf("%-16s %4s %4s %4s\n",
480ce8ab
BP
547 vlog_get_module_name(*mp),
548 vlog_get_level_name(vlog_get_level(*mp, VLF_CONSOLE)),
549 vlog_get_level_name(vlog_get_level(*mp, VLF_SYSLOG)),
550 vlog_get_level_name(vlog_get_level(*mp, VLF_FILE)));
8628b0b7
JP
551 svec_add_nocopy(&lines, line);
552 }
553
554 svec_sort(&lines);
555 SVEC_FOR_EACH (i, line, &lines) {
556 ds_put_cstr(&s, line);
064af421 557 }
8628b0b7 558 svec_destroy(&lines);
064af421
BP
559
560 return ds_cstr(&s);
561}
562
563/* Returns true if a log message emitted for the given 'module' and 'level'
564 * would cause some log output, false if that module and level are completely
565 * disabled. */
566bool
480ce8ab 567vlog_is_enabled(const struct vlog_module *module, enum vlog_level level)
064af421 568{
480ce8ab 569 return module->min_level >= level;
064af421
BP
570}
571
572static const char *
573fetch_braces(const char *p, const char *def, char *out, size_t out_size)
574{
575 if (*p == '{') {
576 size_t n = strcspn(p + 1, "}");
577 size_t n_copy = MIN(n, out_size - 1);
578 memcpy(out, p + 1, n_copy);
579 out[n_copy] = '\0';
580 p += n + 2;
581 } else {
582 ovs_strlcpy(out, def, out_size);
583 }
584 return p;
585}
586
587static void
480ce8ab 588format_log_message(const struct vlog_module *module, enum vlog_level level,
064af421
BP
589 enum vlog_facility facility, unsigned int msg_num,
590 const char *message, va_list args_, struct ds *s)
591{
592 char tmp[128];
593 va_list args;
594 const char *p;
595
596 ds_clear(s);
597 for (p = facilities[facility].pattern; *p != '\0'; ) {
598 enum { LEFT, RIGHT } justify = RIGHT;
599 int pad = '0';
600 size_t length, field, used;
601
602 if (*p != '%') {
603 ds_put_char(s, *p++);
604 continue;
605 }
606
607 p++;
608 if (*p == '-') {
609 justify = LEFT;
610 p++;
611 }
612 if (*p == '0') {
613 pad = '0';
614 p++;
615 }
616 field = 0;
be2c418b 617 while (isdigit((unsigned char)*p)) {
064af421
BP
618 field = (field * 10) + (*p - '0');
619 p++;
620 }
621
622 length = s->length;
623 switch (*p++) {
624 case 'A':
625 ds_put_cstr(s, program_name);
626 break;
627 case 'c':
628 p = fetch_braces(p, "", tmp, sizeof tmp);
629 ds_put_cstr(s, vlog_get_module_name(module));
630 break;
631 case 'd':
632 p = fetch_braces(p, "%Y-%m-%d %H:%M:%S", tmp, sizeof tmp);
b5d29991
GS
633 ds_put_strftime(s, tmp, false);
634 break;
635 case 'D':
636 p = fetch_braces(p, "%Y-%m-%d %H:%M:%S", tmp, sizeof tmp);
637 ds_put_strftime(s, tmp, true);
064af421
BP
638 break;
639 case 'm':
640 /* Format user-supplied log message and trim trailing new-lines. */
641 length = s->length;
642 va_copy(args, args_);
643 ds_put_format_valist(s, message, args);
644 va_end(args);
645 while (s->length > length && s->string[s->length - 1] == '\n') {
646 s->length--;
647 }
648 break;
649 case 'N':
650 ds_put_format(s, "%u", msg_num);
651 break;
652 case 'n':
653 ds_put_char(s, '\n');
654 break;
655 case 'p':
656 ds_put_cstr(s, vlog_get_level_name(level));
657 break;
658 case 'P':
659 ds_put_format(s, "%ld", (long int) getpid());
660 break;
661 case 'r':
4ae90ff9 662 ds_put_format(s, "%lld", time_msec() - time_boot_msec());
064af421 663 break;
781dee08
BP
664 case 't':
665 ds_put_cstr(s, subprogram_name[0] ? subprogram_name : "main");
666 break;
667 case 'T':
668 if (subprogram_name[0]) {
669 ds_put_format(s, "(%s)", subprogram_name);
670 }
671 break;
064af421
BP
672 default:
673 ds_put_char(s, p[-1]);
674 break;
675 }
676 used = s->length - length;
677 if (used < field) {
678 size_t n_pad = field - used;
679 if (justify == RIGHT) {
680 ds_put_uninit(s, n_pad);
681 memmove(&s->string[length + n_pad], &s->string[length], used);
682 memset(&s->string[length], pad, n_pad);
683 } else {
684 ds_put_char_multiple(s, pad, n_pad);
685 }
686 }
687 }
688}
689
690/* Writes 'message' to the log at the given 'level' and as coming from the
691 * given 'module'.
692 *
693 * Guaranteed to preserve errno. */
694void
480ce8ab 695vlog_valist(const struct vlog_module *module, enum vlog_level level,
064af421
BP
696 const char *message, va_list args)
697{
480ce8ab
BP
698 bool log_to_console = module->levels[VLF_CONSOLE] >= level;
699 bool log_to_syslog = module->levels[VLF_SYSLOG] >= level;
9eb94563 700 bool log_to_file = module->levels[VLF_FILE] >= level && log_fd >= 0;
064af421
BP
701 if (log_to_console || log_to_syslog || log_to_file) {
702 int save_errno = errno;
703 static unsigned int msg_num;
704 struct ds s;
705
1e8cf0f7
BP
706 vlog_init();
707
064af421
BP
708 ds_init(&s);
709 ds_reserve(&s, 1024);
710 msg_num++;
711
712 if (log_to_console) {
713 format_log_message(module, level, VLF_CONSOLE, msg_num,
714 message, args, &s);
715 ds_put_char(&s, '\n');
716 fputs(ds_cstr(&s), stderr);
717 }
718
719 if (log_to_syslog) {
720 int syslog_level = syslog_levels[level];
721 char *save_ptr = NULL;
722 char *line;
723
724 format_log_message(module, level, VLF_SYSLOG, msg_num,
725 message, args, &s);
726 for (line = strtok_r(s.string, "\n", &save_ptr); line;
727 line = strtok_r(NULL, "\n", &save_ptr)) {
728 syslog(syslog_level, "%s", line);
729 }
730 }
731
732 if (log_to_file) {
733 format_log_message(module, level, VLF_FILE, msg_num,
734 message, args, &s);
735 ds_put_char(&s, '\n');
cbb13e8e 736 vlog_write_file(&s);
064af421
BP
737 }
738
739 ds_destroy(&s);
740 errno = save_errno;
741 }
742}
743
744void
480ce8ab
BP
745vlog(const struct vlog_module *module, enum vlog_level level,
746 const char *message, ...)
064af421
BP
747{
748 va_list args;
749
750 va_start(args, message);
751 vlog_valist(module, level, message, args);
752 va_end(args);
753}
754
d41d4b71
BP
755/* Logs 'message' to 'module' at maximum verbosity, then exits with a failure
756 * exit code. Always writes the message to stderr, even if the console
757 * facility is disabled.
758 *
759 * Choose this function instead of vlog_abort_valist() if the daemon monitoring
760 * facility shouldn't automatically restart the current daemon. */
279c9e03 761void
c1a543a8 762vlog_fatal_valist(const struct vlog_module *module_,
279c9e03
BP
763 const char *message, va_list args)
764{
765 struct vlog_module *module = (struct vlog_module *) module_;
766
767 /* Don't log this message to the console to avoid redundancy with the
768 * message written by the later ovs_fatal_valist(). */
c1a543a8 769 module->levels[VLF_CONSOLE] = VLL_OFF;
279c9e03 770
c1a543a8 771 vlog_valist(module, VLL_EMER, message, args);
279c9e03
BP
772 ovs_fatal_valist(0, message, args);
773}
774
d41d4b71
BP
775/* Logs 'message' to 'module' at maximum verbosity, then exits with a failure
776 * exit code. Always writes the message to stderr, even if the console
777 * facility is disabled.
778 *
779 * Choose this function instead of vlog_abort() if the daemon monitoring
780 * facility shouldn't automatically restart the current daemon. */
279c9e03 781void
c1a543a8 782vlog_fatal(const struct vlog_module *module, const char *message, ...)
279c9e03
BP
783{
784 va_list args;
785
786 va_start(args, message);
c1a543a8 787 vlog_fatal_valist(module, message, args);
279c9e03
BP
788 va_end(args);
789}
790
d41d4b71
BP
791/* Logs 'message' to 'module' at maximum verbosity, then calls abort(). Always
792 * writes the message to stderr, even if the console facility is disabled.
793 *
794 * Choose this function instead of vlog_fatal_valist() if the daemon monitoring
795 * facility should automatically restart the current daemon. */
796void
797vlog_abort_valist(const struct vlog_module *module_,
798 const char *message, va_list args)
799{
800 struct vlog_module *module = (struct vlog_module *) module_;
801
802 /* Don't log this message to the console to avoid redundancy with the
803 * message written by the later ovs_abort_valist(). */
804 module->levels[VLF_CONSOLE] = VLL_OFF;
805
806 vlog_valist(module, VLL_EMER, message, args);
807 ovs_abort_valist(0, message, args);
808}
809
810/* Logs 'message' to 'module' at maximum verbosity, then calls abort(). Always
811 * writes the message to stderr, even if the console facility is disabled.
812 *
813 * Choose this function instead of vlog_fatal() if the daemon monitoring
814 * facility should automatically restart the current daemon. */
815void
816vlog_abort(const struct vlog_module *module, const char *message, ...)
817{
818 va_list args;
819
820 va_start(args, message);
821 vlog_abort_valist(module, message, args);
822 va_end(args);
823}
824
064af421 825bool
480ce8ab 826vlog_should_drop(const struct vlog_module *module, enum vlog_level level,
064af421
BP
827 struct vlog_rate_limit *rl)
828{
829 if (!vlog_is_enabled(module, level)) {
830 return true;
831 }
832
648f4f1f 833 if (!token_bucket_withdraw(&rl->token_bucket, VLOG_MSG_TOKENS)) {
064af421 834 time_t now = time_now();
648f4f1f
BP
835 if (!rl->n_dropped) {
836 rl->first_dropped = now;
064af421 837 }
648f4f1f
BP
838 rl->last_dropped = now;
839 rl->n_dropped++;
840 return true;
064af421 841 }
064af421
BP
842
843 if (rl->n_dropped) {
e2eed6a7
BP
844 time_t now = time_now();
845 unsigned int first_dropped_elapsed = now - rl->first_dropped;
846 unsigned int last_dropped_elapsed = now - rl->last_dropped;
847
064af421 848 vlog(module, level,
e2eed6a7
BP
849 "Dropped %u log messages in last %u seconds (most recently, "
850 "%u seconds ago) due to excessive rate",
851 rl->n_dropped, first_dropped_elapsed, last_dropped_elapsed);
852
064af421
BP
853 rl->n_dropped = 0;
854 }
855 return false;
856}
857
858void
480ce8ab 859vlog_rate_limit(const struct vlog_module *module, enum vlog_level level,
064af421
BP
860 struct vlog_rate_limit *rl, const char *message, ...)
861{
862 if (!vlog_should_drop(module, level, rl)) {
863 va_list args;
864
865 va_start(args, message);
866 vlog_valist(module, level, message, args);
867 va_end(args);
868 }
869}
870
871void
d295e8e9 872vlog_usage(void)
064af421
BP
873{
874 printf("\nLogging options:\n"
2a3e30b2 875 " -v, --verbose=[SPEC] set logging levels\n"
064af421
BP
876 " -v, --verbose set maximum verbosity level\n"
877 " --log-file[=FILE] enable logging to specified FILE\n"
878 " (default: %s/%s.log)\n",
b43c6fe2 879 ovs_logdir(), program_name);
064af421 880}
cbb13e8e
BP
881\f
882static bool vlog_async_inited = false;
883
884static worker_request_func vlog_async_write_request_cb;
885
886static void
887vlog_write_file(struct ds *s)
888{
889 if (worker_is_running()) {
890 worker_request(s->string, s->length,
891 &log_fd, vlog_async_inited ? 0 : 1,
892 vlog_async_write_request_cb, NULL, NULL);
893 vlog_async_inited = true;
894 } else {
895 write(log_fd, s->string, s->length);
896 }
897}
898
899static void
900vlog_update_async_log_fd(void)
901{
902 if (worker_is_running()) {
903 worker_request(NULL, 0, &log_fd, 1, vlog_async_write_request_cb,
904 NULL, NULL);
905 vlog_async_inited = true;
906 }
907}
908
909static void
910vlog_async_write_request_cb(struct ofpbuf *request,
911 const int *fd, size_t n_fds)
912{
913 if (n_fds > 0) {
914 if (log_fd >= 0) {
915 close(log_fd);
916 }
917 log_fd = *fd;
918 }
919
920 if (request->size > 0) {
921 write(log_fd, request->data, request->size);
922 }
923}