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