CernVM-FS  2.9.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 "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 
29 #include "platform.h"
30 #include "smalloc.h"
31 #include "util/posix.h"
32 
33 using namespace std; // NOLINT
34 
35 #ifdef CVMFS_NAMESPACE_GUARD
36 namespace CVMFS_NAMESPACE_GUARD {
37 #endif
38 
39 static void LogCustom(unsigned id, const std::string &message);
40 
43 
45  DefaultLogging::info = info;
46  DefaultLogging::error = error;
47 }
48 
49 namespace {
50 
51 const unsigned kMicroSyslogMax = 500 * 1024; // rotate after 500kB
52 
53 pthread_mutex_t lock_stdout = PTHREAD_MUTEX_INITIALIZER;
54 pthread_mutex_t lock_stderr = PTHREAD_MUTEX_INITIALIZER;
55 #ifdef DEBUGMSG
56 pthread_mutex_t lock_debug = PTHREAD_MUTEX_INITIALIZER;
57 FILE *file_debug = NULL;
58 string *path_debug = NULL;
59 #endif
60 const char *module_names[] = {
61  "unknown", "cache", "catalog", "sql",
62  "cvmfs", "hash", "download", "compress",
63  "quota", "talk", "monitor", "lru",
64  "fuse stub", "signature", "fs traversal", "catalog traversal",
65  "nfs maps", "publish", "spooler", "concurrency",
66  "utility", "glue buffer", "history", "unionfs",
67  "pathspec", "receiver", "upload s3", "upload http",
68  "s3fanout", "gc", "dns", "authz",
69  "reflog", "kvstore"};
70 int syslog_facility = LOG_USER;
71 int syslog_level = LOG_NOTICE;
72 char *syslog_prefix = NULL;
73 
74 string *usyslog_dest = NULL;
75 int usyslog_fd = -1;
76 int usyslog_fd1 = -1;
77 unsigned usyslog_size = 0;
78 pthread_mutex_t lock_usyslock = PTHREAD_MUTEX_INITIALIZER;
79 
80 const unsigned kMaxCustomlog = 3;
81 string *customlog_dests[] = {NULL, NULL, NULL};
82 int customlog_fds[] = {-1, -1, -1};
83 pthread_mutex_t customlog_locks[] = {
84  PTHREAD_MUTEX_INITIALIZER,
85  PTHREAD_MUTEX_INITIALIZER,
86  PTHREAD_MUTEX_INITIALIZER};
87 
89 static void (*alt_log_func)(const LogSource source, const int mask,
90  const char *msg) = NULL;
91 
92 } // namespace
93 
97 void SetLogSyslogLevel(const int level) {
98  switch (level) {
99  case 1:
100  syslog_level = LOG_DEBUG;
101  break;
102  case 2:
103  syslog_level = LOG_INFO;
104  break;
105  case 3:
106  syslog_level = LOG_NOTICE;
107  break;
108  default:
109  syslog_level = LOG_NOTICE;
110  break;
111  }
112 }
113 
115  switch (syslog_level) {
116  case LOG_DEBUG:
117  return 1;
118  case LOG_INFO:
119  return 2;
120  default:
121  return 3;
122  }
123 }
124 
129 void SetLogSyslogFacility(const int local_facility) {
130  switch (local_facility) {
131  case 0:
132  syslog_facility = LOG_LOCAL0;
133  break;
134  case 1:
135  syslog_facility = LOG_LOCAL1;
136  break;
137  case 2:
138  syslog_facility = LOG_LOCAL2;
139  break;
140  case 3:
141  syslog_facility = LOG_LOCAL3;
142  break;
143  case 4:
144  syslog_facility = LOG_LOCAL4;
145  break;
146  case 5:
147  syslog_facility = LOG_LOCAL5;
148  break;
149  case 6:
150  syslog_facility = LOG_LOCAL6;
151  break;
152  case 7:
153  syslog_facility = LOG_LOCAL7;
154  break;
155  default:
156  syslog_facility = LOG_USER;
157  }
158 }
159 
161  switch (syslog_facility) {
162  case LOG_LOCAL0:
163  return 0;
164  case LOG_LOCAL1:
165  return 1;
166  case LOG_LOCAL2:
167  return 2;
168  case LOG_LOCAL3:
169  return 3;
170  case LOG_LOCAL4:
171  return 4;
172  case LOG_LOCAL5:
173  return 5;
174  case LOG_LOCAL6:
175  return 6;
176  case LOG_LOCAL7:
177  return 7;
178  default:
179  return -1;
180  }
181 }
182 
187 void SetLogSyslogPrefix(const std::string &prefix) {
188  if (syslog_prefix) free(syslog_prefix);
189 
190  if (prefix == "") {
191  syslog_prefix = NULL;
192  } else {
193  unsigned len = prefix.length() + 1;
194  syslog_prefix = static_cast<char *>(smalloc(len));
195  syslog_prefix[len - 1] = '\0';
196  memcpy(syslog_prefix, &prefix[0], prefix.length());
197  }
198 }
199 
200 void SetLogSyslogShowPID(bool flag) {
201  openlog(NULL, flag ? LOG_PID : 0, GetLogSyslogFacility());
202 }
203 
207 void SetLogVerbosity(const LogLevels min_level) { min_log_level = min_level; }
208 
209 
214 void SetLogMicroSyslog(const std::string &filename) {
215  pthread_mutex_lock(&lock_usyslock);
216  if (usyslog_fd >= 0) {
217  close(usyslog_fd);
218  close(usyslog_fd1);
219  usyslog_fd = -1;
220  usyslog_fd1 = -1;
221  }
222 
223  if (filename == "") {
224  delete usyslog_dest;
225  usyslog_dest = NULL;
226  pthread_mutex_unlock(&lock_usyslock);
227  return;
228  }
229 
230  usyslog_fd = open(filename.c_str(), O_RDWR | O_APPEND | O_CREAT, 0600);
231  if (usyslog_fd < 0) {
232  fprintf(stderr, "could not open usyslog file %s (%d), aborting\n",
233  filename.c_str(), errno);
234  abort();
235  }
236  usyslog_fd1 = open((filename + ".1").c_str(), O_WRONLY | O_CREAT, 0600);
237  if (usyslog_fd1 < 0) {
238  fprintf(stderr, "could not open usyslog.1 file %s.1 (%d), aborting\n",
239  filename.c_str(), errno);
240  abort();
241  }
242  platform_stat64 info;
243  int retval = platform_fstat(usyslog_fd, &info);
244  assert(retval == 0);
245  usyslog_size = info.st_size;
246  usyslog_dest = new string(filename);
247  pthread_mutex_unlock(&lock_usyslock);
248 }
249 
250 std::string GetLogMicroSyslog() {
251  pthread_mutex_lock(&lock_usyslock);
252  string result;
253  if (usyslog_dest) result = *usyslog_dest;
254  pthread_mutex_unlock(&lock_usyslock);
255  return result;
256 }
257 
258 static void LogMicroSyslog(const std::string &message) {
259  if (message.size() == 0) return;
260 
261  pthread_mutex_lock(&lock_usyslock);
262  if (usyslog_fd < 0) {
263  pthread_mutex_unlock(&lock_usyslock);
264  return;
265  }
266 
267  int written = write(usyslog_fd, message.data(), message.size());
268  if ((written < 0) || (static_cast<unsigned>(written) != message.size())) {
269  close(usyslog_fd);
270  usyslog_fd = -1;
271  abort();
272  }
273  int retval = fsync(usyslog_fd);
274  assert(retval == 0);
275  usyslog_size += written;
276 
277  if (usyslog_size >= kMicroSyslogMax) {
278  // Wipe out usyslog.1 file
279  retval = ftruncate(usyslog_fd1, 0);
280  assert(retval == 0);
281 
282  // Copy from usyslog to usyslog.1
283  retval = lseek(usyslog_fd, 0, SEEK_SET);
284  assert(retval == 0);
285  unsigned char buf[4096];
286  int num_bytes;
287  do {
288  num_bytes = read(usyslog_fd, buf, 4096);
289  assert(num_bytes >= 0);
290  if (num_bytes == 0) break;
291  int written = write(usyslog_fd1, buf, num_bytes);
292  assert(written == num_bytes);
293  } while (num_bytes == 4096);
294  retval = lseek(usyslog_fd1, 0, SEEK_SET);
295  assert(retval == 0);
296 
297  // Reset usyslog
298  retval = lseek(usyslog_fd, 0, SEEK_SET);
299  assert(retval == 0);
300  retval = ftruncate(usyslog_fd, 0);
301  assert(retval == 0);
302  usyslog_size = 0;
303  }
304  pthread_mutex_unlock(&lock_usyslock);
305 }
306 
310 #ifdef DEBUGMSG
311 void SetLogDebugFile(const string &filename) {
312  if (filename == "") {
313  if ((file_debug != NULL) && (file_debug != stderr)) {
314  fclose(file_debug);
315  file_debug = NULL;
316  }
317  delete path_debug;
318  path_debug = NULL;
319  return;
320  }
321 
322  if ((file_debug != NULL) && (file_debug != stderr)) {
323  if ((fclose(file_debug) < 0)) {
324  fprintf(stderr, "could not close current log file (%d), aborting\n",
325  errno);
326 
327  abort();
328  }
329  }
330  int fd = open(filename.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0600);
331  if ((fd < 0) || ((file_debug = fdopen(fd, "a")) == NULL)) {
332  fprintf(stderr, "could not open debug log file %s (%d), aborting\n",
333  filename.c_str(), errno);
334  syslog(syslog_facility | LOG_ERR,
335  "could not open debug log file %s (%d), "
336  "aborting\n",
337  filename.c_str(), errno);
338  abort();
339  }
340  delete path_debug;
341  path_debug = new string(filename);
342 }
343 
344 string GetLogDebugFile() {
345  if (path_debug) return *path_debug;
346  return "";
347 }
348 #endif
349 
350 void SetAltLogFunc(void (*fn)(const LogSource source, const int mask,
351  const char *msg)) {
352  alt_log_func = fn;
353 }
354 
355 
364 void LogCvmfs(const LogSource source, const int mask, const char *format, ...) {
365  char *msg = NULL;
366  va_list variadic_list;
367 
368 // Log level check, no flag set in mask means kLogNormal
369 #ifndef DEBUGMSG
370  int log_level = mask & ((2 * kLogNone - 1) ^ (kLogLevel0 - 1));
371  if (!log_level) log_level = kLogNormal;
372  if (log_level == kLogNone) return;
373  if (log_level < min_log_level) return;
374 #endif
375 
376  // Format the message string
377  va_start(variadic_list, format);
378  int retval = vasprintf(&msg, format, variadic_list);
379  assert(retval != -1); // else: out of memory
380  va_end(variadic_list);
381 
382  if (alt_log_func) {
383  (*alt_log_func)(source, mask, msg);
384  return;
385  }
386 
387 #ifdef DEBUGMSG
388  if (mask & kLogDebug) {
389  pthread_mutex_lock(&lock_debug);
390 
391  // Set the file pointer for debuging to stderr, if necessary
392  if (file_debug == NULL) file_debug = stderr;
393 
394  // Get timestamp
395  time_t rawtime;
396  time(&rawtime);
397  struct tm now;
398  localtime_r(&rawtime, &now);
399 
400  if (file_debug == stderr) pthread_mutex_lock(&lock_stderr);
401  fprintf(file_debug, "(%s) %s [%02d-%02d-%04d %02d:%02d:%02d %s]\n",
402  module_names[source], msg, (now.tm_mon) + 1, now.tm_mday,
403  (now.tm_year) + 1900, now.tm_hour, now.tm_min, now.tm_sec,
404  now.tm_zone);
405  fflush(file_debug);
406  if (file_debug == stderr) pthread_mutex_unlock(&lock_stderr);
407 
408  pthread_mutex_unlock(&lock_debug);
409  }
410 #endif
411 
412  if (mask & kLogStdout) {
413  pthread_mutex_lock(&lock_stdout);
414  if (mask & kLogShowSource) printf("(%s) ", module_names[source]);
415  printf("%s", msg);
416  if (!(mask & kLogNoLinebreak)) printf("\n");
417  fflush(stdout);
418  pthread_mutex_unlock(&lock_stdout);
419  }
420 
421  if (mask & kLogStderr) {
422  pthread_mutex_lock(&lock_stderr);
423  if (mask & kLogShowSource) fprintf(stderr, "(%s) ", module_names[source]);
424  fprintf(stderr, "%s", msg);
425  if (!(mask & kLogNoLinebreak)) fprintf(stderr, "\n");
426  fflush(stderr);
427  pthread_mutex_unlock(&lock_stderr);
428  }
429 
430  if (mask & (kLogSyslog | kLogSyslogWarn | kLogSyslogErr)) {
431  if (usyslog_dest) {
432  string fmt_msg(msg);
433  if (syslog_prefix) fmt_msg = "(" + string(syslog_prefix) + ") " + fmt_msg;
434  time_t rawtime;
435  time(&rawtime);
436  char fmt_time[26];
437  ctime_r(&rawtime, fmt_time);
438  fmt_msg = string(fmt_time, 24) + " " + fmt_msg;
439  fmt_msg.push_back('\n');
440  LogMicroSyslog(fmt_msg);
441  } else {
442  int level = syslog_level;
443  if (mask & kLogSyslogWarn) level = LOG_WARNING;
444  if (mask & kLogSyslogErr) level = LOG_ERR;
445  if (syslog_prefix) {
446  syslog(syslog_facility | level, "(%s) %s", syslog_prefix, msg);
447  } else {
448  syslog(syslog_facility | level, "%s", msg);
449  }
450  }
451  }
452 
453  if (mask & (kLogCustom0 | kLogCustom1 | kLogCustom2)) {
454  string fmt_msg(msg);
455  if (syslog_prefix) fmt_msg = "(" + string(syslog_prefix) + ") " + fmt_msg;
456  if (!(mask & kLogNoLinebreak)) fmt_msg += "\n";
457  if (mask & kLogCustom0) LogCustom(0, fmt_msg);
458  if (mask & kLogCustom1) LogCustom(1, fmt_msg);
459  if (mask & kLogCustom2) LogCustom(2, fmt_msg);
460  }
461 
462  free(msg);
463 }
464 
465 void PrintError(const string &message) {
466  LogCvmfs(kLogCvmfs, kLogStderr, "[ERROR] %s", message.c_str());
467 }
468 
469 void PrintWarning(const string &message) {
470  LogCvmfs(kLogCvmfs, kLogStderr, "[WARNING] %s", message.c_str());
471 }
472 
473 
477 void SetLogCustomFile(unsigned id, const std::string &filename) {
478  assert(id < kMaxCustomlog);
479  pthread_mutex_lock(&customlog_locks[id]);
480 
481  if (customlog_fds[id] >= 0) {
482  close(customlog_fds[id]);
483  customlog_fds[id] = -1;
484  }
485 
486  if (filename.empty()) {
487  delete customlog_dests[id];
488  customlog_dests[id] = NULL;
489  pthread_mutex_unlock(&customlog_locks[id]);
490  return;
491  }
492 
493  customlog_fds[id] = open(filename.c_str(), O_RDWR | O_APPEND | O_CREAT, 0600);
494  if (customlog_fds[id] < 0) {
496  "could not open log file %s (%d), aborting",
497  filename.c_str(), errno);
498  abort();
499  }
500  delete customlog_dests[id];
501  customlog_dests[id] = new string(filename);
502 
503  pthread_mutex_unlock(&customlog_locks[id]);
504 }
505 
506 
507 static void LogCustom(unsigned id, const std::string &message) {
508  assert(id < kMaxCustomlog);
509  if (message.size() == 0) return;
510 
511  pthread_mutex_lock(&customlog_locks[id]);
512  assert(customlog_fds[id] >= 0);
513 
514  bool retval_b = SafeWrite(customlog_fds[id], message.data(), message.size());
515  if (!retval_b) {
517  "could not write into log file %s (%d), aborting - lost: %s",
518  customlog_dests[id]->c_str(), errno, message.c_str());
519  abort();
520  }
521  int retval_i = fsync(customlog_fds[id]);
522  assert(retval_i == 0);
523 
524  pthread_mutex_unlock(&customlog_locks[id]);
525 }
526 
527 
528 void LogShutdown() {
529  SetLogMicroSyslog("");
530  for (unsigned i = 0; i < kMaxCustomlog; ++i)
531  SetLogCustomFile(i, "");
532 }
533 
534 
535 #ifdef CVMFS_NAMESPACE_GUARD
536 } // namespace CVMFS_NAMESPACE_GUARD
537 #endif
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
void SetLogSyslogFacility(const int local_facility)
Definition: logging.cc:129
const char * module_names[]
Definition: logging.cc:60
pthread_mutex_t customlog_locks[]
Definition: logging.cc:83
void SetLogSyslogLevel(const int level)
Definition: logging.cc:97
struct stat64 platform_stat64
static void LogCustom(unsigned id, const std::string &message)
Definition: logging.cc:507
void SetLogSyslogShowPID(bool flag)
Definition: logging.cc:200
const unsigned kMicroSyslogMax
Definition: logging.cc:51
static void Set(LogFacilities info, LogFacilities error)
Definition: logging.cc:44
static void LogMicroSyslog(const std::string &message)
Definition: logging.cc:258
bool SafeWrite(int fd, const void *buf, size_t nbyte)
Definition: posix.cc:1924
assert((mem||(size==0))&&"Out Of Memory")
void SetAltLogFunc(void(*fn)(const LogSource source, const int mask, const char *msg))
Definition: logging.cc:350
void SetLogMicroSyslog(const std::string &filename)
Definition: logging.cc:214
#define SetLogDebugFile(filename)
pthread_mutex_t lock_stdout
Definition: logging.cc:53
static void(* alt_log_func)(const LogSource source, const int mask, const char *msg)
Definition: logging.cc:89
int GetLogSyslogLevel()
Definition: logging.cc:114
#define GetLogDebugFile()
pthread_mutex_t lock_usyslock
Definition: logging.cc:78
LogSource
void SetLogVerbosity(const LogLevels min_level)
Definition: logging.cc:207
void SetLogCustomFile(unsigned id, const std::string &filename)
Definition: logging.cc:477
std::string GetLogMicroSyslog()
Definition: logging.cc:250
void PrintWarning(const string &message)
Definition: logging.cc:469
LogLevels
void LogShutdown()
Definition: logging.cc:528
LogFacilities
void SetLogSyslogPrefix(const std::string &prefix)
Definition: logging.cc:187
void PrintError(const string &message)
Definition: logging.cc:465
int platform_fstat(int filedes, platform_stat64 *buf)
static LogFacilities info
static LogFacilities error
pthread_mutex_t lock_stderr
Definition: logging.cc:54
const unsigned kMaxCustomlog
Definition: logging.cc:80
int GetLogSyslogFacility()
Definition: logging.cc:160