Directory: | cvmfs/ |
---|---|
File: | cvmfs/util/logging.cc |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 225 | 326 | 69.0% |
Branches: | 157 | 303 | 51.8% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | * | ||
4 | * LogCvmfs() handles all message output. It works like printf. | ||
5 | * It can log to a debug log file, stdout, stderr, and syslog. | ||
6 | * The tracer is a separate module, messages do not overlap with logging. | ||
7 | * | ||
8 | * The syslog setter routines are not thread-safe. They are meant to be | ||
9 | * invoked at the very first, single-threaded stage. | ||
10 | * | ||
11 | * If DEBUGMSG is undefined, pure debug messages are compiled into no-ops. | ||
12 | */ | ||
13 | |||
14 | #include "util/logging_internal.h" // NOLINT(build/include) | ||
15 | |||
16 | #include <errno.h> | ||
17 | #include <fcntl.h> | ||
18 | #include <pthread.h> | ||
19 | #include <syslog.h> | ||
20 | #include <time.h> | ||
21 | #include <unistd.h> | ||
22 | |||
23 | #include <cassert> | ||
24 | #include <cstdio> | ||
25 | #include <cstdlib> | ||
26 | #include <cstring> | ||
27 | #include <ctime> | ||
28 | #include <vector> | ||
29 | |||
30 | #include "util/export.h" | ||
31 | #include "util/mutex.h" | ||
32 | #include "util/platform.h" | ||
33 | #include "util/posix.h" | ||
34 | #include "util/single_copy.h" | ||
35 | #include "util/smalloc.h" | ||
36 | |||
37 | using namespace std; // NOLINT | ||
38 | |||
39 | #ifdef CVMFS_NAMESPACE_GUARD | ||
40 | namespace CVMFS_NAMESPACE_GUARD { | ||
41 | #endif | ||
42 | |||
43 | static void LogCustom(unsigned id, const std::string &message); | ||
44 | |||
45 | LogFacilities DefaultLogging::info = kLogSyslog; | ||
46 | LogFacilities DefaultLogging::error = kLogSyslogErr; | ||
47 | |||
48 | ✗ | void DefaultLogging::Set(LogFacilities info, LogFacilities error) { | |
49 | ✗ | DefaultLogging::info = info; | |
50 | ✗ | DefaultLogging::error = error; | |
51 | } | ||
52 | |||
53 | namespace { | ||
54 | |||
55 | unsigned gMicroSyslogMax = 500 * 1024; // default: rotate after 500kB | ||
56 | |||
57 | pthread_mutex_t lock_stdout = PTHREAD_MUTEX_INITIALIZER; | ||
58 | pthread_mutex_t lock_stderr = PTHREAD_MUTEX_INITIALIZER; | ||
59 | #ifdef DEBUGMSG | ||
60 | pthread_mutex_t lock_debug = PTHREAD_MUTEX_INITIALIZER; | ||
61 | FILE *file_debug = NULL; | ||
62 | string *path_debug = NULL; | ||
63 | #endif | ||
64 | const char *module_names[] = { | ||
65 | "unknown", "cache", "catalog", "sql", | ||
66 | "cvmfs", "hash", "download", "compress", | ||
67 | "quota", "talk", "monitor", "lru", | ||
68 | "fuse stub", "signature", "fs traversal", "catalog traversal", | ||
69 | "nfs maps", "publish", "spooler", "concurrency", | ||
70 | "utility", "glue buffer", "history", "unionfs", | ||
71 | "pathspec", "receiver", "upload s3", "upload http", | ||
72 | "s3fanout", "gc", "dns", "authz", | ||
73 | "reflog", "kvstore", "telemetry", "curl"}; | ||
74 | int syslog_facility = LOG_USER; | ||
75 | int syslog_level = LOG_NOTICE; | ||
76 | char *syslog_prefix = NULL; | ||
77 | |||
78 | string *usyslog_dest = NULL; | ||
79 | int usyslog_fd = -1; | ||
80 | int usyslog_fd1 = -1; | ||
81 | unsigned usyslog_size = 0; | ||
82 | pthread_mutex_t lock_usyslock = PTHREAD_MUTEX_INITIALIZER; | ||
83 | |||
84 | const unsigned kMaxCustomlog = 3; | ||
85 | string *customlog_dests[] = {NULL, NULL, NULL}; | ||
86 | int customlog_fds[] = {-1, -1, -1}; | ||
87 | pthread_mutex_t customlog_locks[] = { | ||
88 | PTHREAD_MUTEX_INITIALIZER, | ||
89 | PTHREAD_MUTEX_INITIALIZER, | ||
90 | PTHREAD_MUTEX_INITIALIZER}; | ||
91 | |||
92 | LogLevels max_log_level = kLogNormal; | ||
93 | static void (*alt_log_func)(const LogSource source, const int mask, | ||
94 | const char *msg) = NULL; | ||
95 | |||
96 | /** | ||
97 | * Circular buffer of the last $n$ calls to LogCvmfs(). Thread-safe class. | ||
98 | */ | ||
99 | class LogBuffer : SingleCopy { | ||
100 | public: | ||
101 | 3 | LogBuffer() : next_id_(0) { | |
102 | 3 | int retval = pthread_mutex_init(&lock_, NULL); | |
103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | assert(retval == 0); |
104 | 3 | } | |
105 | |||
106 | 56 | ~LogBuffer() { | |
107 | 56 | pthread_mutex_destroy(&lock_); | |
108 | 56 | } | |
109 | |||
110 | 1253471 | void Append(const LogBufferEntry &entry) { | |
111 | 1253471 | MutexLockGuard lock_guard(lock_); | |
112 | 1253477 | size_t idx = next_id_++ % kBufferSize; | |
113 |
2/2✓ Branch 1 taken 115 times.
✓ Branch 2 taken 1253362 times.
|
1253477 | if (idx >= buffer_.size()) { |
114 |
1/2✓ Branch 1 taken 115 times.
✗ Branch 2 not taken.
|
115 | buffer_.push_back(entry); |
115 | } else { | ||
116 |
1/2✓ Branch 2 taken 1253362 times.
✗ Branch 3 not taken.
|
1253362 | buffer_[idx] = entry; |
117 | } | ||
118 | 1253477 | } | |
119 | |||
120 | 6 | std::vector<LogBufferEntry> GetBuffer() { | |
121 | // Return a buffer sorted from newest to oldest buffer | ||
122 | 6 | std::vector<LogBufferEntry> sorted_buffer; | |
123 | 6 | MutexLockGuard lock_guard(lock_); | |
124 |
2/2✓ Branch 1 taken 31 times.
✓ Branch 2 taken 6 times.
|
37 | for (unsigned i = 1; i <= buffer_.size(); ++i) { |
125 | 31 | unsigned idx = (next_id_ - i) % kBufferSize; | |
126 |
1/2✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
|
31 | sorted_buffer.push_back(buffer_[idx]); |
127 | } | ||
128 | 12 | return sorted_buffer; | |
129 | 6 | } | |
130 | |||
131 | 1 | void Clear() { | |
132 | 1 | MutexLockGuard lock_guard(lock_); | |
133 | 1 | next_id_ = 0; | |
134 | 1 | buffer_.clear(); | |
135 | 1 | } | |
136 | |||
137 | private: | ||
138 | static const unsigned kBufferSize = 10; | ||
139 | pthread_mutex_t lock_; | ||
140 | int next_id_; | ||
141 | std::vector<LogBufferEntry> buffer_; | ||
142 | }; | ||
143 | |||
144 | LogBuffer g_log_buffer; | ||
145 | |||
146 | } // namespace | ||
147 | |||
148 | /** | ||
149 | * Sets the level that is used for all messages to the syslog facility. | ||
150 | */ | ||
151 | 11 | void SetLogSyslogLevel(const int level) { | |
152 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | switch (level) { |
153 | ✗ | case 1: | |
154 | ✗ | syslog_level = LOG_DEBUG; | |
155 | ✗ | break; | |
156 | ✗ | case 2: | |
157 | ✗ | syslog_level = LOG_INFO; | |
158 | ✗ | break; | |
159 | 11 | case 3: | |
160 | 11 | syslog_level = LOG_NOTICE; | |
161 | 11 | break; | |
162 | ✗ | default: | |
163 | ✗ | syslog_level = LOG_NOTICE; | |
164 | ✗ | break; | |
165 | } | ||
166 | 11 | } | |
167 | |||
168 | 3 | int GetLogSyslogLevel() { | |
169 |
1/3✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | switch (syslog_level) { |
170 | ✗ | case LOG_DEBUG: | |
171 | ✗ | return 1; | |
172 | ✗ | case LOG_INFO: | |
173 | ✗ | return 2; | |
174 | 3 | default: | |
175 | 3 | return 3; | |
176 | } | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * Sets the syslog facility to one of local0 .. local7. | ||
181 | * Falls back to LOG_USER if local_facility is not in [0..7] | ||
182 | */ | ||
183 | ✗ | void SetLogSyslogFacility(const int local_facility) { | |
184 | ✗ | switch (local_facility) { | |
185 | ✗ | case 0: | |
186 | ✗ | syslog_facility = LOG_LOCAL0; | |
187 | ✗ | break; | |
188 | ✗ | case 1: | |
189 | ✗ | syslog_facility = LOG_LOCAL1; | |
190 | ✗ | break; | |
191 | ✗ | case 2: | |
192 | ✗ | syslog_facility = LOG_LOCAL2; | |
193 | ✗ | break; | |
194 | ✗ | case 3: | |
195 | ✗ | syslog_facility = LOG_LOCAL3; | |
196 | ✗ | break; | |
197 | ✗ | case 4: | |
198 | ✗ | syslog_facility = LOG_LOCAL4; | |
199 | ✗ | break; | |
200 | ✗ | case 5: | |
201 | ✗ | syslog_facility = LOG_LOCAL5; | |
202 | ✗ | break; | |
203 | ✗ | case 6: | |
204 | ✗ | syslog_facility = LOG_LOCAL6; | |
205 | ✗ | break; | |
206 | ✗ | case 7: | |
207 | ✗ | syslog_facility = LOG_LOCAL7; | |
208 | ✗ | break; | |
209 | ✗ | default: | |
210 | ✗ | syslog_facility = LOG_USER; | |
211 | } | ||
212 | } | ||
213 | |||
214 | 3 | int GetLogSyslogFacility() { | |
215 |
1/9✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
|
3 | switch (syslog_facility) { |
216 | ✗ | case LOG_LOCAL0: | |
217 | ✗ | return 0; | |
218 | ✗ | case LOG_LOCAL1: | |
219 | ✗ | return 1; | |
220 | ✗ | case LOG_LOCAL2: | |
221 | ✗ | return 2; | |
222 | ✗ | case LOG_LOCAL3: | |
223 | ✗ | return 3; | |
224 | ✗ | case LOG_LOCAL4: | |
225 | ✗ | return 4; | |
226 | ✗ | case LOG_LOCAL5: | |
227 | ✗ | return 5; | |
228 | ✗ | case LOG_LOCAL6: | |
229 | ✗ | return 6; | |
230 | ✗ | case LOG_LOCAL7: | |
231 | ✗ | return 7; | |
232 | 3 | default: | |
233 | 3 | return -1; | |
234 | } | ||
235 | } | ||
236 | |||
237 | /** | ||
238 | * The syslog prefix is used to distinguish multiple repositories in | ||
239 | * /var/log/messages | ||
240 | */ | ||
241 | 151 | void SetLogSyslogPrefix(const std::string &prefix) { | |
242 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 76 times.
|
151 | if (syslog_prefix) free(syslog_prefix); |
243 | |||
244 |
2/2✓ Branch 1 taken 73 times.
✓ Branch 2 taken 78 times.
|
151 | if (prefix == "") { |
245 | 73 | syslog_prefix = NULL; | |
246 | } else { | ||
247 | 78 | unsigned len = prefix.length() + 1; | |
248 | 78 | syslog_prefix = static_cast<char *>(smalloc(len)); | |
249 | 78 | syslog_prefix[len - 1] = '\0'; | |
250 | 78 | memcpy(syslog_prefix, &prefix[0], prefix.length()); | |
251 | } | ||
252 | 151 | } | |
253 | |||
254 | ✗ | void SetLogSyslogShowPID(bool flag) { | |
255 | ✗ | openlog(NULL, flag ? LOG_PID : 0, GetLogSyslogFacility()); | |
256 | } | ||
257 | |||
258 | /** | ||
259 | * Set the maximum verbosity level. By default kLogNormal. | ||
260 | */ | ||
261 | 2 | void SetLogVerbosity(const LogLevels max_level) { max_log_level = max_level; } | |
262 | |||
263 | |||
264 | 1 | void SetLogMicroSyslogMaxSize(unsigned bytes) { | |
265 | 1 | gMicroSyslogMax = bytes; | |
266 | 1 | } | |
267 | |||
268 | /** | ||
269 | * "Micro-Syslog" write kLogSyslog messages into filename. It rotates this | ||
270 | * file. Requires for µCernVM | ||
271 | */ | ||
272 | 177 | void SetLogMicroSyslog(const std::string &filename) { | |
273 | 177 | pthread_mutex_lock(&lock_usyslock); | |
274 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 175 times.
|
177 | if (usyslog_fd >= 0) { |
275 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | close(usyslog_fd); |
276 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | close(usyslog_fd1); |
277 | 2 | usyslog_fd = -1; | |
278 | 2 | usyslog_fd1 = -1; | |
279 | } | ||
280 | |||
281 |
2/2✓ Branch 1 taken 175 times.
✓ Branch 2 taken 2 times.
|
177 | if (filename == "") { |
282 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 173 times.
|
175 | delete usyslog_dest; |
283 | 175 | usyslog_dest = NULL; | |
284 | 175 | pthread_mutex_unlock(&lock_usyslock); | |
285 | 175 | return; | |
286 | } | ||
287 | |||
288 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | usyslog_fd = open(filename.c_str(), O_RDWR | O_APPEND | O_CREAT, 0600); |
289 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (usyslog_fd < 0) { |
290 | ✗ | fprintf(stderr, "could not open usyslog file %s (%d), aborting\n", | |
291 | ✗ | filename.c_str(), errno); | |
292 | ✗ | abort(); | |
293 | } | ||
294 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
|
2 | usyslog_fd1 = open((filename + ".1").c_str(), O_WRONLY | O_CREAT, 0600); |
295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (usyslog_fd1 < 0) { |
296 | ✗ | fprintf(stderr, "could not open usyslog.1 file %s.1 (%d), aborting\n", | |
297 | ✗ | filename.c_str(), errno); | |
298 | ✗ | abort(); | |
299 | } | ||
300 | platform_stat64 info; | ||
301 | 2 | int retval = platform_fstat(usyslog_fd, &info); | |
302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | assert(retval == 0); |
303 | 2 | usyslog_size = info.st_size; | |
304 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | usyslog_dest = new string(filename); |
305 | 2 | pthread_mutex_unlock(&lock_usyslock); | |
306 | } | ||
307 | |||
308 | 49 | std::string GetLogMicroSyslog() { | |
309 | 49 | pthread_mutex_lock(&lock_usyslock); | |
310 | 49 | string result; | |
311 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
49 | if (usyslog_dest) result = *usyslog_dest; |
312 | 49 | pthread_mutex_unlock(&lock_usyslock); | |
313 | 49 | return result; | |
314 | } | ||
315 | |||
316 | 1004 | static void LogMicroSyslog(const std::string &message) { | |
317 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1004 times.
|
1004 | if (message.size() == 0) return; |
318 | |||
319 | 1004 | pthread_mutex_lock(&lock_usyslock); | |
320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1004 times.
|
1004 | if (usyslog_fd < 0) { |
321 | ✗ | pthread_mutex_unlock(&lock_usyslock); | |
322 | ✗ | return; | |
323 | } | ||
324 | |||
325 | 1004 | int written = write(usyslog_fd, message.data(), message.size()); | |
326 |
3/6✓ Branch 0 taken 1004 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1004 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1004 times.
|
1004 | if ((written < 0) || (static_cast<unsigned>(written) != message.size())) { |
327 | ✗ | close(usyslog_fd); | |
328 | ✗ | usyslog_fd = -1; | |
329 | ✗ | abort(); | |
330 | } | ||
331 | 1004 | int retval = fsync(usyslog_fd); | |
332 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1004 times.
|
1004 | assert(retval == 0); |
333 | 1004 | usyslog_size += written; | |
334 | |||
335 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 995 times.
|
1004 | if (usyslog_size >= gMicroSyslogMax) { |
336 | // Wipe out usyslog.1 file | ||
337 | 9 | retval = ftruncate(usyslog_fd1, 0); | |
338 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(retval == 0); |
339 | |||
340 | // Copy from usyslog to usyslog.1 | ||
341 | 9 | retval = lseek(usyslog_fd, 0, SEEK_SET); | |
342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(retval == 0); |
343 | unsigned char buf[4096]; | ||
344 | int num_bytes; | ||
345 | do { | ||
346 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | num_bytes = read(usyslog_fd, buf, 4096); |
347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(num_bytes >= 0); |
348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (num_bytes == 0) break; |
349 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | int written = write(usyslog_fd1, buf, num_bytes); |
350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(written == num_bytes); |
351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | } while (num_bytes == 4096); |
352 | 9 | retval = lseek(usyslog_fd1, 0, SEEK_SET); | |
353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(retval == 0); |
354 | |||
355 | // Reset usyslog | ||
356 | 9 | retval = lseek(usyslog_fd, 0, SEEK_SET); | |
357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(retval == 0); |
358 | 9 | retval = ftruncate(usyslog_fd, 0); | |
359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | assert(retval == 0); |
360 | 9 | usyslog_size = 0; | |
361 | } | ||
362 | 1004 | pthread_mutex_unlock(&lock_usyslock); | |
363 | } | ||
364 | |||
365 | /** | ||
366 | * Changes the debug log file from stderr. No effect if DEBUGMSG is undefined. | ||
367 | */ | ||
368 | #ifdef DEBUGMSG | ||
369 | 169 | void SetLogDebugFile(const string &filename) { | |
370 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | if (filename == "") { |
371 |
2/4✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 169 times.
|
169 | if ((file_debug != NULL) && (file_debug != stderr)) { |
372 | ✗ | fclose(file_debug); | |
373 | ✗ | file_debug = NULL; | |
374 | } | ||
375 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
|
169 | delete path_debug; |
376 | 169 | path_debug = NULL; | |
377 | 169 | return; | |
378 | } | ||
379 | |||
380 | ✗ | if ((file_debug != NULL) && (file_debug != stderr)) { | |
381 | ✗ | if ((fclose(file_debug) < 0)) { | |
382 | ✗ | fprintf(stderr, "could not close current log file (%d), aborting\n", | |
383 | ✗ | errno); | |
384 | |||
385 | ✗ | abort(); | |
386 | } | ||
387 | } | ||
388 | ✗ | int fd = open(filename.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0600); | |
389 | ✗ | if ((fd < 0) || ((file_debug = fdopen(fd, "a")) == NULL)) { | |
390 | ✗ | fprintf(stderr, "could not open debug log file %s (%d), aborting\n", | |
391 | ✗ | filename.c_str(), errno); | |
392 | ✗ | syslog(syslog_facility | LOG_ERR, | |
393 | "could not open debug log file %s (%d), " | ||
394 | "aborting\n", | ||
395 | ✗ | filename.c_str(), errno); | |
396 | ✗ | abort(); | |
397 | } | ||
398 | ✗ | delete path_debug; | |
399 | ✗ | path_debug = new string(filename); | |
400 | } | ||
401 | |||
402 | 51 | string GetLogDebugFile() { | |
403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
|
51 | if (path_debug) return *path_debug; |
404 |
1/2✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
|
51 | return ""; |
405 | } | ||
406 | #endif | ||
407 | |||
408 | 34 | void SetAltLogFunc(void (*fn)(const LogSource source, const int mask, | |
409 | const char *msg)) { | ||
410 | 34 | alt_log_func = fn; | |
411 | 34 | } | |
412 | |||
413 | |||
414 | /** | ||
415 | * Logs a message to one or multiple facilities specified by mask. | ||
416 | * Mask can be extended by a log level in the future, using the higher bits. | ||
417 | * | ||
418 | * @param[in] source Component that triggers the logging | ||
419 | * @param[in] mask Bit mask of log facilities | ||
420 | * @param[in] format Format string followed by arguments like printf | ||
421 | */ | ||
422 | CVMFS_EXPORT | ||
423 | 1259984 | void vLogCvmfs(const LogSource source, const int mask, | |
424 | const char *format, va_list variadic_list) { | ||
425 | 1259984 | char *msg = NULL; | |
426 | |||
427 | // Log level check, no flag set in mask means kLogNormal | ||
428 | #ifndef DEBUGMSG | ||
429 | ✗ | int log_level = mask & ((2 * kLogNone - 1) ^ (kLogLevel0 - 1)); | |
430 | ✗ | if (!log_level) log_level = kLogNormal; | |
431 | ✗ | if (log_level == kLogNone) return; | |
432 | ✗ | if (log_level > max_log_level) return; | |
433 | #endif | ||
434 | |||
435 | // Format the message string | ||
436 | 1259984 | int retval = vasprintf(&msg, format, variadic_list); | |
437 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1259984 times.
|
1259986 | assert(retval != -1); // else: out of memory |
438 | |||
439 |
2/2✓ Branch 0 taken 6524 times.
✓ Branch 1 taken 1253460 times.
|
1259984 | if (alt_log_func) { |
440 |
1/2✓ Branch 1 taken 6524 times.
✗ Branch 2 not taken.
|
6524 | (*alt_log_func)(source, mask, msg); |
441 | 6524 | return; | |
442 | } | ||
443 | |||
444 | #ifdef DEBUGMSG | ||
445 |
2/2✓ Branch 0 taken 865401 times.
✓ Branch 1 taken 388059 times.
|
1253460 | if (mask & kLogDebug) { |
446 | 865401 | pthread_mutex_lock(&lock_debug); | |
447 | |||
448 | // Set the file pointer for debugging to stderr, if necessary | ||
449 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 865363 times.
|
865412 | if (file_debug == NULL) file_debug = stderr; |
450 | |||
451 | // Get timestamp | ||
452 | time_t rawtime; | ||
453 | 865412 | time(&rawtime); | |
454 | struct tm now; | ||
455 | 865412 | localtime_r(&rawtime, &now); | |
456 | |||
457 |
1/2✓ Branch 0 taken 865412 times.
✗ Branch 1 not taken.
|
865412 | if (file_debug == stderr) pthread_mutex_lock(&lock_stderr); |
458 | 865412 | fprintf(file_debug, "(%s) %s [%02d-%02d-%04d %02d:%02d:%02d %s]\n", | |
459 | 865412 | module_names[source], msg, (now.tm_mon) + 1, now.tm_mday, | |
460 |
1/2✓ Branch 1 taken 865412 times.
✗ Branch 2 not taken.
|
865412 | (now.tm_year) + 1900, now.tm_hour, now.tm_min, now.tm_sec, |
461 | now.tm_zone); | ||
462 |
1/2✓ Branch 1 taken 865412 times.
✗ Branch 2 not taken.
|
865412 | fflush(file_debug); |
463 |
1/2✓ Branch 0 taken 865412 times.
✗ Branch 1 not taken.
|
865412 | if (file_debug == stderr) pthread_mutex_unlock(&lock_stderr); |
464 | |||
465 | 865412 | pthread_mutex_unlock(&lock_debug); | |
466 | } | ||
467 | #endif | ||
468 | |||
469 |
2/2✓ Branch 0 taken 382083 times.
✓ Branch 1 taken 871388 times.
|
1253471 | if (mask & kLogStdout) { |
470 | 382083 | pthread_mutex_lock(&lock_stdout); | |
471 |
3/4✓ Branch 0 taken 381897 times.
✓ Branch 1 taken 199 times.
✓ Branch 3 taken 381897 times.
✗ Branch 4 not taken.
|
382096 | if (mask & kLogShowSource) printf("(%s) ", module_names[source]); |
472 |
1/2✓ Branch 1 taken 382096 times.
✗ Branch 2 not taken.
|
382096 | printf("%s", msg); |
473 |
3/4✓ Branch 0 taken 382088 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 382088 times.
✗ Branch 4 not taken.
|
382096 | if (!(mask & kLogNoLinebreak)) printf("\n"); |
474 |
1/2✓ Branch 1 taken 382096 times.
✗ Branch 2 not taken.
|
382096 | fflush(stdout); |
475 | 382096 | pthread_mutex_unlock(&lock_stdout); | |
476 | } | ||
477 | |||
478 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1253477 times.
|
1253484 | if (mask & kLogStderr) { |
479 | 7 | pthread_mutex_lock(&lock_stderr); | |
480 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7 | if (mask & kLogShowSource) fprintf(stderr, "(%s) ", module_names[source]); |
481 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | fprintf(stderr, "%s", msg); |
482 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
|
7 | if (!(mask & kLogNoLinebreak)) fprintf(stderr, "\n"); |
483 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | fflush(stderr); |
484 | 7 | pthread_mutex_unlock(&lock_stderr); | |
485 | } | ||
486 | |||
487 |
2/2✓ Branch 0 taken 1322 times.
✓ Branch 1 taken 1252162 times.
|
1253484 | if (mask & (kLogSyslog | kLogSyslogWarn | kLogSyslogErr)) { |
488 |
2/2✓ Branch 0 taken 1004 times.
✓ Branch 1 taken 318 times.
|
1322 | if (usyslog_dest) { |
489 |
1/2✓ Branch 2 taken 1004 times.
✗ Branch 3 not taken.
|
1004 | string fmt_msg(msg); |
490 |
5/10✓ Branch 0 taken 1004 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1004 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1004 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1004 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1004 times.
✗ Branch 14 not taken.
|
1004 | if (syslog_prefix) fmt_msg = "(" + string(syslog_prefix) + ") " + fmt_msg; |
491 | time_t rawtime; | ||
492 | 1004 | time(&rawtime); | |
493 | char fmt_time[26]; | ||
494 | 1004 | ctime_r(&rawtime, fmt_time); | |
495 |
3/6✓ Branch 2 taken 1004 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1004 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1004 times.
✗ Branch 9 not taken.
|
1004 | fmt_msg = string(fmt_time, 24) + " " + fmt_msg; |
496 |
1/2✓ Branch 1 taken 1004 times.
✗ Branch 2 not taken.
|
1004 | fmt_msg.push_back('\n'); |
497 |
1/2✓ Branch 1 taken 1004 times.
✗ Branch 2 not taken.
|
1004 | LogMicroSyslog(fmt_msg); |
498 | 1004 | } else { | |
499 | 318 | int level = syslog_level; | |
500 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 207 times.
|
318 | if (mask & kLogSyslogWarn) level = LOG_WARNING; |
501 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 254 times.
|
318 | if (mask & kLogSyslogErr) level = LOG_ERR; |
502 |
2/2✓ Branch 0 taken 190 times.
✓ Branch 1 taken 128 times.
|
318 | if (syslog_prefix) { |
503 |
1/2✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
|
190 | syslog(syslog_facility | level, "(%s) %s", syslog_prefix, msg); |
504 | } else { | ||
505 |
1/2✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
|
128 | syslog(syslog_facility | level, "%s", msg); |
506 | } | ||
507 | } | ||
508 | } | ||
509 | |||
510 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1253476 times.
|
1253480 | if (mask & (kLogCustom0 | kLogCustom1 | kLogCustom2)) { |
511 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | string fmt_msg(msg); |
512 |
6/10✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
4 | if (syslog_prefix) fmt_msg = "(" + string(syslog_prefix) + ") " + fmt_msg; |
513 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | if (!(mask & kLogNoLinebreak)) fmt_msg += "\n"; |
514 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
|
4 | if (mask & kLogCustom0) LogCustom(0, fmt_msg); |
515 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
4 | if (mask & kLogCustom1) LogCustom(1, fmt_msg); |
516 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
4 | if (mask & kLogCustom2) LogCustom(2, fmt_msg); |
517 | 4 | } | |
518 | |||
519 | // The log buffer can be read via extended attributes from cvmfs, therefore | ||
520 | // we provide an option to hide entries from the buffer if they contain | ||
521 | // sensitive information | ||
522 |
2/2✓ Branch 0 taken 1253475 times.
✓ Branch 1 taken 5 times.
|
1253480 | if (!(mask & kLogSensitive)) |
523 |
3/6✓ Branch 2 taken 1253473 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1253476 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1253477 times.
✗ Branch 9 not taken.
|
1253475 | g_log_buffer.Append(LogBufferEntry(source, mask, msg)); |
524 | |||
525 | 1253478 | free(msg); | |
526 | } | ||
527 | CVMFS_EXPORT | ||
528 | 1259980 | void LogCvmfs(const LogSource source, const int mask, const char *format, ...) { | |
529 | va_list variadic_list; | ||
530 | 1259980 | va_start(variadic_list, format); | |
531 |
1/2✓ Branch 1 taken 1260002 times.
✗ Branch 2 not taken.
|
1259980 | vLogCvmfs(source, mask, format, variadic_list); |
532 | 1260002 | va_end(variadic_list); | |
533 | 1260002 | } | |
534 | |||
535 | 6 | std::vector<LogBufferEntry> GetLogBuffer() { | |
536 | 6 | return g_log_buffer.GetBuffer(); | |
537 | } | ||
538 | |||
539 | 1 | void ClearLogBuffer() { | |
540 | 1 | g_log_buffer.Clear(); | |
541 | 1 | } | |
542 | |||
543 | 5 | void PrintError(const string &message) { | |
544 | 5 | LogCvmfs(kLogCvmfs, kLogStderr, "[ERROR] %s", message.c_str()); | |
545 | 5 | } | |
546 | |||
547 | ✗ | void PrintWarning(const string &message) { | |
548 | ✗ | LogCvmfs(kLogCvmfs, kLogStderr, "[WARNING] %s", message.c_str()); | |
549 | } | ||
550 | |||
551 | |||
552 | /** | ||
553 | * Opens a custom log file | ||
554 | */ | ||
555 | 18 | void SetLogCustomFile(unsigned id, const std::string &filename) { | |
556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | assert(id < kMaxCustomlog); |
557 | 18 | pthread_mutex_lock(&customlog_locks[id]); | |
558 | |||
559 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
|
18 | if (customlog_fds[id] >= 0) { |
560 | 3 | close(customlog_fds[id]); | |
561 | 3 | customlog_fds[id] = -1; | |
562 | } | ||
563 | |||
564 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
|
18 | if (filename.empty()) { |
565 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
|
15 | delete customlog_dests[id]; |
566 | 15 | customlog_dests[id] = NULL; | |
567 | 15 | pthread_mutex_unlock(&customlog_locks[id]); | |
568 | 15 | return; | |
569 | } | ||
570 | |||
571 | 3 | customlog_fds[id] = open(filename.c_str(), O_RDWR | O_APPEND | O_CREAT, 0600); | |
572 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (customlog_fds[id] < 0) { |
573 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr, | |
574 | "could not open log file %s (%d), aborting", | ||
575 | ✗ | filename.c_str(), errno); | |
576 | ✗ | abort(); | |
577 | } | ||
578 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | delete customlog_dests[id]; |
579 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | customlog_dests[id] = new string(filename); |
580 | |||
581 | 3 | pthread_mutex_unlock(&customlog_locks[id]); | |
582 | } | ||
583 | |||
584 | |||
585 | 4 | static void LogCustom(unsigned id, const std::string &message) { | |
586 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(id < kMaxCustomlog); |
587 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (message.size() == 0) return; |
588 | |||
589 | 4 | pthread_mutex_lock(&customlog_locks[id]); | |
590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(customlog_fds[id] >= 0); |
591 | |||
592 | 4 | bool retval_b = SafeWrite(customlog_fds[id], message.data(), message.size()); | |
593 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!retval_b) { |
594 | ✗ | LogCvmfs(kLogCvmfs, kLogDebug | kLogSyslogErr, | |
595 | "could not write into log file %s (%d), aborting - lost: %s", | ||
596 | ✗ | customlog_dests[id]->c_str(), errno, message.c_str()); | |
597 | ✗ | abort(); | |
598 | } | ||
599 | 4 | int retval_i = fsync(customlog_fds[id]); | |
600 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(retval_i == 0); |
601 | |||
602 | 4 | pthread_mutex_unlock(&customlog_locks[id]); | |
603 | } | ||
604 | |||
605 | |||
606 | 5 | void LogShutdown() { | |
607 |
2/4✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5 times.
✗ Branch 6 not taken.
|
5 | SetLogMicroSyslog(""); |
608 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 5 times.
|
20 | for (unsigned i = 0; i < kMaxCustomlog; ++i) |
609 |
2/4✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
|
15 | SetLogCustomFile(i, ""); |
610 | 5 | } | |
611 | |||
612 | |||
613 | #ifdef CVMFS_NAMESPACE_GUARD | ||
614 | } // namespace CVMFS_NAMESPACE_GUARD | ||
615 | #endif | ||
616 |