| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/util/logging.cc |
| Date: | 2026-04-05 02:35:23 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 233 | 343 | 67.9% |
| 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 <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 | 15480730 | void Append(const LogBufferEntry &entry) { | |
| 112 | 15480730 | const MutexLockGuard lock_guard(lock_); | |
| 113 | 15480757 | const size_t idx = next_id_++ % kBufferSize; | |
| 114 |
2/2✓ Branch 1 taken 727 times.
✓ Branch 2 taken 15480030 times.
|
15480757 | if (idx >= buffer_.size()) { |
| 115 |
1/2✓ Branch 1 taken 727 times.
✗ Branch 2 not taken.
|
727 | buffer_.push_back(entry); |
| 116 | } else { | ||
| 117 |
1/2✓ Branch 2 taken 15480030 times.
✗ Branch 3 not taken.
|
15480030 | buffer_[idx] = entry; |
| 118 | } | ||
| 119 | 15480757 | } | |
| 120 | |||
| 121 | 96 | std::vector<LogBufferEntry> GetBuffer() { | |
| 122 | // Return a buffer sorted from newest to oldest buffer | ||
| 123 | 96 | std::vector<LogBufferEntry> sorted_buffer; | |
| 124 | 96 | const MutexLockGuard lock_guard(lock_); | |
| 125 |
2/2✓ Branch 1 taken 554 times.
✓ Branch 2 taken 96 times.
|
650 | for (unsigned i = 1; i <= buffer_.size(); ++i) { |
| 126 | 554 | const unsigned idx = (next_id_ - i) % kBufferSize; | |
| 127 |
1/2✓ Branch 2 taken 554 times.
✗ Branch 3 not taken.
|
554 | sorted_buffer.push_back(buffer_[idx]); |
| 128 | } | ||
| 129 | 192 | return sorted_buffer; | |
| 130 | 96 | } | |
| 131 | |||
| 132 | 14 | void Clear() { | |
| 133 | 14 | const MutexLockGuard lock_guard(lock_); | |
| 134 | 14 | next_id_ = 0; | |
| 135 | 14 | buffer_.clear(); | |
| 136 | 14 | } | |
| 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 | 117 | void SetLogSyslogLevel(const int level) { | |
| 153 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
|
117 | switch (level) { |
| 154 | ✗ | case 1: | |
| 155 | ✗ | syslog_level = LOG_DEBUG; | |
| 156 | ✗ | break; | |
| 157 | ✗ | case 2: | |
| 158 | ✗ | syslog_level = LOG_INFO; | |
| 159 | ✗ | break; | |
| 160 | 117 | case 3: | |
| 161 | 117 | syslog_level = LOG_NOTICE; | |
| 162 | 117 | break; | |
| 163 | ✗ | default: | |
| 164 | ✗ | syslog_level = LOG_NOTICE; | |
| 165 | ✗ | break; | |
| 166 | } | ||
| 167 | 117 | } | |
| 168 | |||
| 169 | 63 | int GetLogSyslogLevel() { | |
| 170 |
1/3✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
|
63 | switch (syslog_level) { |
| 171 | ✗ | case LOG_DEBUG: | |
| 172 | ✗ | return 1; | |
| 173 | ✗ | case LOG_INFO: | |
| 174 | ✗ | return 2; | |
| 175 | 63 | default: | |
| 176 | 63 | 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 | 63 | 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 63 times.
|
63 | 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 | 63 | default: | |
| 234 | 63 | return -1; | |
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | /** | ||
| 239 | * The syslog prefix is used to distinguish multiple repositories in | ||
| 240 | * /var/log/messages | ||
| 241 | */ | ||
| 242 | 4818 | void SetLogSyslogPrefix(const std::string &prefix) { | |
| 243 |
2/2✓ Branch 0 taken 2420 times.
✓ Branch 1 taken 2398 times.
|
4818 | if (syslog_prefix) |
| 244 | 2420 | free(syslog_prefix); | |
| 245 | |||
| 246 |
2/2✓ Branch 1 taken 2393 times.
✓ Branch 2 taken 2425 times.
|
4818 | if (prefix == "") { |
| 247 | 2393 | syslog_prefix = NULL; | |
| 248 | } else { | ||
| 249 | 2425 | const unsigned len = prefix.length() + 1; | |
| 250 | 2425 | syslog_prefix = static_cast<char *>(smalloc(len)); | |
| 251 | 2425 | syslog_prefix[len - 1] = '\0'; | |
| 252 | 2425 | memcpy(syslog_prefix, &prefix[0], prefix.length()); | |
| 253 | } | ||
| 254 | 4818 | } | |
| 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 | 24 | void SetLogVerbosity(const LogLevels max_level) { max_log_level = max_level; } | |
| 264 | |||
| 265 | |||
| 266 | 20 | 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 | 2613 | void SetLogMicroSyslog(const std::string &filename) { | |
| 273 | 2613 | pthread_mutex_lock(&lock_usyslock); | |
| 274 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 2580 times.
|
2613 | if (usyslog_fd >= 0) { |
| 275 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | close(usyslog_fd); |
| 276 |
1/2✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
|
33 | close(usyslog_fd1); |
| 277 | 33 | usyslog_fd = -1; | |
| 278 | 33 | usyslog_fd1 = -1; | |
| 279 | } | ||
| 280 | |||
| 281 |
2/2✓ Branch 1 taken 2580 times.
✓ Branch 2 taken 33 times.
|
2613 | if (filename == "") { |
| 282 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 2547 times.
|
2580 | delete usyslog_dest; |
| 283 | 2580 | usyslog_dest = NULL; | |
| 284 | 2580 | pthread_mutex_unlock(&lock_usyslock); | |
| 285 | 2580 | return; | |
| 286 | } | ||
| 287 | |||
| 288 |
1/2✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 | usyslog_fd = open(filename.c_str(), O_RDWR | O_APPEND | O_CREAT, 0600); |
| 289 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | 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 33 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
|
33 | usyslog_fd1 = open((filename + ".1").c_str(), O_WRONLY | O_CREAT, 0600); |
| 295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | 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 | 33 | const int retval = platform_fstat(usyslog_fd, &info); | |
| 302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | assert(retval == 0); |
| 303 | 33 | usyslog_size = info.st_size; | |
| 304 |
2/4✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
|
33 | usyslog_dest = new string(filename); |
| 305 | 33 | pthread_mutex_unlock(&lock_usyslock); | |
| 306 | } | ||
| 307 | |||
| 308 | 60 | std::string GetLogMicroSyslog() { | |
| 309 | 60 | pthread_mutex_lock(&lock_usyslock); | |
| 310 | 60 | string result; | |
| 311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | if (usyslog_dest) |
| 312 | ✗ | result = *usyslog_dest; | |
| 313 | 60 | pthread_mutex_unlock(&lock_usyslock); | |
| 314 | 60 | return result; | |
| 315 | } | ||
| 316 | |||
| 317 | 20052 | static void LogMicroSyslog(const std::string &message) { | |
| 318 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 20052 times.
|
20052 | if (message.size() == 0) |
| 319 | ✗ | return; | |
| 320 | |||
| 321 | 20052 | pthread_mutex_lock(&lock_usyslock); | |
| 322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20052 times.
|
20052 | if (usyslog_fd < 0) { |
| 323 | ✗ | pthread_mutex_unlock(&lock_usyslock); | |
| 324 | ✗ | return; | |
| 325 | } | ||
| 326 | |||
| 327 | 20052 | const int written = write(usyslog_fd, message.data(), message.size()); | |
| 328 |
3/6✓ Branch 0 taken 20052 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 20052 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20052 times.
|
20052 | if ((written < 0) || (static_cast<unsigned>(written) != message.size())) { |
| 329 | ✗ | close(usyslog_fd); | |
| 330 | ✗ | usyslog_fd = -1; | |
| 331 | ✗ | abort(); | |
| 332 | } | ||
| 333 | 20052 | int retval = fsync(usyslog_fd); | |
| 334 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20052 times.
|
20052 | assert(retval == 0); |
| 335 | 20052 | usyslog_size += written; | |
| 336 | |||
| 337 |
2/2✓ Branch 0 taken 140 times.
✓ Branch 1 taken 19912 times.
|
20052 | if (usyslog_size >= gMicroSyslogMax) { |
| 338 | // Wipe out usyslog.1 file | ||
| 339 | 140 | retval = ftruncate(usyslog_fd1, 0); | |
| 340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(retval == 0); |
| 341 | |||
| 342 | // Copy from usyslog to usyslog.1 | ||
| 343 | 140 | retval = lseek(usyslog_fd, 0, SEEK_SET); | |
| 344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(retval == 0); |
| 345 | unsigned char buf[4096]; | ||
| 346 | int num_bytes; | ||
| 347 | do { | ||
| 348 |
1/2✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
|
140 | num_bytes = read(usyslog_fd, buf, 4096); |
| 349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(num_bytes >= 0); |
| 350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | if (num_bytes == 0) |
| 351 | ✗ | break; | |
| 352 |
1/2✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
|
140 | const int written = write(usyslog_fd1, buf, num_bytes); |
| 353 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(written == num_bytes); |
| 354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | } while (num_bytes == 4096); |
| 355 | 140 | retval = lseek(usyslog_fd1, 0, SEEK_SET); | |
| 356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(retval == 0); |
| 357 | |||
| 358 | // Reset usyslog | ||
| 359 | 140 | retval = lseek(usyslog_fd, 0, SEEK_SET); | |
| 360 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(retval == 0); |
| 361 | 140 | retval = ftruncate(usyslog_fd, 0); | |
| 362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(retval == 0); |
| 363 | 140 | usyslog_size = 0; | |
| 364 | } | ||
| 365 | 20052 | 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 | 2491 | void SetLogDebugFile(const string &filename) { | |
| 373 |
1/2✓ Branch 1 taken 2491 times.
✗ Branch 2 not taken.
|
2491 | if (filename == "") { |
| 374 |
2/4✓ Branch 0 taken 2491 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2491 times.
|
2491 | 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 2491 times.
|
2491 | delete path_debug; |
| 379 | 2491 | path_debug = NULL; | |
| 380 | 2491 | 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 | 112 | string GetLogDebugFile() { | |
| 406 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
|
112 | if (path_debug) |
| 407 | ✗ | return *path_debug; | |
| 408 |
1/2✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
|
112 | return ""; |
| 409 | } | ||
| 410 | #endif | ||
| 411 | |||
| 412 | 401 | void SetAltLogFunc(void (*fn)(const LogSource source, const int mask, | |
| 413 | const char *msg)) { | ||
| 414 | 401 | alt_log_func = fn; | |
| 415 | 401 | } | |
| 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 | 15558161 | void vLogCvmfs(const LogSource source, const int mask, const char *format, | |
| 428 | va_list variadic_list) { | ||
| 429 | 15558161 | 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 | 15558161 | const int retval = vasprintf(&msg, format, variadic_list); | |
| 444 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15558716 times.
|
15558630 | assert(retval != -1); // else: out of memory |
| 445 | |||
| 446 |
2/2✓ Branch 0 taken 78141 times.
✓ Branch 1 taken 15480575 times.
|
15558716 | if (alt_log_func) { |
| 447 |
1/2✓ Branch 1 taken 78141 times.
✗ Branch 2 not taken.
|
78141 | (*alt_log_func)(source, mask, msg); |
| 448 | 78141 | return; | |
| 449 | } | ||
| 450 | |||
| 451 | #ifdef DEBUGMSG | ||
| 452 |
2/2✓ Branch 0 taken 11844285 times.
✓ Branch 1 taken 3636290 times.
|
15480575 | if (mask & kLogDebug) { |
| 453 | 11844285 | 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 11844319 times.
|
11844417 | if (file_debug == NULL) |
| 457 | 98 | file_debug = stderr; | |
| 458 | |||
| 459 | // Get timestamp | ||
| 460 | time_t rawtime; | ||
| 461 | 11844417 | time(&rawtime); | |
| 462 | struct tm now; | ||
| 463 | 11844417 | localtime_r(&rawtime, &now); | |
| 464 | |||
| 465 |
1/2✓ Branch 0 taken 11844417 times.
✗ Branch 1 not taken.
|
11844417 | if (file_debug == stderr) |
| 466 | 11844417 | pthread_mutex_lock(&lock_stderr); | |
| 467 | 11844417 | fprintf(file_debug, "(%s) %s [%02d-%02d-%04d %02d:%02d:%02d %s]\n", | |
| 468 | 11844417 | module_names[source], msg, (now.tm_mon) + 1, now.tm_mday, | |
| 469 |
1/2✓ Branch 1 taken 11844417 times.
✗ Branch 2 not taken.
|
11844417 | (now.tm_year) + 1900, now.tm_hour, now.tm_min, now.tm_sec, |
| 470 | now.tm_zone); | ||
| 471 |
1/2✓ Branch 1 taken 11844417 times.
✗ Branch 2 not taken.
|
11844417 | fflush(file_debug); |
| 472 |
1/2✓ Branch 0 taken 11844417 times.
✗ Branch 1 not taken.
|
11844417 | if (file_debug == stderr) |
| 473 | 11844417 | pthread_mutex_unlock(&lock_stderr); | |
| 474 | |||
| 475 | 11844417 | pthread_mutex_unlock(&lock_debug); | |
| 476 | } | ||
| 477 | #endif | ||
| 478 | |||
| 479 |
2/2✓ Branch 0 taken 3547570 times.
✓ Branch 1 taken 11933137 times.
|
15480707 | if (mask & kLogStdout) { |
| 480 | 3547570 | pthread_mutex_lock(&lock_stdout); | |
| 481 |
2/2✓ Branch 0 taken 3541270 times.
✓ Branch 1 taken 6464 times.
|
3547734 | if (mask & kLogShowSource) |
| 482 |
1/2✓ Branch 1 taken 3541270 times.
✗ Branch 2 not taken.
|
3541270 | printf("(%s) ", module_names[source]); |
| 483 |
1/2✓ Branch 1 taken 3547734 times.
✗ Branch 2 not taken.
|
3547734 | printf("%s", msg); |
| 484 |
2/2✓ Branch 0 taken 3547647 times.
✓ Branch 1 taken 87 times.
|
3547734 | if (!(mask & kLogNoLinebreak)) |
| 485 |
1/2✓ Branch 1 taken 3547647 times.
✗ Branch 2 not taken.
|
3547647 | printf("\n"); |
| 486 |
1/2✓ Branch 1 taken 3547734 times.
✗ Branch 2 not taken.
|
3547734 | fflush(stdout); |
| 487 | 3547734 | pthread_mutex_unlock(&lock_stdout); | |
| 488 | } | ||
| 489 | |||
| 490 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 15480748 times.
|
15480871 | if (mask & kLogStderr) { |
| 491 | 123 | pthread_mutex_lock(&lock_stderr); | |
| 492 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
123 | if (mask & kLogShowSource) |
| 493 | ✗ | fprintf(stderr, "(%s) ", module_names[source]); | |
| 494 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
123 | fprintf(stderr, "%s", msg); |
| 495 |
1/2✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
|
123 | if (!(mask & kLogNoLinebreak)) |
| 496 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
123 | fprintf(stderr, "\n"); |
| 497 |
1/2✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
|
123 | fflush(stderr); |
| 498 | 123 | pthread_mutex_unlock(&lock_stderr); | |
| 499 | } | ||
| 500 | |||
| 501 |
2/2✓ Branch 0 taken 28781 times.
✓ Branch 1 taken 15452090 times.
|
15480871 | if (mask & (kLogSyslog | kLogSyslogWarn | kLogSyslogErr)) { |
| 502 |
2/2✓ Branch 0 taken 20052 times.
✓ Branch 1 taken 8729 times.
|
28781 | if (usyslog_dest) { |
| 503 |
1/2✓ Branch 2 taken 20052 times.
✗ Branch 3 not taken.
|
20052 | string fmt_msg(msg); |
| 504 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 20000 times.
|
20052 | if (syslog_prefix) |
| 505 |
4/8✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 52 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 52 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 52 times.
✗ Branch 12 not taken.
|
52 | fmt_msg = "(" + string(syslog_prefix) + ") " + fmt_msg; |
| 506 | time_t rawtime; | ||
| 507 | 20052 | time(&rawtime); | |
| 508 | char fmt_time[26]; | ||
| 509 | 20052 | ctime_r(&rawtime, fmt_time); | |
| 510 |
3/6✓ Branch 2 taken 20052 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20052 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 20052 times.
✗ Branch 9 not taken.
|
20052 | fmt_msg = string(fmt_time, 24) + " " + fmt_msg; |
| 511 |
1/2✓ Branch 1 taken 20052 times.
✗ Branch 2 not taken.
|
20052 | fmt_msg.push_back('\n'); |
| 512 |
1/2✓ Branch 1 taken 20052 times.
✗ Branch 2 not taken.
|
20052 | LogMicroSyslog(fmt_msg); |
| 513 | 20052 | } else { | |
| 514 | 8729 | int level = syslog_level; | |
| 515 |
2/2✓ Branch 0 taken 4119 times.
✓ Branch 1 taken 4610 times.
|
8729 | if (mask & kLogSyslogWarn) |
| 516 | 4119 | level = LOG_WARNING; | |
| 517 |
2/2✓ Branch 0 taken 1459 times.
✓ Branch 1 taken 7270 times.
|
8729 | if (mask & kLogSyslogErr) |
| 518 | 1459 | level = LOG_ERR; | |
| 519 |
2/2✓ Branch 0 taken 4125 times.
✓ Branch 1 taken 4604 times.
|
8729 | if (syslog_prefix) { |
| 520 |
1/2✓ Branch 1 taken 4125 times.
✗ Branch 2 not taken.
|
4125 | syslog(syslog_facility | level, "(%s) %s", syslog_prefix, msg); |
| 521 | } else { | ||
| 522 |
1/2✓ Branch 1 taken 4484 times.
✗ Branch 2 not taken.
|
4604 | syslog(syslog_facility | level, "%s", msg); |
| 523 | } | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 15480691 times.
|
15480751 | if (mask & (kLogCustom0 | kLogCustom1 | kLogCustom2)) { |
| 528 |
1/2✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
|
60 | string fmt_msg(msg); |
| 529 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 45 times.
|
60 | if (syslog_prefix) |
| 530 |
4/8✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 15 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 15 times.
✗ Branch 12 not taken.
|
15 | fmt_msg = "(" + string(syslog_prefix) + ") " + fmt_msg; |
| 531 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
60 | if (!(mask & kLogNoLinebreak)) |
| 532 |
1/2✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
|
60 | fmt_msg += "\n"; |
| 533 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
|
60 | if (mask & kLogCustom0) |
| 534 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | LogCustom(0, fmt_msg); |
| 535 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 45 times.
|
60 | if (mask & kLogCustom1) |
| 536 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | LogCustom(1, fmt_msg); |
| 537 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 45 times.
|
60 | if (mask & kLogCustom2) |
| 538 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | LogCustom(2, fmt_msg); |
| 539 | 60 | } | |
| 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 15480737 times.
✓ Branch 1 taken 14 times.
|
15480751 | if (!(mask & kLogSensitive)) |
| 545 |
3/6✓ Branch 2 taken 15480723 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15480742 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 15480757 times.
✗ Branch 9 not taken.
|
15480737 | g_log_buffer.Append(LogBufferEntry(source, mask, msg)); |
| 546 | |||
| 547 | 15480771 | free(msg); | |
| 548 | } | ||
| 549 | CVMFS_EXPORT | ||
| 550 | 15558019 | void LogCvmfs(const LogSource source, const int mask, const char *format, ...) { | |
| 551 | va_list variadic_list; | ||
| 552 | 15558019 | va_start(variadic_list, format); | |
| 553 |
1/2✓ Branch 1 taken 15558904 times.
✗ Branch 2 not taken.
|
15558019 | vLogCvmfs(source, mask, format, variadic_list); |
| 554 | 15558904 | va_end(variadic_list); | |
| 555 | 15558904 | } | |
| 556 | |||
| 557 | 96 | std::vector<LogBufferEntry> GetLogBuffer() { return g_log_buffer.GetBuffer(); } | |
| 558 | |||
| 559 | 14 | void ClearLogBuffer() { g_log_buffer.Clear(); } | |
| 560 | |||
| 561 | 63 | void PrintError(const string &message) { | |
| 562 | 63 | LogCvmfs(kLogCvmfs, kLogStderr, "[ERROR] %s", message.c_str()); | |
| 563 | 63 | } | |
| 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 | 276 | void SetLogCustomFile(unsigned id, const std::string &filename) { | |
| 574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
|
276 | assert(id < kMaxCustomlog); |
| 575 | 276 | pthread_mutex_lock(&customlog_locks[id]); | |
| 576 | |||
| 577 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 231 times.
|
276 | if (customlog_fds[id] >= 0) { |
| 578 | 45 | close(customlog_fds[id]); | |
| 579 | 45 | customlog_fds[id] = -1; | |
| 580 | } | ||
| 581 | |||
| 582 |
2/2✓ Branch 1 taken 228 times.
✓ Branch 2 taken 48 times.
|
276 | if (filename.empty()) { |
| 583 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 183 times.
|
228 | delete customlog_dests[id]; |
| 584 | 228 | customlog_dests[id] = NULL; | |
| 585 | 228 | pthread_mutex_unlock(&customlog_locks[id]); | |
| 586 | 228 | return; | |
| 587 | } | ||
| 588 | |||
| 589 | 48 | customlog_fds[id] = open(filename.c_str(), O_RDWR | O_APPEND | O_CREAT, 0600); | |
| 590 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | 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 48 times.
|
48 | delete customlog_dests[id]; |
| 597 |
1/2✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
|
48 | customlog_dests[id] = new string(filename); |
| 598 | |||
| 599 | 48 | pthread_mutex_unlock(&customlog_locks[id]); | |
| 600 | } | ||
| 601 | |||
| 602 | |||
| 603 | 60 | static void LogCustom(unsigned id, const std::string &message) { | |
| 604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | assert(id < kMaxCustomlog); |
| 605 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
|
60 | if (message.size() == 0) |
| 606 | ✗ | return; | |
| 607 | |||
| 608 | 60 | pthread_mutex_lock(&customlog_locks[id]); | |
| 609 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | assert(customlog_fds[id] >= 0); |
| 610 | |||
| 611 | 60 | const bool retval_b = SafeWrite(customlog_fds[id], message.data(), | |
| 612 | message.size()); | ||
| 613 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | 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 | 60 | const int retval_i = fsync(customlog_fds[id]); | |
| 620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | assert(retval_i == 0); |
| 621 | |||
| 622 | 60 | pthread_mutex_unlock(&customlog_locks[id]); | |
| 623 | } | ||
| 624 | |||
| 625 | |||
| 626 | 76 | void LogShutdown() { | |
| 627 |
2/4✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 76 times.
✗ Branch 6 not taken.
|
76 | SetLogMicroSyslog(""); |
| 628 |
2/2✓ Branch 0 taken 228 times.
✓ Branch 1 taken 76 times.
|
304 | for (unsigned i = 0; i < kMaxCustomlog; ++i) |
| 629 |
2/4✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 228 times.
✗ Branch 6 not taken.
|
228 | SetLogCustomFile(i, ""); |
| 630 | 76 | } | |
| 631 | |||
| 632 | |||
| 633 | #ifdef CVMFS_NAMESPACE_GUARD | ||
| 634 | } // namespace CVMFS_NAMESPACE_GUARD | ||
| 635 | #endif | ||
| 636 |