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