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