GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/log.c Lines: 34 53 64.2 %
Date: 2020-12-10 21:44:00 Branches: 7 14 50.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 2017 rxi
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 * of this software and associated documentation files (the "Software"), to
6
 * deal in the Software without restriction, including without limitation the
7
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
 * sell copies of the Software, and to permit persons to whom the Software is
9
 * furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in
12
 * all copies or substantial portions of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
 * IN THE SOFTWARE.
21
 */
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <stdarg.h>
26
#include <string.h>
27
#include <time.h>
28
#include <sys/time.h>
29
#include <pthread.h>
30
31
#include "log.h"
32
#include "predict.h"
33
34
static struct {
35
    void *udata;
36
    log_LockFn lock;
37
    FILE *fp;
38
    int level;
39
    int quiet;
40
} L;
41
42
static int year;
43
static int month;
44
static int day;
45
static int hour;
46
static int minutes;
47
static int seconds;
48
static int usec;
49
50
static struct timeval tv;
51
static struct tm *tm;
52
53
static const char *level_names[] = {
54
    "FATAL",
55
    "ERROR",
56
    "WARN",
57
    "INFO",
58
    "DEBUG",
59
    "TRACE"
60
};
61
62
static const char *level_colors[] = {
63
    "\x1b[35m",
64
    "\x1b[31m",
65
    "\x1b[33m",
66
    "\x1b[32m",
67
    "\x1b[36m",
68
    "\x1b[94m"
69
};
70
71
10
static inline void time_to_str(char *buf) {
72
10
    gettimeofday(&tv, NULL);
73
10
    tm = localtime(&tv.tv_sec);
74
    /* Add 1900 to get the right year value read the manual page for localtime() */
75
10
    year    = tm->tm_year + 1900;
76
    /* Months are 0 indexed in struct tm */
77
10
    month   = tm->tm_mon + 1;
78
10
    day     = tm->tm_mday;
79
10
    hour    = tm->tm_hour;
80
10
    minutes = tm->tm_min;
81
10
    seconds = tm->tm_sec;
82
10
    usec    = tv.tv_usec;
83
    // buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", lt)] = '\0';
84
10
    int len = sprintf(buf,
85
            "%04d-%02d-%02d %02d:%02d:%02d.%06d ",
86
            year,
87
            month,
88
            day,
89
            hour,
90
            minutes,
91
            seconds,
92
            usec);
93
10
    buf[len] = '\0';
94
10
}
95
96
10
static inline void lock(void) {
97
10
    if ( likely(L.lock) ) {
98
        L.lock(L.udata, 1);
99
    }
100
}
101
102
10
static inline void unlock(void) {
103
10
    if ( likely(L.lock) ) {
104
        L.lock(L.udata, 0);
105
    }
106
}
107
108
void log_set_udata(void *udata) {
109
    L.udata = udata;
110
}
111
112
void log_set_lock(log_LockFn fn) {
113
    L.lock = fn;
114
}
115
116
void log_set_fp(FILE *fp) {
117
    L.fp = fp;
118
}
119
120
void log_set_level(int level) {
121
    L.level = level;
122
}
123
124
void log_set_quiet(int enable) {
125
    L.quiet = enable ? 1 : 0;
126
}
127
128
1096
void log_log(int level, const char *file, int line, const char *fmt, ...) {
129
1096
    if ( likely(level > L.level) ) {
130
1086
        return;
131

10
    } else if ( unlikely(L.quiet && !L.fp) ) {
132
        return;
133
    }
134
135
10
    char time_string[100];
136
137
    /* Acquire lock */
138
10
    lock();
139
140
10
    time_to_str(time_string);
141
142
    /* Log to stderr */
143
10
    if ( unlikely(!L.quiet) ) {
144
10
        va_list args;
145
146
10
        fprintf(
147
                stderr, "[%lu] %s %s %-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ",
148
                pthread_self(), time_string, level_colors[level], level_names[level], file, line);
149
10
        va_start(args, fmt);
150
10
        vfprintf(stderr, fmt, args);
151
10
        va_end(args);
152
10
        fprintf(stderr, "\n");
153
10
        fflush(stderr);
154
    }
155
156
    /* Log to file */
157
10
    if ( likely(L.fp) ) {
158
        va_list args;
159
        fprintf(L.fp, "[%lu] %s %-5s %s:%d: ", pthread_self(), time_string, level_names[level], file, line);
160
        va_start(args, fmt);
161
        vfprintf(L.fp, fmt, args);
162
        va_end(args);
163
        fprintf(L.fp, "\n");
164
        fflush(L.fp);
165
    }
166
167
    /* Release lock */
168
10
    unlock();
169
}