~james-page/ubuntu/saucy/openvswitch/1.12-snapshot

« back to all changes in this revision

Viewing changes to lib/vlog.c

  • Committer: James Page
  • Date: 2013-08-21 10:16:57 UTC
  • mfrom: (1.1.20)
  • Revision ID: james.page@canonical.com-20130821101657-3o0z0qeiv5zkwlzi
New upstream snapshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#include <syslog.h>
29
29
#include <time.h>
30
30
#include <unistd.h>
 
31
#include "async-append.h"
31
32
#include "coverage.h"
32
33
#include "dirs.h"
33
34
#include "dynamic-string.h"
34
35
#include "ofpbuf.h"
 
36
#include "ovs-thread.h"
35
37
#include "sat-math.h"
36
38
#include "svec.h"
37
39
#include "timeval.h"
38
40
#include "unixctl.h"
39
41
#include "util.h"
40
 
#include "worker.h"
41
42
 
42
43
VLOG_DEFINE_THIS_MODULE(vlog);
43
44
 
49
50
#define ovs_assert use_assert_instead_of_ovs_assert_in_this_module
50
51
 
51
52
/* Name for each logging level. */
52
 
static const char *level_names[VLL_N_LEVELS] = {
 
53
static const char *const level_names[VLL_N_LEVELS] = {
53
54
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) #NAME,
54
55
    VLOG_LEVELS
55
56
#undef VLOG_LEVEL
56
57
};
57
58
 
58
59
/* Syslog value for each logging level. */
59
 
static int syslog_levels[VLL_N_LEVELS] = {
 
60
static const int syslog_levels[VLL_N_LEVELS] = {
60
61
#define VLOG_LEVEL(NAME, SYSLOG_LEVEL) SYSLOG_LEVEL,
61
62
    VLOG_LEVELS
62
63
#undef VLOG_LEVEL
81
82
#define n_vlog_modules ARRAY_SIZE(vlog_modules)
82
83
#endif
83
84
 
 
85
/* Protects the 'pattern' in all "struct facility"s, so that a race between
 
86
 * changing and reading the pattern does not cause an access to freed
 
87
 * memory. */
 
88
static struct ovs_rwlock pattern_rwlock = OVS_RWLOCK_INITIALIZER;
 
89
 
84
90
/* Information about each facility. */
85
91
struct facility {
86
92
    const char *name;           /* Name. */
87
 
    char *pattern;              /* Current pattern. */
 
93
    char *pattern OVS_GUARDED_BY(pattern_rwlock); /* Current pattern. */
88
94
    bool default_pattern;       /* Whether current pattern is the default. */
89
95
};
90
96
static struct facility facilities[VLF_N_FACILITIES] = {
93
99
#undef VLOG_FACILITY
94
100
};
95
101
 
96
 
/* VLF_FILE configuration. */
97
 
static char *log_file_name;
98
 
static int log_fd = -1;
 
102
/* Sequence number for the message currently being composed. */
 
103
DEFINE_PER_THREAD_DATA(unsigned int, msg_num, 0);
99
104
 
100
 
/* vlog initialized? */
101
 
static bool vlog_inited;
 
105
/* VLF_FILE configuration.
 
106
 *
 
107
 * All of the following is protected by 'log_file_mutex', which nests inside
 
108
 * pattern_rwlock. */
 
109
static struct ovs_mutex log_file_mutex = OVS_ADAPTIVE_MUTEX_INITIALIZER;
 
110
static char *log_file_name OVS_GUARDED_BY(log_file_mutex);
 
111
static int log_fd OVS_GUARDED_BY(log_file_mutex) = -1;
 
112
static struct async_append *log_writer OVS_GUARDED_BY(log_file_mutex);
102
113
 
103
114
static void format_log_message(const struct vlog_module *, enum vlog_level,
104
 
                               enum vlog_facility, unsigned int msg_num,
 
115
                               enum vlog_facility,
105
116
                               const char *message, va_list, struct ds *)
106
 
    PRINTF_FORMAT(5, 0);
107
 
static void vlog_write_file(struct ds *);
108
 
static void vlog_update_async_log_fd(void);
 
117
    PRINTF_FORMAT(4, 0) OVS_REQ_RDLOCK(&pattern_rwlock);
109
118
 
110
119
/* Searches the 'n_names' in 'names'.  Returns the index of a match for
111
120
 * 'target', or 'n_names' if no name matches. */
112
121
static size_t
113
 
search_name_array(const char *target, const char **names, size_t n_names)
 
122
search_name_array(const char *target, const char *const *names, size_t n_names)
114
123
{
115
124
    size_t i;
116
125
 
193
202
}
194
203
 
195
204
static void
196
 
update_min_level(struct vlog_module *module)
 
205
update_min_level(struct vlog_module *module) OVS_REQUIRES(&log_file_mutex)
197
206
{
198
207
    enum vlog_facility facility;
199
208
 
215
224
    assert(facility >= 0 && facility < VLF_N_FACILITIES);
216
225
    assert(level < VLL_N_LEVELS);
217
226
 
 
227
    ovs_mutex_lock(&log_file_mutex);
218
228
    if (!module) {
219
229
        struct vlog_module **mp;
220
230
 
226
236
        module->levels[facility] = level;
227
237
        update_min_level(module);
228
238
    }
 
239
    ovs_mutex_unlock(&log_file_mutex);
229
240
}
230
241
 
231
242
/* Sets the logging level for the given 'module' and 'facility' to 'level'.  A
249
260
do_set_pattern(enum vlog_facility facility, const char *pattern)
250
261
{
251
262
    struct facility *f = &facilities[facility];
 
263
 
 
264
    ovs_rwlock_wrlock(&pattern_rwlock);
252
265
    if (!f->default_pattern) {
253
266
        free(f->pattern);
254
267
    } else {
255
268
        f->default_pattern = false;
256
269
    }
257
270
    f->pattern = xstrdup(pattern);
 
271
    ovs_rwlock_unlock(&pattern_rwlock);
258
272
}
259
273
 
260
274
/* Sets the pattern for the given 'facility' to 'pattern'. */
271
285
    }
272
286
}
273
287
 
274
 
/* Returns the name of the log file used by VLF_FILE, or a null pointer if no
275
 
 * log file has been set.  (A non-null return value does not assert that the
276
 
 * named log file is in use: if vlog_set_log_file() or vlog_reopen_log_file()
277
 
 * fails, it still sets the log file name.) */
278
 
const char *
279
 
vlog_get_log_file(void)
280
 
{
281
 
    return log_file_name;
282
 
}
283
 
 
284
288
/* Sets the name of the log file used by VLF_FILE to 'file_name', or to the
285
289
 * default file name if 'file_name' is null.  Returns 0 if successful,
286
290
 * otherwise a positive errno value. */
287
291
int
288
292
vlog_set_log_file(const char *file_name)
289
293
{
290
 
    char *old_log_file_name;
 
294
    char *new_log_file_name;
291
295
    struct vlog_module **mp;
292
 
    int error;
293
 
 
294
 
    /* Close old log file. */
295
 
    if (log_fd >= 0) {
 
296
    struct stat old_stat;
 
297
    struct stat new_stat;
 
298
    int new_log_fd;
 
299
    bool same_file;
 
300
    bool log_close;
 
301
 
 
302
    /* Open new log file. */
 
303
    new_log_file_name = (file_name
 
304
                         ? xstrdup(file_name)
 
305
                         : xasprintf("%s/%s.log", ovs_logdir(), program_name));
 
306
    new_log_fd = open(new_log_file_name, O_WRONLY | O_CREAT | O_APPEND, 0666);
 
307
    if (new_log_fd < 0) {
 
308
        VLOG_WARN("failed to open %s for logging: %s",
 
309
                  new_log_file_name, ovs_strerror(errno));
 
310
        free(new_log_file_name);
 
311
        return errno;
 
312
    }
 
313
 
 
314
    /* If the new log file is the same one we already have open, bail out. */
 
315
    ovs_mutex_lock(&log_file_mutex);
 
316
    same_file = (log_fd >= 0
 
317
                 && new_log_fd >= 0
 
318
                 && !fstat(log_fd, &old_stat)
 
319
                 && !fstat(new_log_fd, &new_stat)
 
320
                 && old_stat.st_dev == new_stat.st_dev
 
321
                 && old_stat.st_ino == new_stat.st_ino);
 
322
    ovs_mutex_unlock(&log_file_mutex);
 
323
    if (same_file) {
 
324
        close(new_log_fd);
 
325
        free(new_log_file_name);
 
326
        return 0;
 
327
    }
 
328
 
 
329
    /* Log closing old log file (we can't log while holding log_file_mutex). */
 
330
    ovs_mutex_lock(&log_file_mutex);
 
331
    log_close = log_fd >= 0;
 
332
    ovs_mutex_unlock(&log_file_mutex);
 
333
    if (log_close) {
296
334
        VLOG_INFO("closing log file");
 
335
    }
 
336
 
 
337
    /* Close old log file, if any, and install new one. */
 
338
    ovs_mutex_lock(&log_file_mutex);
 
339
    if (log_fd >= 0) {
 
340
        free(log_file_name);
297
341
        close(log_fd);
298
 
        log_fd = -1;
299
 
    }
300
 
 
301
 
    /* Update log file name and free old name.  The ordering is important
302
 
     * because 'file_name' might be 'log_file_name' or some suffix of it. */
303
 
    old_log_file_name = log_file_name;
304
 
    log_file_name = (file_name
305
 
                     ? xstrdup(file_name)
306
 
                     : xasprintf("%s/%s.log", ovs_logdir(), program_name));
307
 
    free(old_log_file_name);
308
 
    file_name = NULL;           /* Might have been freed. */
309
 
 
310
 
    /* Open new log file and update min_levels[] to reflect whether we actually
311
 
     * have a log_file. */
312
 
    log_fd = open(log_file_name, O_WRONLY | O_CREAT | O_APPEND, 0666);
313
 
    if (log_fd >= 0) {
314
 
        vlog_update_async_log_fd();
315
 
    }
 
342
        async_append_destroy(log_writer);
 
343
    }
 
344
 
 
345
    log_file_name = xstrdup(new_log_file_name);
 
346
    log_fd = new_log_fd;
 
347
    log_writer = async_append_create(new_log_fd);
 
348
 
316
349
    for (mp = vlog_modules; mp < &vlog_modules[n_vlog_modules]; mp++) {
317
350
        update_min_level(*mp);
318
351
    }
319
 
 
320
 
    /* Log success or failure. */
321
 
    if (log_fd < 0) {
322
 
        VLOG_WARN("failed to open %s for logging: %s",
323
 
                  log_file_name, strerror(errno));
324
 
        error = errno;
325
 
    } else {
326
 
        VLOG_INFO("opened log file %s", log_file_name);
327
 
        error = 0;
328
 
    }
329
 
 
330
 
    return error;
 
352
    ovs_mutex_unlock(&log_file_mutex);
 
353
 
 
354
    /* Log opening new log file (we can't log while holding log_file_mutex). */
 
355
    VLOG_INFO("opened log file %s", new_log_file_name);
 
356
    free(new_log_file_name);
 
357
 
 
358
    return 0;
331
359
}
332
360
 
333
361
/* Closes and then attempts to re-open the current log file.  (This is useful
336
364
int
337
365
vlog_reopen_log_file(void)
338
366
{
339
 
    struct stat old, new;
340
 
 
341
 
    /* Skip re-opening if there's nothing to reopen. */
342
 
    if (!log_file_name) {
343
 
        return 0;
344
 
    }
345
 
 
346
 
    /* Skip re-opening if it would be a no-op because the old and new files are
347
 
     * the same.  (This avoids writing "closing log file" followed immediately
348
 
     * by "opened log file".) */
349
 
    if (log_fd >= 0
350
 
        && !fstat(log_fd, &old)
351
 
        && !stat(log_file_name, &new)
352
 
        && old.st_dev == new.st_dev
353
 
        && old.st_ino == new.st_ino) {
354
 
        return 0;
355
 
    }
356
 
 
357
 
    return vlog_set_log_file(log_file_name);
 
367
    char *fn;
 
368
 
 
369
    ovs_mutex_lock(&log_file_mutex);
 
370
    fn = log_file_name ? xstrdup(log_file_name) : NULL;
 
371
    ovs_mutex_unlock(&log_file_mutex);
 
372
 
 
373
    if (fn) {
 
374
        int error = vlog_set_log_file(fn);
 
375
        free(fn);
 
376
        return error;
 
377
    } else {
 
378
        return 0;
 
379
    }
358
380
}
359
381
 
360
382
/* Set debugging levels.  Returns null if successful, otherwise an error
486
508
vlog_unixctl_reopen(struct unixctl_conn *conn, int argc OVS_UNUSED,
487
509
                    const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
488
510
{
489
 
    if (log_file_name) {
 
511
    bool has_log_file;
 
512
 
 
513
    ovs_mutex_lock(&log_file_mutex);
 
514
    has_log_file = log_file_name != NULL;
 
515
    ovs_mutex_unlock(&log_file_mutex);
 
516
 
 
517
    if (has_log_file) {
490
518
        int error = vlog_reopen_log_file();
491
519
        if (error) {
492
 
            unixctl_command_reply_error(conn, strerror(errno));
 
520
            unixctl_command_reply_error(conn, ovs_strerror(errno));
493
521
        } else {
494
522
            unixctl_command_reply(conn, NULL);
495
523
        }
547
575
    set_rate_limits(conn, argc, argv, false);
548
576
}
549
577
 
550
 
/* Initializes the logging subsystem and registers its unixctl server
551
 
 * commands. */
552
 
void
553
 
vlog_init(void)
 
578
static void
 
579
vlog_init__(void)
554
580
{
555
581
    static char *program_name_copy;
556
582
    time_t now;
557
583
 
558
 
    if (vlog_inited) {
559
 
        return;
560
 
    }
561
 
    vlog_inited = true;
562
 
 
563
584
    /* openlog() is allowed to keep the pointer passed in, without making a
564
585
     * copy.  The daemonize code sometimes frees and replaces 'program_name',
565
586
     * so make a private copy just for openlog().  (We keep a pointer to the
570
591
 
571
592
    now = time_wall();
572
593
    if (now < 0) {
573
 
        struct tm tm;
574
 
        char s[128];
575
 
 
576
 
        gmtime_r(&now, &tm);
577
 
        strftime(s, sizeof s, "%a, %d %b %Y %H:%M:%S", &tm);
 
594
        char *s = xastrftime("%a, %d %b %Y %H:%M:%S", now, true);
578
595
        VLOG_ERR("current time is negative: %s (%ld)", s, (long int) now);
 
596
        free(s);
579
597
    }
580
598
 
581
599
    unixctl_command_register(
590
608
                             vlog_unixctl_reopen, NULL);
591
609
}
592
610
 
593
 
/* Closes the logging subsystem. */
 
611
/* Initializes the logging subsystem and registers its unixctl server
 
612
 * commands. */
594
613
void
595
 
vlog_exit(void)
 
614
vlog_init(void)
596
615
{
597
 
    if (vlog_inited) {
598
 
        closelog();
599
 
        vlog_inited = false;
600
 
    }
 
616
    static pthread_once_t once = PTHREAD_ONCE_INIT;
 
617
    pthread_once(&once, vlog_init__);
601
618
}
602
619
 
603
620
/* Print the current logging level for each module. */
665
682
 
666
683
static void
667
684
format_log_message(const struct vlog_module *module, enum vlog_level level,
668
 
                   enum vlog_facility facility, unsigned int msg_num,
 
685
                   enum vlog_facility facility,
669
686
                   const char *message, va_list args_, struct ds *s)
670
687
{
671
688
    char tmp[128];
674
691
 
675
692
    ds_clear(s);
676
693
    for (p = facilities[facility].pattern; *p != '\0'; ) {
 
694
        const char *subprogram_name;
677
695
        enum { LEFT, RIGHT } justify = RIGHT;
678
696
        int pad = '0';
679
697
        size_t length, field, used;
709
727
            break;
710
728
        case 'd':
711
729
            p = fetch_braces(p, "%Y-%m-%d %H:%M:%S", tmp, sizeof tmp);
712
 
            ds_put_strftime(s, tmp, false);
 
730
            ds_put_strftime(s, tmp, time_wall(), false);
713
731
            break;
714
732
        case 'D':
715
733
            p = fetch_braces(p, "%Y-%m-%d %H:%M:%S", tmp, sizeof tmp);
716
 
            ds_put_strftime(s, tmp, true);
 
734
            ds_put_strftime(s, tmp, time_wall(), true);
717
735
            break;
718
736
        case 'm':
719
737
            /* Format user-supplied log message and trim trailing new-lines. */
726
744
            }
727
745
            break;
728
746
        case 'N':
729
 
            ds_put_format(s, "%u", msg_num);
 
747
            ds_put_format(s, "%u", *msg_num_get_unsafe());
730
748
            break;
731
749
        case 'n':
732
750
            ds_put_char(s, '\n');
741
759
            ds_put_format(s, "%lld", time_msec() - time_boot_msec());
742
760
            break;
743
761
        case 't':
 
762
            subprogram_name = get_subprogram_name();
744
763
            ds_put_cstr(s, subprogram_name[0] ? subprogram_name : "main");
745
764
            break;
746
765
        case 'T':
 
766
            subprogram_name = get_subprogram_name();
747
767
            if (subprogram_name[0]) {
748
768
                ds_put_format(s, "(%s)", subprogram_name);
749
769
            }
776
796
{
777
797
    bool log_to_console = module->levels[VLF_CONSOLE] >= level;
778
798
    bool log_to_syslog = module->levels[VLF_SYSLOG] >= level;
779
 
    bool log_to_file = module->levels[VLF_FILE] >= level && log_fd >= 0;
 
799
    bool log_to_file;
 
800
 
 
801
    ovs_mutex_lock(&log_file_mutex);
 
802
    log_to_file = module->levels[VLF_FILE] >= level && log_fd >= 0;
 
803
    ovs_mutex_unlock(&log_file_mutex);
780
804
    if (log_to_console || log_to_syslog || log_to_file) {
781
805
        int save_errno = errno;
782
 
        static unsigned int msg_num;
783
806
        struct ds s;
784
807
 
785
808
        vlog_init();
786
809
 
787
810
        ds_init(&s);
788
811
        ds_reserve(&s, 1024);
789
 
        msg_num++;
 
812
        ++*msg_num_get();
790
813
 
 
814
        ovs_rwlock_rdlock(&pattern_rwlock);
791
815
        if (log_to_console) {
792
 
            format_log_message(module, level, VLF_CONSOLE, msg_num,
793
 
                               message, args, &s);
 
816
            format_log_message(module, level, VLF_CONSOLE, message, args, &s);
794
817
            ds_put_char(&s, '\n');
795
818
            fputs(ds_cstr(&s), stderr);
796
819
        }
800
823
            char *save_ptr = NULL;
801
824
            char *line;
802
825
 
803
 
            format_log_message(module, level, VLF_SYSLOG, msg_num,
804
 
                               message, args, &s);
 
826
            format_log_message(module, level, VLF_SYSLOG, message, args, &s);
805
827
            for (line = strtok_r(s.string, "\n", &save_ptr); line;
806
828
                 line = strtok_r(NULL, "\n", &save_ptr)) {
807
829
                syslog(syslog_level, "%s", line);
809
831
        }
810
832
 
811
833
        if (log_to_file) {
812
 
            format_log_message(module, level, VLF_FILE, msg_num,
813
 
                               message, args, &s);
 
834
            format_log_message(module, level, VLF_FILE, message, args, &s);
814
835
            ds_put_char(&s, '\n');
815
 
            vlog_write_file(&s);
 
836
 
 
837
            ovs_mutex_lock(&log_file_mutex);
 
838
            if (log_fd >= 0) {
 
839
                async_append_write(log_writer, s.string, s.length);
 
840
                if (level == VLL_EMER) {
 
841
                    async_append_flush(log_writer);
 
842
                }
 
843
            }
 
844
            ovs_mutex_unlock(&log_file_mutex);
816
845
        }
 
846
        ovs_rwlock_unlock(&pattern_rwlock);
817
847
 
818
848
        ds_destroy(&s);
819
849
        errno = save_errno;
913
943
        return true;
914
944
    }
915
945
 
 
946
    ovs_mutex_lock(&rl->mutex);
916
947
    if (!token_bucket_withdraw(&rl->token_bucket, VLOG_MSG_TOKENS)) {
917
948
        time_t now = time_now();
918
949
        if (!rl->n_dropped) {
920
951
        }
921
952
        rl->last_dropped = now;
922
953
        rl->n_dropped++;
 
954
        ovs_mutex_unlock(&rl->mutex);
923
955
        return true;
924
956
    }
925
957
 
926
 
    if (rl->n_dropped) {
 
958
    if (!rl->n_dropped) {
 
959
        ovs_mutex_unlock(&rl->mutex);
 
960
    } else {
927
961
        time_t now = time_now();
 
962
        unsigned int n_dropped = rl->n_dropped;
928
963
        unsigned int first_dropped_elapsed = now - rl->first_dropped;
929
964
        unsigned int last_dropped_elapsed = now - rl->last_dropped;
 
965
        rl->n_dropped = 0;
 
966
        ovs_mutex_unlock(&rl->mutex);
930
967
 
931
968
        vlog(module, level,
932
969
             "Dropped %u log messages in last %u seconds (most recently, "
933
970
             "%u seconds ago) due to excessive rate",
934
 
             rl->n_dropped, first_dropped_elapsed, last_dropped_elapsed);
 
971
             n_dropped, first_dropped_elapsed, last_dropped_elapsed);
 
972
    }
935
973
 
936
 
        rl->n_dropped = 0;
937
 
    }
938
974
    return false;
939
975
}
940
976
 
961
997
           "                          (default: %s/%s.log)\n",
962
998
           ovs_logdir(), program_name);
963
999
}
964
 
 
965
 
static bool vlog_async_inited = false;
966
 
 
967
 
static worker_request_func vlog_async_write_request_cb;
968
 
 
969
 
static void
970
 
vlog_write_file(struct ds *s)
971
 
{
972
 
    if (worker_is_running()) {
973
 
        static bool in_worker_request = false;
974
 
        if (!in_worker_request) {
975
 
            in_worker_request = true;
976
 
 
977
 
            worker_request(s->string, s->length,
978
 
                           &log_fd, vlog_async_inited ? 0 : 1,
979
 
                           vlog_async_write_request_cb, NULL, NULL);
980
 
            vlog_async_inited = true;
981
 
 
982
 
            in_worker_request = false;
983
 
            return;
984
 
        } else {
985
 
            /* We've been entered recursively.  This can happen if
986
 
             * worker_request(), or a function that it calls, tries to log
987
 
             * something.  We can't call worker_request() recursively, so fall
988
 
             * back to writing the log file directly. */
989
 
            COVERAGE_INC(vlog_recursive);
990
 
        }
991
 
    }
992
 
    ignore(write(log_fd, s->string, s->length));
993
 
}
994
 
 
995
 
static void
996
 
vlog_update_async_log_fd(void)
997
 
{
998
 
    if (worker_is_running()) {
999
 
        worker_request(NULL, 0, &log_fd, 1, vlog_async_write_request_cb,
1000
 
                       NULL, NULL);
1001
 
        vlog_async_inited = true;
1002
 
    }
1003
 
}
1004
 
 
1005
 
static void
1006
 
vlog_async_write_request_cb(struct ofpbuf *request,
1007
 
                            const int *fd, size_t n_fds)
1008
 
{
1009
 
    if (n_fds > 0) {
1010
 
        if (log_fd >= 0) {
1011
 
            close(log_fd);
1012
 
        }
1013
 
        log_fd = *fd;
1014
 
    }
1015
 
 
1016
 
    if (request->size > 0) {
1017
 
        ignore(write(log_fd, request->data, request->size));
1018
 
    }
1019
 
}