Coverage Report

Created: 2023-03-26 07:41

/src/openvswitch/lib/vlog.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015, 2016 Nicira, Inc.
3
 *
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:
7
 *
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.
15
 */
16
17
#include <config.h>
18
#include "openvswitch/vlog.h"
19
#include <assert.h>
20
#include <ctype.h>
21
#include <errno.h>
22
#include <fcntl.h>
23
#include <stdarg.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <sys/stat.h>
27
#include <sys/types.h>
28
#include <syslog.h>
29
#include <time.h>
30
#include <unistd.h>
31
#include "async-append.h"
32
#include "coverage.h"
33
#include "dirs.h"
34
#include "openvswitch/dynamic-string.h"
35
#include "openvswitch/ofpbuf.h"
36
#include "ovs-thread.h"
37
#include "sat-math.h"
38
#include "socket-util.h"
39
#include "svec.h"
40
#include "syslog-direct.h"
41
#include "syslog-libc.h"
42
#include "syslog-null.h"
43
#include "syslog-provider.h"
44
#include "timeval.h"
45
#include "unixctl.h"
46
#include "util.h"
47
48
VLOG_DEFINE_THIS_MODULE(vlog);
49
50
/* ovs_assert() logs the assertion message, so using ovs_assert() in this
51
 * source file could cause recursion. */
52
#undef ovs_assert
53
#define ovs_assert use_assert_instead_of_ovs_assert_in_this_module
54
55
/* Name for each logging level. */
56
static const char *const level_names[VLL_N_LEVELS] = {
57
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) #NAME,
58
    VLOG_LEVELS
59
#undef VLOG_LEVEL
60
};
61
62
/* Syslog value for each logging level. */
63
static const int syslog_levels[VLL_N_LEVELS] = {
64
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) SYSLOG_LEVEL,
65
    VLOG_LEVELS
66
#undef VLOG_LEVEL
67
};
68
69
/* RFC 5424 defines specific values for each syslog level.  Normally LOG_* use
70
 * the same values.  Verify that in fact they're the same.  If we get assertion
71
 * failures here then we need to define a separate rfc5424_levels[] array. */
72
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL, RFC5424) \
73
    BUILD_ASSERT_DECL(SYSLOG_LEVEL == RFC5424);
74
VLOG_LEVELS
75
#undef VLOG_LEVELS
76
77
/* Similarly, RFC 5424 defines the local0 facility with the value ordinarily
78
 * used for LOG_LOCAL0. */
79
BUILD_ASSERT_DECL(LOG_LOCAL0 == (16 << 3));
80
81
/* Protects the 'pattern' in all "struct destination"s, so that a race between
82
 * changing and reading the pattern does not cause an access to freed
83
 * memory. */
84
static struct ovs_rwlock pattern_rwlock = OVS_RWLOCK_INITIALIZER;
85
86
/* Information about each destination. */
87
struct destination {
88
    const char *name;           /* Name. */
89
    char *pattern OVS_GUARDED_BY(pattern_rwlock); /* Current pattern. */
90
    bool default_pattern;       /* Whether current pattern is the default. */
91
};
92
static struct destination destinations[VLF_N_DESTINATIONS] = {
93
#define VLOG_DESTINATION(NAME, PATTERN) {#NAME, PATTERN, true},
94
    VLOG_DESTINATIONS
95
#undef VLOG_DESTINATION
96
};
97
98
/* Sequence number for the message currently being composed. */
99
DEFINE_STATIC_PER_THREAD_DATA(unsigned int, msg_num, 0);
100
101
/* VLF_FILE configuration.
102
 *
103
 * All of the following is protected by 'log_file_mutex', which nests inside
104
 * pattern_rwlock. */
105
static struct ovs_mutex log_file_mutex OVS_ACQ_AFTER(pattern_rwlock)
106
    = OVS_MUTEX_INITIALIZER;
107
static char *log_file_name OVS_GUARDED_BY(log_file_mutex) = NULL;
108
static int log_fd OVS_GUARDED_BY(log_file_mutex) = -1;
109
static struct async_append *log_writer OVS_GUARDED_BY(log_file_mutex);
110
static bool log_async OVS_GUARDED_BY(log_file_mutex);
111
static struct syslogger *syslogger = NULL;
112
113
/* The log modules. */
114
static struct ovs_list vlog_modules OVS_GUARDED_BY(log_file_mutex)
115
    = OVS_LIST_INITIALIZER(&vlog_modules);
116
117
/* Syslog export configuration. */
118
static int syslog_fd OVS_GUARDED_BY(pattern_rwlock) = -1;
119
120
/* Log facility configuration. */
121
static atomic_int log_facility = 0;
122
123
/* Facility name and its value. */
124
struct vlog_facility {
125
    char *name;           /* Name. */
126
    unsigned int value;   /* Facility associated with 'name'. */
127
};
128
static struct vlog_facility vlog_facilities[] = {
129
    {"kern", LOG_KERN},
130
    {"user", LOG_USER},
131
    {"mail", LOG_MAIL},
132
    {"daemon", LOG_DAEMON},
133
    {"auth", LOG_AUTH},
134
    {"syslog", LOG_SYSLOG},
135
    {"lpr", LOG_LPR},
136
    {"news", LOG_NEWS},
137
    {"uucp", LOG_UUCP},
138
    {"clock", LOG_CRON},
139
    {"ftp", LOG_FTP},
140
    {"ntp", 12<<3},
141
    {"audit", 13<<3},
142
    {"alert", 14<<3},
143
    {"clock2", 15<<3},
144
    {"local0", LOG_LOCAL0},
145
    {"local1", LOG_LOCAL1},
146
    {"local2", LOG_LOCAL2},
147
    {"local3", LOG_LOCAL3},
148
    {"local4", LOG_LOCAL4},
149
    {"local5", LOG_LOCAL5},
150
    {"local6", LOG_LOCAL6},
151
    {"local7", LOG_LOCAL7}
152
};
153
static bool vlog_facility_exists(const char* facility, int *value);
154
155
static void format_log_message(const struct vlog_module *, enum vlog_level,
156
                               const char *pattern,
157
                               const char *message, va_list, struct ds *)
158
    OVS_PRINTF_FORMAT(4, 0);
159
160
/* Searches the 'n_names' in 'names'.  Returns the index of a match for
161
 * 'target', or 'n_names' if no name matches. */
162
static size_t
163
search_name_array(const char *target, const char *const *names, size_t n_names)
164
0
{
165
0
    size_t i;
166
167
0
    for (i = 0; i < n_names; i++) {
168
0
        assert(names[i]);
169
0
        if (!strcasecmp(names[i], target)) {
170
0
            break;
171
0
        }
172
0
    }
173
0
    return i;
174
0
}
175
176
/* Returns the name for logging level 'level'. */
177
const char *
178
vlog_get_level_name(enum vlog_level level)
179
0
{
180
0
    assert(level < VLL_N_LEVELS);
181
0
    return level_names[level];
182
0
}
183
184
/* Returns the logging level with the given 'name', or VLL_N_LEVELS if 'name'
185
 * is not the name of a logging level. */
186
enum vlog_level
187
vlog_get_level_val(const char *name)
188
0
{
189
0
    return search_name_array(name, level_names, ARRAY_SIZE(level_names));
190
0
}
191
192
/* Returns the name for logging destination 'destination'. */
193
const char *
194
vlog_get_destination_name(enum vlog_destination destination)
195
0
{
196
0
    assert(destination < VLF_N_DESTINATIONS);
197
0
    return destinations[destination].name;
198
0
}
199
200
/* Returns the logging destination named 'name', or VLF_N_DESTINATIONS if
201
 * 'name' is not the name of a logging destination. */
202
enum vlog_destination
203
vlog_get_destination_val(const char *name)
204
0
{
205
0
    size_t i;
206
207
0
    for (i = 0; i < VLF_N_DESTINATIONS; i++) {
208
0
        if (!strcasecmp(destinations[i].name, name)) {
209
0
            break;
210
0
        }
211
0
    }
212
0
    return i;
213
0
}
214
215
void
216
vlog_insert_module(struct ovs_list *vlog)
217
170
{
218
170
    ovs_mutex_lock(&log_file_mutex);
219
170
    ovs_list_insert(&vlog_modules, vlog);
220
170
    ovs_mutex_unlock(&log_file_mutex);
221
170
}
222
223
/* Returns the name for logging module 'module'. */
224
const char *
225
vlog_get_module_name(const struct vlog_module *module)
226
0
{
227
0
    return module->name;
228
0
}
229
230
/* Returns the logging module named 'name', or NULL if 'name' is not the name
231
 * of a logging module. */
232
struct vlog_module *
233
vlog_module_from_name(const char *name)
234
0
{
235
0
    struct vlog_module *mp;
236
237
0
    ovs_mutex_lock(&log_file_mutex);
238
0
    LIST_FOR_EACH (mp, list, &vlog_modules) {
239
0
        if (!strcasecmp(name, mp->name)) {
240
0
            ovs_mutex_unlock(&log_file_mutex);
241
0
            return mp;
242
0
        }
243
0
    }
244
0
    ovs_mutex_unlock(&log_file_mutex);
245
246
0
    return NULL;
247
0
}
248
249
/* Returns the current logging level for the given 'module' and
250
 * 'destination'. */
251
enum vlog_level
252
vlog_get_level(const struct vlog_module *module,
253
               enum vlog_destination destination)
254
0
{
255
0
    assert(destination < VLF_N_DESTINATIONS);
256
0
    return module->levels[destination];
257
0
}
258
259
static void
260
update_min_level(struct vlog_module *module) OVS_REQUIRES(log_file_mutex)
261
0
{
262
0
    enum vlog_destination destination;
263
264
0
    module->min_level = VLL_OFF;
265
0
    for (destination = 0; destination < VLF_N_DESTINATIONS; destination++) {
266
0
        if (log_fd >= 0 || destination != VLF_FILE) {
267
0
            enum vlog_level level = module->levels[destination];
268
0
            if (level > module->min_level) {
269
0
                module->min_level = level;
270
0
            }
271
0
        }
272
0
    }
273
0
}
274
275
static void
276
set_destination_level(enum vlog_destination destination,
277
                      struct vlog_module *module, enum vlog_level level)
278
0
{
279
0
    assert(destination >= 0 && destination < VLF_N_DESTINATIONS);
280
0
    assert(level < VLL_N_LEVELS);
281
282
0
    ovs_mutex_lock(&log_file_mutex);
283
0
    if (!module) {
284
0
        struct vlog_module *mp;
285
0
        LIST_FOR_EACH (mp, list, &vlog_modules) {
286
0
            mp->levels[destination] = level;
287
0
            update_min_level(mp);
288
0
        }
289
0
    } else {
290
0
        module->levels[destination] = level;
291
0
        update_min_level(module);
292
0
    }
293
0
    ovs_mutex_unlock(&log_file_mutex);
294
0
}
295
296
/* Sets the logging level for the given 'module' and 'destination' to 'level'.
297
 * A null 'module' or a 'destination' of VLF_ANY_DESTINATION is treated as a
298
 * wildcard across all modules or destinations, respectively. */
299
void
300
vlog_set_levels(struct vlog_module *module, enum vlog_destination destination,
301
                enum vlog_level level)
302
0
{
303
0
    assert(destination < VLF_N_DESTINATIONS ||
304
0
           destination == VLF_ANY_DESTINATION);
305
0
    if (destination == VLF_ANY_DESTINATION) {
306
0
        for (destination = 0; destination < VLF_N_DESTINATIONS;
307
0
             destination++) {
308
0
            set_destination_level(destination, module, level);
309
0
        }
310
0
    } else {
311
0
        set_destination_level(destination, module, level);
312
0
    }
313
0
}
314
315
static void
316
do_set_pattern(enum vlog_destination destination, const char *pattern)
317
0
{
318
0
    struct destination *f = &destinations[destination];
319
320
0
    ovs_rwlock_wrlock(&pattern_rwlock);
321
0
    if (!f->default_pattern) {
322
0
        free(f->pattern);
323
0
    } else {
324
0
        f->default_pattern = false;
325
0
    }
326
0
    f->pattern = xstrdup(pattern);
327
0
    ovs_rwlock_unlock(&pattern_rwlock);
328
0
}
329
330
/* Sets the pattern for the given 'destination' to 'pattern'. */
331
void
332
vlog_set_pattern(enum vlog_destination destination, const char *pattern)
333
0
{
334
0
    assert(destination < VLF_N_DESTINATIONS ||
335
0
           destination == VLF_ANY_DESTINATION);
336
0
    if (destination == VLF_ANY_DESTINATION) {
337
0
        for (destination = 0; destination < VLF_N_DESTINATIONS;
338
0
             destination++) {
339
0
            do_set_pattern(destination, pattern);
340
0
        }
341
0
    } else {
342
0
        do_set_pattern(destination, pattern);
343
0
    }
344
0
}
345
346
/* Returns a copy of the name of the log file used by VLF_FILE, or NULL if none
347
 * is configured.  The caller must eventually free the returned string. */
348
char *
349
vlog_get_log_file(void)
350
0
{
351
0
    ovs_mutex_lock(&log_file_mutex);
352
0
    char *fn = nullable_xstrdup(log_file_name);
353
0
    ovs_mutex_unlock(&log_file_mutex);
354
355
0
    return fn;
356
0
}
357
358
/* Sets the name of the log file used by VLF_FILE to 'new_log_file_name', or
359
 * closes the current log file if 'new_log_file_name' is NULL.  Takes ownership
360
 * of 'new_log_file_name'.  Returns 0 if successful, otherwise a positive errno
361
 * value. */
362
static int
363
vlog_set_log_file__(char *new_log_file_name)
364
0
{
365
0
    struct vlog_module *mp;
366
0
    struct stat old_stat;
367
0
    struct stat new_stat;
368
0
    int new_log_fd;
369
0
    bool same_file;
370
0
    bool log_close;
371
372
    /* Open new log file. */
373
0
    if (new_log_file_name) {
374
0
        new_log_fd = open(new_log_file_name, O_WRONLY | O_CREAT | O_APPEND,
375
0
                          0660);
376
0
        if (new_log_fd < 0) {
377
0
            VLOG_WARN("failed to open %s for logging: %s",
378
0
                      new_log_file_name, ovs_strerror(errno));
379
0
            free(new_log_file_name);
380
0
            return errno;
381
0
        }
382
0
    } else {
383
0
        new_log_fd = -1;
384
0
    }
385
386
    /* If the new log file is the same one we already have open, bail out. */
387
0
    ovs_mutex_lock(&log_file_mutex);
388
0
    same_file = ((log_fd < 0
389
0
                  && new_log_fd < 0) ||
390
0
                 (log_fd >= 0
391
0
                  && new_log_fd >= 0
392
0
                  && !fstat(log_fd, &old_stat)
393
0
                  && !fstat(new_log_fd, &new_stat)
394
0
                  && old_stat.st_dev == new_stat.st_dev
395
0
                  && old_stat.st_ino == new_stat.st_ino));
396
0
    ovs_mutex_unlock(&log_file_mutex);
397
0
    if (same_file) {
398
0
        close(new_log_fd);
399
0
        free(new_log_file_name);
400
0
        return 0;
401
0
    }
402
403
    /* Log closing old log file (we can't log while holding log_file_mutex). */
404
0
    ovs_mutex_lock(&log_file_mutex);
405
0
    log_close = log_fd >= 0;
406
0
    ovs_mutex_unlock(&log_file_mutex);
407
0
    if (log_close) {
408
0
        VLOG_INFO("closing log file");
409
0
    }
410
411
    /* Close old log file, if any. */
412
0
    ovs_mutex_lock(&log_file_mutex);
413
0
    if (log_fd >= 0) {
414
0
        close(log_fd);
415
0
    }
416
0
    async_append_destroy(log_writer);
417
0
    free(log_file_name);
418
419
    /* Install new log file. */
420
0
    log_file_name = nullable_xstrdup(new_log_file_name);
421
0
    log_fd = new_log_fd;
422
0
    log_writer = log_async ? async_append_create(new_log_fd) : NULL;
423
424
0
    LIST_FOR_EACH (mp, list, &vlog_modules) {
425
0
        update_min_level(mp);
426
0
    }
427
0
    ovs_mutex_unlock(&log_file_mutex);
428
429
    /* Log opening new log file (we can't log while holding log_file_mutex). */
430
0
    VLOG_INFO("opened log file %s", new_log_file_name);
431
0
    free(new_log_file_name);
432
433
0
    return 0;
434
0
}
435
436
/* Closes the log file, if any.
437
 *
438
 * If the real goal is open a new log file, use vlog_set_log_file() to directly
439
 * do that: there is no need to close the old file first. */
440
void
441
vlog_close_log_file(void)
442
0
{
443
0
    vlog_set_log_file__(NULL);
444
0
}
445
446
/* Sets the name of the log file used by VLF_FILE to 'file_name', or to the
447
 * default file name if 'file_name' is null.  Returns 0 if successful,
448
 * otherwise a positive errno value. */
449
int
450
vlog_set_log_file(const char *file_name)
451
0
{
452
0
    return vlog_set_log_file__(
453
0
        file_name
454
0
        ? xstrdup(file_name)
455
0
        : xasprintf("%s/%s.log", ovs_logdir(), program_name));
456
0
}
457
458
/* Closes and then attempts to re-open the current log file.  (This is useful
459
 * just after log rotation, to ensure that the new log file starts being used.)
460
 * Returns 0 if successful, otherwise a positive errno value. */
461
int
462
vlog_reopen_log_file(void)
463
0
{
464
0
    char *fn;
465
466
0
    ovs_mutex_lock(&log_file_mutex);
467
0
    fn = nullable_xstrdup(log_file_name);
468
0
    ovs_mutex_unlock(&log_file_mutex);
469
470
0
    if (fn) {
471
0
        int error = vlog_set_log_file(fn);
472
0
        free(fn);
473
0
        return error;
474
0
    } else {
475
0
        return 0;
476
0
    }
477
0
}
478
479
#ifndef _WIN32
480
/* In case a log file exists, change its owner to new 'user' and 'group'.
481
 *
482
 * This is useful for handling cases where the --log-file option is
483
 * specified ahead of the --user option.  */
484
void
485
vlog_change_owner_unix(uid_t user, gid_t group)
486
0
{
487
0
    struct ds err = DS_EMPTY_INITIALIZER;
488
0
    int error;
489
490
0
    ovs_mutex_lock(&log_file_mutex);
491
0
    error = log_file_name ? chown(log_file_name, user, group) : 0;
492
0
    if (error) {
493
        /* Build the error message. We can not call VLOG_FATAL directly
494
         * here because VLOG_FATAL() will try again to to acquire
495
         * 'log_file_mutex' lock, causing deadlock.
496
         */
497
0
        ds_put_format(&err, "Failed to change %s ownership: %s.",
498
0
                      log_file_name, ovs_strerror(errno));
499
0
    }
500
0
    ovs_mutex_unlock(&log_file_mutex);
501
502
0
    if (error) {
503
0
        VLOG_FATAL("%s", ds_steal_cstr(&err));
504
0
    }
505
0
}
506
#endif
507
508
/* Set debugging levels.  Returns null if successful, otherwise an error
509
 * message that the caller must free(). */
510
char *
511
vlog_set_levels_from_string(const char *s_)
512
0
{
513
0
    char *s = xstrdup(s_);
514
0
    char *save_ptr = NULL;
515
0
    char *msg = NULL;
516
0
    char *word;
517
518
0
    word = strtok_r(s, " ,:\t", &save_ptr);
519
0
    if (word && !strcasecmp(word, "PATTERN")) {
520
0
        enum vlog_destination destination;
521
522
0
        word = strtok_r(NULL, " ,:\t", &save_ptr);
523
0
        if (!word) {
524
0
            msg = xstrdup("missing destination");
525
0
            goto exit;
526
0
        }
527
528
0
        destination = (!strcasecmp(word, "ANY")
529
0
                       ? VLF_ANY_DESTINATION
530
0
                       : vlog_get_destination_val(word));
531
0
        if (destination == VLF_N_DESTINATIONS) {
532
0
            msg = xasprintf("unknown destination \"%s\"", word);
533
0
            goto exit;
534
0
        }
535
0
        vlog_set_pattern(destination, save_ptr);
536
0
    } else if (word && !strcasecmp(word, "FACILITY")) {
537
0
        int value;
538
539
0
        if (!vlog_facility_exists(save_ptr, &value)) {
540
0
            msg = xstrdup("invalid facility");
541
0
            goto exit;
542
0
        }
543
0
        atomic_store_explicit(&log_facility, value, memory_order_relaxed);
544
0
    } else {
545
0
        struct vlog_module *module = NULL;
546
0
        enum vlog_level level = VLL_N_LEVELS;
547
0
        enum vlog_destination destination = VLF_N_DESTINATIONS;
548
549
0
        for (; word != NULL; word = strtok_r(NULL, " ,:\t", &save_ptr)) {
550
0
            if (!strcasecmp(word, "ANY")) {
551
0
                continue;
552
0
            } else if (vlog_get_destination_val(word) != VLF_N_DESTINATIONS) {
553
0
                if (destination != VLF_N_DESTINATIONS) {
554
0
                    msg = xstrdup("cannot specify multiple destinations");
555
0
                    goto exit;
556
0
                }
557
0
                destination = vlog_get_destination_val(word);
558
0
            } else if (vlog_get_level_val(word) != VLL_N_LEVELS) {
559
0
                if (level != VLL_N_LEVELS) {
560
0
                    msg = xstrdup("cannot specify multiple levels");
561
0
                    goto exit;
562
0
                }
563
0
                level = vlog_get_level_val(word);
564
0
            } else if (vlog_module_from_name(word)) {
565
0
                if (module) {
566
0
                    msg = xstrdup("cannot specify multiple modules");
567
0
                    goto exit;
568
0
                }
569
0
                module = vlog_module_from_name(word);
570
0
            } else {
571
0
                msg = xasprintf("no destination, level, or module \"%s\"",
572
0
                                word);
573
0
                goto exit;
574
0
            }
575
0
        }
576
577
0
        if (destination == VLF_N_DESTINATIONS) {
578
0
            destination = VLF_ANY_DESTINATION;
579
0
        }
580
0
        if (level == VLL_N_LEVELS) {
581
0
            level = VLL_DBG;
582
0
        }
583
0
        vlog_set_levels(module, destination, level);
584
0
    }
585
586
0
exit:
587
0
    free(s);
588
0
    return msg;
589
0
}
590
591
/* Set debugging levels.  Abort with an error message if 's' is invalid. */
592
void
593
vlog_set_levels_from_string_assert(const char *s)
594
0
{
595
0
    char *error = vlog_set_levels_from_string(s);
596
0
    if (error) {
597
0
        ovs_fatal(0, "%s", error);
598
0
    }
599
0
}
600
601
/* If 'arg' is null, configure maximum verbosity.  Otherwise, sets
602
 * configuration according to 'arg' (see vlog_set_levels_from_string()). */
603
void
604
vlog_set_verbosity(const char *arg)
605
0
{
606
0
    if (arg) {
607
0
        char *msg = vlog_set_levels_from_string(arg);
608
0
        if (msg) {
609
0
            ovs_fatal(0, "processing \"%s\": %s", arg, msg);
610
0
        }
611
0
    } else {
612
0
        vlog_set_levels(NULL, VLF_ANY_DESTINATION, VLL_DBG);
613
0
    }
614
0
}
615
616
void
617
vlog_set_syslog_method(const char *method)
618
0
{
619
0
    if (syslogger) {
620
        /* Set syslogger only, if one is not already set.  This effectively
621
         * means that only the first --syslog-method argument is honored. */
622
0
        return;
623
0
    }
624
625
0
    if (!strcmp(method, "null")) {
626
0
        syslogger = syslog_null_create();
627
0
    } else if (!strcmp(method, "libc")) {
628
0
        syslogger = syslog_libc_create();
629
0
    } else if (!strncmp(method, "udp:", 4) || !strncmp(method, "unix:", 5)) {
630
0
        syslogger = syslog_direct_create(method);
631
0
    } else {
632
0
        ovs_fatal(0, "unsupported syslog method '%s'", method);
633
0
    }
634
0
}
635
636
/* Set the vlog udp syslog target. */
637
void
638
vlog_set_syslog_target(const char *target)
639
0
{
640
0
    int new_fd;
641
642
0
    inet_open_active(SOCK_DGRAM, target, -1, NULL, &new_fd, 0);
643
644
0
    ovs_rwlock_wrlock(&pattern_rwlock);
645
0
    if (syslog_fd >= 0) {
646
0
        close(syslog_fd);
647
0
    }
648
0
    syslog_fd = new_fd;
649
0
    ovs_rwlock_unlock(&pattern_rwlock);
650
0
}
651
652
/*
653
 * This function writes directly to log file without using async writer or
654
 * taking a lock.  Caller must hold 'log_file_mutex' or be sure that it's
655
 * not necessary.  Could be used in exceptional cases like dumping of backtrace
656
 * on fatal signals.
657
 */
658
void
659
vlog_direct_write_to_log_file_unsafe(const char *s)
660
    OVS_NO_THREAD_SAFETY_ANALYSIS
661
0
{
662
0
    if (log_fd >= 0) {
663
0
        ignore(write(log_fd, s, strlen(s)));
664
0
    }
665
0
}
666
667
/* Returns 'false' if 'facility' is not a valid string. If 'facility'
668
 * is a valid string, sets 'value' with the integer value of 'facility'
669
 * and returns 'true'. */
670
static bool
671
vlog_facility_exists(const char* facility, int *value)
672
0
{
673
0
    size_t i;
674
0
    for (i = 0; i < ARRAY_SIZE(vlog_facilities); i++) {
675
0
        if (!strcasecmp(vlog_facilities[i].name, facility)) {
676
0
            *value = vlog_facilities[i].value;
677
0
            return true;
678
0
        }
679
0
    }
680
0
    return false;
681
0
}
682
683
static void
684
vlog_unixctl_set(struct unixctl_conn *conn, int argc, const char *argv[],
685
                 void *aux OVS_UNUSED)
686
0
{
687
0
    int i;
688
689
    /* With no argument, set all destinations and modules to "dbg". */
690
0
    if (argc == 1) {
691
0
        vlog_set_levels(NULL, VLF_ANY_DESTINATION, VLL_DBG);
692
0
    }
693
0
    for (i = 1; i < argc; i++) {
694
0
        char *msg = vlog_set_levels_from_string(argv[i]);
695
0
        if (msg) {
696
0
            unixctl_command_reply_error(conn, msg);
697
0
            free(msg);
698
0
            return;
699
0
        }
700
0
    }
701
0
    unixctl_command_reply(conn, NULL);
702
0
}
703
704
static void
705
vlog_unixctl_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
706
                  const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
707
0
{
708
0
    char *msg = vlog_get_levels();
709
0
    unixctl_command_reply(conn, msg);
710
0
    free(msg);
711
0
}
712
713
static void
714
vlog_unixctl_list_pattern(struct unixctl_conn *conn, int argc OVS_UNUSED,
715
                          const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
716
0
{
717
0
    char *msg;
718
719
0
    msg = vlog_get_patterns();
720
0
    unixctl_command_reply(conn, msg);
721
0
    free(msg);
722
0
}
723
724
static void
725
vlog_unixctl_reopen(struct unixctl_conn *conn, int argc OVS_UNUSED,
726
                    const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
727
0
{
728
0
    bool has_log_file;
729
730
0
    ovs_mutex_lock(&log_file_mutex);
731
0
    has_log_file = log_file_name != NULL;
732
0
    ovs_mutex_unlock(&log_file_mutex);
733
734
0
    if (has_log_file) {
735
0
        int error = vlog_reopen_log_file();
736
0
        if (error) {
737
0
            unixctl_command_reply_error(conn, ovs_strerror(errno));
738
0
        } else {
739
0
            unixctl_command_reply(conn, NULL);
740
0
        }
741
0
    } else {
742
0
        unixctl_command_reply_error(conn, "Logging to file not configured");
743
0
    }
744
0
}
745
746
static void
747
vlog_unixctl_close(struct unixctl_conn *conn, int argc OVS_UNUSED,
748
                   const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
749
0
{
750
0
    ovs_mutex_lock(&log_file_mutex);
751
0
    if (log_fd >= 0) {
752
0
        close(log_fd);
753
0
        log_fd = -1;
754
755
0
        async_append_destroy(log_writer);
756
0
        log_writer = NULL;
757
758
0
        struct vlog_module *mp;
759
0
        LIST_FOR_EACH (mp, list, &vlog_modules) {
760
0
            update_min_level(mp);
761
0
        }
762
0
    }
763
0
    ovs_mutex_unlock(&log_file_mutex);
764
765
0
    unixctl_command_reply(conn, NULL);
766
0
}
767
768
static void
769
set_all_rate_limits(bool enable)
770
0
{
771
0
    struct vlog_module *mp;
772
773
0
    ovs_mutex_lock(&log_file_mutex);
774
0
    LIST_FOR_EACH (mp, list, &vlog_modules) {
775
0
        mp->honor_rate_limits = enable;
776
0
    }
777
0
    ovs_mutex_unlock(&log_file_mutex);
778
0
}
779
780
static void
781
set_rate_limits(struct unixctl_conn *conn, int argc,
782
                const char *argv[], bool enable)
783
0
{
784
0
    if (argc > 1) {
785
0
        int i;
786
787
0
        for (i = 1; i < argc; i++) {
788
0
            if (!strcasecmp(argv[i], "ANY")) {
789
0
                set_all_rate_limits(enable);
790
0
            } else {
791
0
                struct vlog_module *module = vlog_module_from_name(argv[i]);
792
0
                if (!module) {
793
0
                    unixctl_command_reply_error(conn, "unknown module");
794
0
                    return;
795
0
                }
796
0
                module->honor_rate_limits = enable;
797
0
            }
798
0
        }
799
0
    } else {
800
0
        set_all_rate_limits(enable);
801
0
    }
802
0
    unixctl_command_reply(conn, NULL);
803
0
}
804
805
static void
806
vlog_enable_rate_limit(struct unixctl_conn *conn, int argc,
807
                       const char *argv[], void *aux OVS_UNUSED)
808
0
{
809
0
    set_rate_limits(conn, argc, argv, true);
810
0
}
811
812
static void
813
vlog_disable_rate_limit(struct unixctl_conn *conn, int argc,
814
                       const char *argv[], void *aux OVS_UNUSED)
815
0
{
816
0
    set_rate_limits(conn, argc, argv, false);
817
0
}
818
819
/* Initializes the logging subsystem and registers its unixctl server
820
 * commands. */
821
void
822
vlog_init(void)
823
0
{
824
0
    static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
825
826
0
    if (ovsthread_once_start(&once)) {
827
0
        long long int now;
828
0
        int facility;
829
0
        bool print_syslog_target_deprecation;
830
831
        /* Do initialization work that needs to be done before any logging
832
         * occurs.  We want to keep this really minimal because any attempt to
833
         * log anything before calling ovsthread_once_done() will deadlock. */
834
0
        atomic_read_explicit(&log_facility, &facility, memory_order_relaxed);
835
0
        if (!syslogger) {
836
0
            char *env = getenv("OVS_SYSLOG_METHOD");
837
0
            if (env && env[0]) {
838
0
                vlog_set_syslog_method(env);
839
0
            } else {
840
0
                syslogger = syslog_libc_create();
841
0
            }
842
0
        }
843
0
        syslogger->class->openlog(syslogger, facility ? facility : LOG_DAEMON);
844
0
        ovsthread_once_done(&once);
845
846
        /* Now do anything that we want to happen only once but doesn't have to
847
         * finish before we start logging. */
848
849
0
        now = time_wall_msec();
850
0
        if (now < 0) {
851
0
            char *s = xastrftime_msec("%a, %d %b %Y %H:%M:%S", now, true);
852
0
            VLOG_ERR("current time is negative: %s (%lld)", s, now);
853
0
            free(s);
854
0
        }
855
856
0
        unixctl_command_register(
857
0
            "vlog/set", "{spec | PATTERN:destination:pattern}",
858
0
            0, INT_MAX, vlog_unixctl_set, NULL);
859
0
        unixctl_command_register("vlog/list", "", 0, 0, vlog_unixctl_list,
860
0
                                 NULL);
861
0
        unixctl_command_register("vlog/list-pattern", "", 0, 0,
862
0
                                 vlog_unixctl_list_pattern, NULL);
863
0
        unixctl_command_register("vlog/enable-rate-limit", "[module]...",
864
0
                                 0, INT_MAX, vlog_enable_rate_limit, NULL);
865
0
        unixctl_command_register("vlog/disable-rate-limit", "[module]...",
866
0
                                 0, INT_MAX, vlog_disable_rate_limit, NULL);
867
0
        unixctl_command_register("vlog/reopen", "", 0, 0,
868
0
                                 vlog_unixctl_reopen, NULL);
869
0
        unixctl_command_register("vlog/close", "", 0, 0,
870
0
                                 vlog_unixctl_close, NULL);
871
872
0
        ovs_rwlock_rdlock(&pattern_rwlock);
873
0
        print_syslog_target_deprecation = syslog_fd >= 0;
874
0
        ovs_rwlock_unlock(&pattern_rwlock);
875
876
0
        if (print_syslog_target_deprecation) {
877
0
            VLOG_WARN("--syslog-target flag is deprecated, use "
878
0
                      "--syslog-method instead");
879
0
        }
880
0
    }
881
0
}
882
883
/* Enables VLF_FILE log output to be written asynchronously to disk.
884
 * Asynchronous file writes avoid blocking the process in the case of a busy
885
 * disk, but on the other hand they are less robust: there is a chance that the
886
 * write will not make it to the log file if the process crashes soon after the
887
 * log call. */
888
void
889
vlog_enable_async(void)
890
0
{
891
0
    ovs_mutex_lock(&log_file_mutex);
892
0
    log_async = true;
893
0
    if (log_fd >= 0 && !log_writer) {
894
0
        log_writer = async_append_create(log_fd);
895
0
    }
896
0
    ovs_mutex_unlock(&log_file_mutex);
897
0
}
898
899
void
900
vlog_disable_async(void)
901
0
{
902
0
    ovs_mutex_lock(&log_file_mutex);
903
0
    log_async = false;
904
0
    async_append_destroy(log_writer);
905
0
    log_writer = NULL;
906
0
    ovs_mutex_unlock(&log_file_mutex);
907
0
}
908
909
/* Print the current logging level for each module. */
910
char *
911
vlog_get_levels(void)
912
0
{
913
0
    struct ds s = DS_EMPTY_INITIALIZER;
914
0
    struct vlog_module *mp;
915
0
    struct svec lines = SVEC_EMPTY_INITIALIZER;
916
0
    size_t i;
917
918
0
    ds_put_format(&s, "                 console    syslog    file\n");
919
0
    ds_put_format(&s, "                 -------    ------    ------\n");
920
921
0
    ovs_mutex_lock(&log_file_mutex);
922
0
    LIST_FOR_EACH (mp, list, &vlog_modules) {
923
0
        struct ds line;
924
925
0
        ds_init(&line);
926
0
        ds_put_format(&line, "%-16s  %4s       %4s       %4s",
927
0
                      vlog_get_module_name(mp),
928
0
                      vlog_get_level_name(vlog_get_level(mp, VLF_CONSOLE)),
929
0
                      vlog_get_level_name(vlog_get_level(mp, VLF_SYSLOG)),
930
0
                      vlog_get_level_name(vlog_get_level(mp, VLF_FILE)));
931
0
        if (!mp->honor_rate_limits) {
932
0
            ds_put_cstr(&line, "    (rate limiting disabled)");
933
0
        }
934
0
        ds_put_char(&line, '\n');
935
936
0
        svec_add_nocopy(&lines, ds_steal_cstr(&line));
937
0
    }
938
0
    ovs_mutex_unlock(&log_file_mutex);
939
940
0
    svec_sort(&lines);
941
942
0
    char *line;
943
0
    SVEC_FOR_EACH (i, line, &lines) {
944
0
        ds_put_cstr(&s, line);
945
0
    }
946
0
    svec_destroy(&lines);
947
948
0
    return ds_cstr(&s);
949
0
}
950
951
/* Returns as a string current logging patterns for each destination.
952
 * This string must be released by caller. */
953
char *
954
vlog_get_patterns(void)
955
0
{
956
0
    struct ds ds = DS_EMPTY_INITIALIZER;
957
0
    enum vlog_destination destination;
958
959
0
    ovs_rwlock_rdlock(&pattern_rwlock);
960
0
    ds_put_format(&ds, "         prefix                            format\n");
961
0
    ds_put_format(&ds, "         ------                            ------\n");
962
963
0
    for (destination = 0; destination < VLF_N_DESTINATIONS; destination++) {
964
0
        struct destination *f = &destinations[destination];
965
0
        const char *prefix = "none";
966
967
0
        if (destination == VLF_SYSLOG && syslogger) {
968
0
            prefix = syslog_get_prefix(syslogger);
969
0
        }
970
0
        ds_put_format(&ds, "%-7s  %-32s  %s\n", f->name, prefix, f->pattern);
971
0
    }
972
0
    ovs_rwlock_unlock(&pattern_rwlock);
973
974
0
    return ds_cstr(&ds);
975
0
}
976
977
/* Returns true if a log message emitted for the given 'module' and 'level'
978
 * would cause some log output, false if that module and level are completely
979
 * disabled. */
980
bool
981
vlog_is_enabled(const struct vlog_module *module, enum vlog_level level)
982
417
{
983
417
    return module->min_level >= level;
984
417
}
985
986
static const char *
987
fetch_braces(const char *p, const char *def, char *out, size_t out_size)
988
0
{
989
0
    if (*p == '{') {
990
0
        size_t n = strcspn(p + 1, "}");
991
0
        size_t n_copy = MIN(n, out_size - 1);
992
0
        memcpy(out, p + 1, n_copy);
993
0
        out[n_copy] = '\0';
994
0
        p += n + 2;
995
0
    } else {
996
0
        ovs_strlcpy(out, def, out_size);
997
0
    }
998
0
    return p;
999
0
}
1000
1001
static void
1002
format_log_message(const struct vlog_module *module, enum vlog_level level,
1003
                   const char *pattern, const char *message,
1004
                   va_list args_, struct ds *s)
1005
0
{
1006
0
    char tmp[128];
1007
0
    va_list args;
1008
0
    const char *p;
1009
0
    int facility;
1010
1011
0
    ds_clear(s);
1012
0
    for (p = pattern; *p != '\0'; ) {
1013
0
        const char *subprogram_name;
1014
0
        enum { LEFT, RIGHT } justify = RIGHT;
1015
0
        int pad = ' ';
1016
0
        size_t length, field, used;
1017
1018
0
        if (*p != '%') {
1019
0
            ds_put_char(s, *p++);
1020
0
            continue;
1021
0
        }
1022
1023
0
        p++;
1024
0
        if (*p == '-') {
1025
0
            justify = LEFT;
1026
0
            p++;
1027
0
        }
1028
0
        if (*p == '0') {
1029
0
            pad = '0';
1030
0
            p++;
1031
0
        }
1032
0
        field = 0;
1033
0
        while (isdigit((unsigned char)*p)) {
1034
0
            field = (field * 10) + (*p - '0');
1035
0
            p++;
1036
0
        }
1037
1038
0
        length = s->length;
1039
0
        switch (*p++) {
1040
0
        case 'A':
1041
0
            ds_put_cstr(s, program_name);
1042
0
            break;
1043
0
        case 'B':
1044
0
            atomic_read_explicit(&log_facility, &facility,
1045
0
                                 memory_order_relaxed);
1046
0
            facility = facility ? facility : LOG_LOCAL0;
1047
0
            ds_put_format(s, "%d", facility + syslog_levels[level]);
1048
0
            break;
1049
0
        case 'c':
1050
0
            p = fetch_braces(p, "", tmp, sizeof tmp);
1051
0
            ds_put_cstr(s, vlog_get_module_name(module));
1052
0
            break;
1053
0
        case 'd':
1054
0
            p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
1055
0
            ds_put_strftime_msec(s, tmp, time_wall_msec(), false);
1056
0
            break;
1057
0
        case 'D':
1058
0
            p = fetch_braces(p, "%Y-%m-%d %H:%M:%S.###", tmp, sizeof tmp);
1059
0
            ds_put_strftime_msec(s, tmp, time_wall_msec(), true);
1060
0
            break;
1061
0
        case 'E':
1062
0
            gethostname(tmp, sizeof tmp);
1063
0
            tmp[sizeof tmp - 1] = '\0';
1064
0
            ds_put_cstr(s, tmp);
1065
0
            break;
1066
0
        case 'm':
1067
            /* Format user-supplied log message and trim trailing new-lines. */
1068
0
            length = s->length;
1069
0
            va_copy(args, args_);
1070
0
            ds_put_format_valist(s, message, args);
1071
0
            va_end(args);
1072
0
            while (s->length > length && s->string[s->length - 1] == '\n') {
1073
0
                s->length--;
1074
0
            }
1075
0
            break;
1076
0
        case 'N':
1077
0
            ds_put_format(s, "%u", *msg_num_get_unsafe());
1078
0
            break;
1079
0
        case 'n':
1080
0
            ds_put_char(s, '\n');
1081
0
            break;
1082
0
        case 'p':
1083
0
            ds_put_cstr(s, vlog_get_level_name(level));
1084
0
            break;
1085
0
        case 'P':
1086
0
            ds_put_format(s, "%ld", (long int) getpid());
1087
0
            break;
1088
0
        case 'r':
1089
0
            ds_put_format(s, "%lld", time_msec() - time_boot_msec());
1090
0
            break;
1091
0
        case 't':
1092
0
            subprogram_name = get_subprogram_name();
1093
0
            ds_put_cstr(s, subprogram_name[0] ? subprogram_name : "main");
1094
0
            break;
1095
0
        case 'T':
1096
0
            subprogram_name = get_subprogram_name();
1097
0
            if (subprogram_name[0]) {
1098
0
                ds_put_format(s, "(%s)", subprogram_name);
1099
0
            }
1100
0
            break;
1101
0
        default:
1102
0
            ds_put_char(s, p[-1]);
1103
0
            break;
1104
0
        }
1105
0
        used = s->length - length;
1106
0
        if (used < field) {
1107
0
            size_t n_pad = field - used;
1108
0
            if (justify == RIGHT) {
1109
0
                ds_put_uninit(s, n_pad);
1110
0
                memmove(&s->string[length + n_pad], &s->string[length], used);
1111
0
                memset(&s->string[length], pad, n_pad);
1112
0
            } else {
1113
0
                ds_put_char_multiple(s, pad, n_pad);
1114
0
            }
1115
0
        }
1116
0
    }
1117
0
}
1118
1119
/* Exports the given 'syslog_message' to the configured udp syslog sink. */
1120
static void
1121
send_to_syslog_fd(const char *s, size_t length)
1122
    OVS_REQ_RDLOCK(pattern_rwlock)
1123
0
{
1124
0
    static size_t max_length = SIZE_MAX;
1125
0
    size_t send_len = MIN(length, max_length);
1126
1127
0
    while (write(syslog_fd, s, send_len) < 0 && errno == EMSGSIZE) {
1128
0
        send_len -= send_len / 20;
1129
0
        max_length = send_len;
1130
0
    }
1131
0
}
1132
1133
/* Writes 'message' to the log at the given 'level' and as coming from the
1134
 * given 'module'.
1135
 *
1136
 * Guaranteed to preserve errno. */
1137
void
1138
vlog_valist(const struct vlog_module *module, enum vlog_level level,
1139
            const char *message, va_list args)
1140
0
{
1141
0
    bool log_to_console = module->levels[VLF_CONSOLE] >= level;
1142
0
    bool log_to_syslog = module->levels[VLF_SYSLOG] >= level;
1143
0
    bool log_to_file = module->levels[VLF_FILE]  >= level;
1144
1145
0
    if (!(log_to_console || log_to_syslog || log_to_file)) {
1146
        /* fast path - all logging levels specify no logging, no
1147
         * need to hog the log mutex
1148
         */
1149
0
        return;
1150
0
    }
1151
1152
0
    ovs_mutex_lock(&log_file_mutex);
1153
0
    log_to_file &= (log_fd >= 0);
1154
0
    ovs_mutex_unlock(&log_file_mutex);
1155
0
    if (log_to_console || log_to_syslog || log_to_file) {
1156
0
        int save_errno = errno;
1157
0
        struct ds s;
1158
1159
0
        vlog_init();
1160
1161
0
        ds_init(&s);
1162
0
        ds_reserve(&s, 1024);
1163
0
        ++*msg_num_get();
1164
1165
0
        ovs_rwlock_rdlock(&pattern_rwlock);
1166
0
        if (log_to_console) {
1167
0
            format_log_message(module, level,
1168
0
                               destinations[VLF_CONSOLE].pattern, message,
1169
0
                               args, &s);
1170
0
            ds_put_char(&s, '\n');
1171
0
            fputs(ds_cstr(&s), stderr);
1172
0
        }
1173
1174
0
        if (log_to_syslog) {
1175
0
            int syslog_level = syslog_levels[level];
1176
0
            char *save_ptr = NULL;
1177
0
            char *line;
1178
0
            int facility;
1179
1180
0
            format_log_message(module, level, destinations[VLF_SYSLOG].pattern,
1181
0
                               message, args, &s);
1182
0
            for (line = strtok_r(s.string, "\n", &save_ptr); line;
1183
0
                 line = strtok_r(NULL, "\n", &save_ptr)) {
1184
0
                atomic_read_explicit(&log_facility, &facility,
1185
0
                                     memory_order_relaxed);
1186
0
                syslogger->class->syslog(syslogger, syslog_level|facility, line);
1187
0
            }
1188
1189
0
            if (syslog_fd >= 0) {
1190
0
                format_log_message(module, level,
1191
0
                                   "<%B>1 %D{%Y-%m-%dT%H:%M:%S.###Z} "
1192
0
                                   "%E %A %P %c - \xef\xbb\xbf%m",
1193
0
                                   message, args, &s);
1194
0
                send_to_syslog_fd(ds_cstr(&s), s.length);
1195
0
            }
1196
0
        }
1197
1198
0
        if (log_to_file) {
1199
0
            format_log_message(module, level, destinations[VLF_FILE].pattern,
1200
0
                               message, args, &s);
1201
0
            ds_put_char(&s, '\n');
1202
1203
0
            ovs_mutex_lock(&log_file_mutex);
1204
0
            if (log_fd >= 0) {
1205
0
                if (log_writer) {
1206
0
                    async_append_write(log_writer, s.string, s.length);
1207
0
                    if (level == VLL_EMER) {
1208
0
                        async_append_flush(log_writer);
1209
0
                    }
1210
0
                } else {
1211
0
                    ignore(write(log_fd, s.string, s.length));
1212
0
                }
1213
0
            }
1214
0
            ovs_mutex_unlock(&log_file_mutex);
1215
0
        }
1216
0
        ovs_rwlock_unlock(&pattern_rwlock);
1217
1218
0
        ds_destroy(&s);
1219
0
        errno = save_errno;
1220
0
    }
1221
0
}
1222
1223
void
1224
vlog(const struct vlog_module *module, enum vlog_level level,
1225
     const char *message, ...)
1226
0
{
1227
0
    va_list args;
1228
1229
0
    va_start(args, message);
1230
0
    vlog_valist(module, level, message, args);
1231
0
    va_end(args);
1232
0
}
1233
1234
/* Logs 'message' to 'module' at maximum verbosity, then exits with a failure
1235
 * exit code.  Always writes the message to stderr, even if the console
1236
 * destination is disabled.
1237
 *
1238
 * Choose this function instead of vlog_abort_valist() if the daemon monitoring
1239
 * facility shouldn't automatically restart the current daemon.  */
1240
void
1241
vlog_fatal_valist(const struct vlog_module *module_,
1242
                  const char *message, va_list args)
1243
0
{
1244
0
    struct vlog_module *module = CONST_CAST(struct vlog_module *, module_);
1245
1246
    /* Don't log this message to the console to avoid redundancy with the
1247
     * message written by the later ovs_fatal_valist(). */
1248
0
    module->levels[VLF_CONSOLE] = VLL_OFF;
1249
1250
0
    vlog_valist(module, VLL_EMER, message, args);
1251
0
    ovs_fatal_valist(0, message, args);
1252
0
}
1253
1254
/* Logs 'message' to 'module' at maximum verbosity, then exits with a failure
1255
 * exit code.  Always writes the message to stderr, even if the console
1256
 * destination is disabled.
1257
 *
1258
 * Choose this function instead of vlog_abort() if the daemon monitoring
1259
 * facility shouldn't automatically restart the current daemon.  */
1260
void
1261
vlog_fatal(const struct vlog_module *module, const char *message, ...)
1262
0
{
1263
0
    va_list args;
1264
1265
0
    va_start(args, message);
1266
0
    vlog_fatal_valist(module, message, args);
1267
0
    va_end(args);
1268
0
}
1269
1270
/* Logs 'message' to 'module' at maximum verbosity, then calls abort().  Always
1271
 * writes the message to stderr, even if the console destination is disabled.
1272
 *
1273
 * Choose this function instead of vlog_fatal_valist() if the daemon monitoring
1274
 * facility should automatically restart the current daemon.  */
1275
void
1276
vlog_abort_valist(const struct vlog_module *module_,
1277
                  const char *message, va_list args)
1278
0
{
1279
0
    struct vlog_module *module = (struct vlog_module *) module_;
1280
1281
    /* Don't log this message to the console to avoid redundancy with the
1282
     * message written by the later ovs_abort_valist(). */
1283
0
    module->levels[VLF_CONSOLE] = VLL_OFF;
1284
1285
0
    vlog_valist(module, VLL_EMER, message, args);
1286
0
    ovs_abort_valist(0, message, args);
1287
0
}
1288
1289
/* Logs 'message' to 'module' at maximum verbosity, then calls abort().  Always
1290
 * writes the message to stderr, even if the console destination is disabled.
1291
 *
1292
 * Choose this function instead of vlog_fatal() if the daemon monitoring
1293
 * facility should automatically restart the current daemon.  */
1294
void
1295
vlog_abort(const struct vlog_module *module, const char *message, ...)
1296
0
{
1297
0
    va_list args;
1298
1299
0
    va_start(args, message);
1300
0
    vlog_abort_valist(module, message, args);
1301
0
    va_end(args);
1302
0
}
1303
1304
bool
1305
vlog_should_drop(const struct vlog_module *module, enum vlog_level level,
1306
                 struct vlog_rate_limit *rl)
1307
0
{
1308
0
    if (!module->honor_rate_limits) {
1309
0
        return false;
1310
0
    }
1311
1312
0
    if (!vlog_is_enabled(module, level)) {
1313
0
        return true;
1314
0
    }
1315
1316
0
    ovs_mutex_lock(&rl->mutex);
1317
0
    if (!token_bucket_withdraw(&rl->token_bucket, VLOG_MSG_TOKENS)) {
1318
0
        time_t now = time_now();
1319
0
        if (!rl->n_dropped) {
1320
0
            rl->first_dropped = now;
1321
0
        }
1322
0
        rl->last_dropped = now;
1323
0
        rl->n_dropped++;
1324
0
        ovs_mutex_unlock(&rl->mutex);
1325
0
        return true;
1326
0
    }
1327
1328
0
    if (!rl->n_dropped) {
1329
0
        ovs_mutex_unlock(&rl->mutex);
1330
0
    } else {
1331
0
        time_t now = time_now();
1332
0
        unsigned int n_dropped = rl->n_dropped;
1333
0
        unsigned int first_dropped_elapsed = now - rl->first_dropped;
1334
0
        unsigned int last_dropped_elapsed = now - rl->last_dropped;
1335
0
        rl->n_dropped = 0;
1336
0
        ovs_mutex_unlock(&rl->mutex);
1337
1338
0
        vlog(module, level,
1339
0
             "Dropped %u log messages in last %u seconds (most recently, "
1340
0
             "%u seconds ago) due to excessive rate",
1341
0
             n_dropped, first_dropped_elapsed, last_dropped_elapsed);
1342
0
    }
1343
1344
0
    return false;
1345
0
}
1346
1347
void
1348
vlog_rate_limit(const struct vlog_module *module, enum vlog_level level,
1349
                struct vlog_rate_limit *rl, const char *message, ...)
1350
0
{
1351
0
    if (!vlog_should_drop(module, level, rl)) {
1352
0
        va_list args;
1353
1354
0
        va_start(args, message);
1355
0
        vlog_valist(module, level, message, args);
1356
0
        va_end(args);
1357
0
    }
1358
0
}
1359
1360
void
1361
vlog_usage(void)
1362
0
{
1363
0
    printf("\n\
1364
0
Logging options:\n\
1365
0
  -vSPEC, --verbose=SPEC   set logging levels\n\
1366
0
  -v, --verbose            set maximum verbosity level\n\
1367
0
  --log-file[=FILE]        enable logging to specified FILE\n\
1368
0
                           (default: %s/%s.log)\n\
1369
0
  --syslog-method=(libc|unix:file|udp:ip:port)\n\
1370
0
                           specify how to send messages to syslog daemon\n\
1371
0
  --syslog-target=HOST:PORT  also send syslog msgs to HOST:PORT via UDP\n",
1372
0
           ovs_logdir(), program_name);
1373
0
}