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 |
|
|
} |