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