libutil++  1.9.3
 All Classes Functions Variables
Log.cpp
1 /*
2 ** libutil++
3 ** $Id: Log.cpp 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 static const char rcsid[] __attribute__((used)) = "$Id: Log.cpp 1653 2016-02-28 19:54:59Z sella $";
10 
11 #include "Log.h"
12 #include "LogException.h"
13 #include "LogFormat.h"
14 #include "Process.h"
15 #include "../Exception.h"
16 
17 #include <stdio.h>
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <syslog.h>
21 #include <stdarg.h>
22 #include <assert.h>
23 #include <string.h>
24 
25 #include <string>
26 
27 #define BUFFER_SIZE (64 * 1024)
28 
29 using namespace sella::util;
30 
31 const char* Log::LABEL_EMERGENCY = "EMRG";
32 const char* Log::LABEL_ALERT = "ALRT";
33 const char* Log::LABEL_CRITICAL = "CRIT";
34 const char* Log::LABEL_ERROR = "ERRO";
35 const char* Log::LABEL_WARNING = "WARN";
36 const char* Log::LABEL_NOTICE = "NOTE";
37 const char* Log::LABEL_INFO = "INFO";
38 const char* Log::LABEL_DEBUG = "DEBG";
39 
40 Log::shared libutilxx__log __attribute__((init_priority(101)));
41 
42 Log::Log(const std::string &identifier, int facility, int option, int mask, const LogFormat &format, size_t size) throw (LogException) :
43  references(*(new uint64_t(1))),
44  everyN(*(new uint64_t(1))),
45 
46  identifier(identifier),
47  facility(facility),
48  option(option),
49 
50  syslog(true),
51  syslogMask(mask),
52 
53  allTraceOptions(false)
54 {
55  pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);
56  this->format = format.clone();
57  setLogSize(size);
58 
59  if (identifier.empty()) {
60  this->identifier = Process::getBaseName();
61  }
62 
63  ::openlog(this->identifier.c_str(), option, facility);
64 }
65 
66 Log::Log(const std::string &file, const LogFormat &format, size_t size) throw (LogException) :
67  references(*(new uint64_t(1))),
68  everyN(*(new uint64_t(1))),
69  identifier(file),
70  facility(::open(file.c_str(), O_APPEND|O_CREAT|O_NONBLOCK, S_IRWXU)),
71  option(0),
72 
73  syslog(false),
74  syslogMask(0),
75 
76  allTraceOptions(false)
77 {
78  pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);
79  this->format = format.clone();
80  setLogSize(size);
81 
82  if (this->facility < 0) {
83  THROW(LogException, "failed to open file '%s' for logging", file.c_str());
84  }
85 }
86 
87 Log::Log(const Log &other) throw () :
88  references(other.references),
89  everyN(other.everyN),
90 
91  identifier(other.identifier),
92  facility(other.facility),
93  option(other.option),
94 
95  format(NULL),
96  syslog(other.syslog),
97  syslogMask(other.syslogMask),
98  size(other.size),
99 
100  traceOptions(other.traceOptions),
101  allTraceOptions(other.allTraceOptions)
102 {
103  pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);
104  this->references += 1;
105  this->format = other.format->clone();
106 }
107 
108 Log::~Log() throw () {
109  if ((--(this->references)) == 0) {
110  delete &(this->references);
111  delete &(this->everyN);
112  delete format;
113 
114  if (this->syslog) {
115  closelog();
116  } else {
117  close(this->facility);
118  }
119  }
120 
121  pthread_spin_destroy(&mutex);
122 }
123 
124 Log& Log::operator=(const Log &other) throw () {
125  if (this != &other) {
126  pthread_spin_lock(&mutex);
127 
128  this->references = other.references;
129  this->references += 1;
130  this->everyN = other.everyN;
131 
132  this->identifier = other.identifier;
133  this->facility = other.facility;
134  this->option = other.option;
135 
136  if (this->format) {
137  delete format;
138  }
139 
140  this->format = other.format->clone();
141  this->syslog = other.syslog;
142  this->syslogMask = other.syslogMask;
143  this->size = other.size;
144 
145  this->traceOptions = other.traceOptions;
146  this->allTraceOptions = other.allTraceOptions;
147 
148  pthread_spin_unlock(&mutex);
149  }
150  return *this;
151 }
152 
153 const Log::shared Log::shared_ptr(const std::string &identifier, int facility, int option, int mask, const LogFormat &format, size_t size) throw (LogException) {
154  return std::make_shared<Log>(identifier, facility, option, mask, format, size);
155 }
156 
157 const Log::shared Log::shared_ptr(const std::string &file, const LogFormat &format, size_t size) throw (LogException) {
158  return std::make_shared<Log>(file, format, size);
159 }
160 
161 const char* Log::priority(int level) throw () {
162  switch (LOG_PRI(level)) {
163  case Log::LEVEL_EMERGENCY:
164  return Log::LABEL_EMERGENCY;
165  case Log::LEVEL_ALERT:
166  return Log::LABEL_ALERT;
167  case Log::LEVEL_CRITICAL:
168  return Log::LABEL_CRITICAL;
169  case Log::LEVEL_ERROR:
170  return Log::LABEL_ERROR;
171  case Log::LEVEL_WARNING:
172  return Log::LABEL_WARNING;
173  case Log::LEVEL_NOTICE:
174  return Log::LABEL_NOTICE;
175  case Log::LEVEL_INFO:
176  return Log::LABEL_INFO;
177  case Log::LEVEL_DEBUG:
178  return Log::LABEL_DEBUG;
179  }
180 
181  return "UNKN";
182 }
183 
184 void Log::setIdentifier(const std::string &identifier) throw () {
185  this->identifier = identifier;
186 
187  ::openlog(identifier.c_str(), option, facility);
188 }
189 
190 void Log::setFacility(int facility) throw () {
191  this->facility = facility;
192 
193  ::openlog(identifier.c_str(), option, facility);
194 }
195 
196 void Log::setOption(int option) throw () {
197  this->option = option;
198 
199  ::openlog(identifier.c_str(), option, facility);
200 }
201 
202 void Log::setFormat(const LogFormat &format) throw () {
203  pthread_spin_lock(&mutex);
204 
205  if (this->format) {
206  delete this->format;
207  }
208 
209  this->format = format.clone();
210 
211  pthread_spin_unlock(&mutex);
212 }
213 
214 void Log::setLogLevel(int level, bool on) throw () {
215  pthread_spin_lock(&mutex);
216 
217  if (on) {
218  this->syslogMask |= LOG_MASK(level);
219  } else {
220  this->syslogMask &= ~LOG_MASK(level);
221  }
222 
223  pthread_spin_unlock(&mutex);
224 }
225 
226 int Log::setLogMask(int mask) throw () {
227  pthread_spin_lock(&mutex);
228 
229  int prevMask = this->syslogMask;
230  this->syslogMask = mask;
231 
232  pthread_spin_unlock(&mutex);
233 
234  return prevMask;
235 }
236 
237 void Log::setLogSize(size_t size) throw () {
238  this->size = (size < BUFFER_SIZE) ? size : BUFFER_SIZE;
239 }
240 
241 int Log::getLogMask(void) throw () {
242  return this->syslogMask;
243 }
244 
245 bool Log::isLogMask(int level) throw () {
246  return (this->syslogMask & LOG_MASK(level));
247 }
248 
249 size_t Log::getLogSize(void) throw () {
250  return this->size;
251 }
252 
253 void Log::setTraceOption(const std::string &option, bool on) throw () {
254  /* No mutex for 'all' to make this signal handler safe. */
255  if (option.compare("all") == 0) {
256  allTraceOptions = on;
257 
258  return;
259  }
260 
261  pthread_spin_lock(&mutex);
262 
263  if (on) {
264  traceOptions.insert(option);
265  } else {
266  traceOptions.erase(option);
267  }
268 
269  pthread_spin_unlock(&mutex);
270 }
271 
272 void Log::setTraceOption(const std::vector<std::string> &options, bool on) throw () {
273  setTraceOptions(options, on);
274 }
275 
276 void Log::setTraceOption(const std::list<std::string> &options, bool on) throw () {
277  setTraceOptions(options, on);
278 }
279 
280 void Log::setTraceOptions(const std::vector<std::string> &options, bool on) throw () {
281  for (auto it = options.cbegin(); it != options.cend(); ++it) {
282  setTraceOption(*it, on);
283  }
284 }
285 
286 void Log::setTraceOptions(const std::list<std::string> &options, bool on) throw () {
287  for (auto it = options.cbegin(); it != options.cend(); ++it) {
288  setTraceOption(*it, on);
289  }
290 }
291 
292 bool Log::isTraceOption(const char* option) throw () {
293  assert(option);
294 
295  /* Thread safe operations. */
296  if (allTraceOptions) {
297  return true;
298  } else if (traceOptions.empty()) {
299  return false;
300  }
301 
302  pthread_spin_lock(&mutex);
303 
304  if (traceOptions.find(option) == traceOptions.end()) {
305  pthread_spin_unlock(&mutex);
306 
307  return false;
308  }
309 
310  pthread_spin_unlock(&mutex);
311 
312  return true;
313 }
314 
315 bool Log::isTraceOption(const std::string &option) throw () {
316  /* Thread safe operations. */
317  if (allTraceOptions) {
318  return true;
319  } else if (traceOptions.empty()) {
320  return false;
321  }
322 
323  pthread_spin_lock(&mutex);
324 
325  if (traceOptions.find(option) == traceOptions.end()) {
326  pthread_spin_unlock(&mutex);
327 
328  return false;
329  }
330 
331  pthread_spin_unlock(&mutex);
332 
333  return true;
334 }
335 
336 bool Log::isTraceOption(const std::vector<std::string> &options) throw () {
337  for (auto &&o: options) {
338  if (isTraceOption(o)) {
339  return true;
340  }
341  }
342 
343  return false;
344 }
345 
346 bool Log::isTraceOption(const std::list<std::string> &options) throw () {
347  for (auto &&o: options) {
348  if (isTraceOption(o)) {
349  return true;
350  }
351  }
352 
353  return false;
354 }
355 
356 bool Log::hasTraceOptions(void) throw () {
357  return (allTraceOptions || traceOptions.empty());
358 }
359 
360 void Log::clearTraceOptions(void) throw () {
361  pthread_spin_lock(&mutex);
362 
363  allTraceOptions = false;
364  traceOptions.clear();
365 
366  pthread_spin_unlock(&mutex);
367 }
368 
369 bool Log::isTime(time_t &next, int sec) throw () {
370  time_t now = time(NULL);
371 
372  if (time(NULL) >= next) {
373  next = now + sec;
374 
375  return true;
376  }
377 
378  return false;
379 }
380 
381 bool Log::incEveryN(uint64_t n) throw () {
382  pthread_spin_lock(&mutex);
383 
384  bool result = (everyN++ % n == 0);
385 
386  pthread_spin_unlock(&mutex);
387 
388  return result;
389 }
390 
391 bool Log::incFirstN(uint64_t n) throw () {
392  pthread_spin_lock(&mutex);
393 
394  bool result = (everyN++ <= n);
395 
396  pthread_spin_unlock(&mutex);
397 
398  return result;
399 }
400 
401 void Log::resetEveryN(void) throw () {
402  pthread_spin_lock(&mutex);
403 
404  this->everyN = 0;
405 
406  pthread_spin_unlock(&mutex);
407 }
408 
409 bool Log::trace(const char *option, const char *func, const char *file, int line, const char *format, ...) throw () {
410  int level = Log::LEVEL_INFO;
411  va_list arguments;
412  char buffer[BUFFER_SIZE];
413  struct timeval stamp;
414 
415  gettimeofday(&stamp, NULL);
416 
417  if (format == NULL) {
418  buffer[0] = '\0';
419  } else {
420  va_start(arguments, format);
421  vsnprintf(buffer, sizeof(buffer), format, arguments);
422  va_end(arguments);
423  }
424 
425  pthread_spin_lock(&mutex);
426 
427  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option, buffer);
428 
429  if (this->syslog) {
430  resize(text);
431  ::syslog(facility|level, "%s", text.c_str());
432  } else {
433  ssize_t c; (void) c; // Suppress warning
434 
435  c = ::write(this->facility, text.c_str(), text.size());
436  c = ::write(this->facility, "\n", 1);
437  }
438 
439  pthread_spin_unlock(&mutex);
440 
441  return true;
442 }
443 
444 bool Log::trace(std::string &option, const char *func, const char *file, int line, const char *format, ...) throw () {
445  int level = Log::LEVEL_INFO;
446  va_list arguments;
447  char buffer[BUFFER_SIZE];
448  struct timeval stamp;
449 
450  gettimeofday(&stamp, NULL);
451 
452  if (format == NULL) {
453  buffer[0] = '\0';
454  } else {
455  va_start(arguments, format);
456  vsnprintf(buffer, sizeof(buffer), format, arguments);
457  va_end(arguments);
458  }
459 
460  pthread_spin_lock(&mutex);
461 
462  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option.c_str(), buffer);
463 
464  if (this->syslog) {
465  resize(text);
466  ::syslog(facility|level, "%s", text.c_str());
467  } else {
468  ssize_t c; (void) c; // Suppress warning
469 
470  c = ::write(this->facility, text.c_str(), text.size());
471  c = ::write(this->facility, "\n", 1);
472  }
473 
474  pthread_spin_unlock(&mutex);
475 
476  return true;
477 }
478 
479 bool Log::trace(const char *option, const char *func, const char *file, int line, const std::string &format, ...) throw () {
480  int level = Log::LEVEL_INFO;
481  va_list arguments;
482  char buffer[BUFFER_SIZE];
483  struct timeval stamp;
484 
485  gettimeofday(&stamp, NULL);
486 
487  va_start(arguments, format);
488  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
489  va_end(arguments);
490 
491  pthread_spin_lock(&mutex);
492 
493  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option, buffer);
494 
495  if (this->syslog) {
496  resize(text);
497  ::syslog(facility|level, "%s", text.c_str());
498  } else {
499  ssize_t c; (void) c; // Suppress warning
500 
501  c = ::write(this->facility, text.c_str(), text.size());
502  c = ::write(this->facility, "\n", 1);
503  }
504 
505  pthread_spin_unlock(&mutex);
506 
507  return true;
508 }
509 
510 bool Log::trace(std::string &option, const char *func, const char *file, int line, const std::string &format, ...) throw () {
511  int level = Log::LEVEL_INFO;
512  va_list arguments;
513  char buffer[BUFFER_SIZE];
514  struct timeval stamp;
515 
516  gettimeofday(&stamp, NULL);
517 
518  va_start(arguments, format);
519  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
520  va_end(arguments);
521 
522  pthread_spin_lock(&mutex);
523 
524  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option.c_str(), buffer);
525 
526  if (this->syslog) {
527  resize(text);
528  ::syslog(facility|level, "%s", text.c_str());
529  } else {
530  ssize_t c; (void) c; // Suppress warning
531 
532  c = ::write(this->facility, text.c_str(), text.size());
533  c = ::write(this->facility, "\n", 1);
534  }
535 
536  pthread_spin_unlock(&mutex);
537 
538  return true;
539 }
540 
541 bool Log::trace(const std::vector<std::string> &options, const char *func, const char *file, int line, const char *format, ...) throw () {
542  std::string ops;
543  va_list arguments;
544  char buffer[BUFFER_SIZE];
545 
546  for (auto &&o: options) {
547  ops.append(o);
548  ops.push_back(',');
549  }
550 
551  ops.pop_back();
552 
553  if (format == NULL) {
554  buffer[0] = '\0';
555  } else {
556  va_start(arguments, format);
557  vsnprintf(buffer, sizeof(buffer), format, arguments);
558  va_end(arguments);
559  }
560 
561  return trace(ops, func, file, line, buffer);
562 }
563 
564 bool Log::trace(const std::vector<std::string> &options, const char *func, const char *file, int line, const std::string &format, ...) throw () {
565  std::string ops;
566  va_list arguments;
567  char buffer[BUFFER_SIZE];
568 
569  for (auto &&o: options) {
570  ops.append(o);
571  ops.push_back(',');
572  }
573 
574  ops.pop_back();
575 
576  va_start(arguments, format);
577  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
578  va_end(arguments);
579 
580  return trace(ops, func, file, line, buffer);
581 }
582 
583 bool Log::trace(const std::list<std::string> &options, const char *func, const char *file, int line, const char *format, ...) throw () {
584  std::string ops;
585  va_list arguments;
586  char buffer[BUFFER_SIZE];
587 
588  for (auto &&o: options) {
589  ops.append(o);
590  ops.push_back(',');
591  }
592 
593  ops.pop_back();
594 
595  if (format == NULL) {
596  buffer[0] = '\0';
597  } else {
598  va_start(arguments, format);
599  vsnprintf(buffer, sizeof(buffer), format, arguments);
600  va_end(arguments);
601  }
602 
603  return trace(ops, func, file, line, buffer);
604 }
605 
606 bool Log::trace(const std::list<std::string> &options, const char *func, const char *file, int line, const std::string &format, ...) throw () {
607  std::string ops;
608  va_list arguments;
609  char buffer[BUFFER_SIZE];
610 
611  for (auto &&o: options) {
612  ops.append(o);
613  ops.push_back(',');
614  }
615 
616  ops.pop_back();
617 
618  va_start(arguments, format);
619  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
620  va_end(arguments);
621 
622  return trace(ops, func, file, line, buffer);
623 }
624 
625 bool Log::write(int facility, int level, const char *func, const char *file, int line, const sella::Exception &e, const std::string &format, ...) throw () {
626  va_list arguments;
627  char buffer[BUFFER_SIZE];
628  struct timeval stamp;
629 
630  if (!isLogMask(level)) {
631  return false;
632  }
633 
634  gettimeofday(&stamp, NULL);
635 
636  if (format.empty()) {
637  strncpy(buffer, "Exception", sizeof(buffer));
638  } else {
639  va_start(arguments, format);
640  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
641  va_end(arguments);
642  }
643 
644  pthread_spin_lock(&mutex);
645 
646  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
647 
648  if (this->syslog) {
649  resize(text);
650  ::syslog(facility|level, "%s", text.c_str());
651  } else {
652  ssize_t c; (void) c; // Suppress warning
653 
654  c = ::write(this->facility, text.c_str(), text.size());
655  c = ::write(this->facility, "\n", 1);
656  }
657 
658  pthread_spin_unlock(&mutex);
659 
660  return true;
661 }
662 
663 bool Log::write(int facility, int level, const char *func, const char *file, int line, const std::string &format, ...) throw () {
664  va_list arguments;
665  char buffer[BUFFER_SIZE];
666  struct timeval stamp;
667 
668  if (!isLogMask(level)) {
669  return false;
670  }
671 
672  gettimeofday(&stamp, NULL);
673 
674  va_start(arguments, format);
675  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
676  va_end(arguments);
677 
678  pthread_spin_lock(&mutex);
679 
680  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
681 
682  if (this->syslog) {
683  resize(text);
684  ::syslog(facility|level, "%s", text.c_str());
685  } else {
686  ssize_t c; (void) c; // Suppress warning
687 
688  c = ::write(this->facility, text.c_str(), text.size());
689  c = ::write(this->facility, "\n", 1);
690  }
691 
692  pthread_spin_unlock(&mutex);
693 
694  return true;
695 }
696 
697 bool Log::write(int level, const char *func, const char *file, int line, const sella::Exception &e) throw () {
698  struct timeval stamp;
699 
700  if (!isLogMask(level)) {
701  return false;
702  }
703 
704  gettimeofday(&stamp, NULL);
705 
706  pthread_spin_lock(&mutex);
707 
708  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, NULL);
709 
710  if (this->syslog) {
711  resize(text);
712  ::syslog(level, "%s", text.c_str());
713  } else {
714  ssize_t c; (void) c; // Suppress warning
715 
716  c = ::write(this->facility, text.c_str(), text.size());
717  c = ::write(this->facility, "\n", 1);
718  }
719 
720  pthread_spin_unlock(&mutex);
721 
722  return true;
723 }
724 
725 bool Log::write(int level, const char *func, const char *file, int line, const sella::Exception &e, const std::string &format, ...) throw () {
726  va_list arguments;
727  char buffer[BUFFER_SIZE];
728  struct timeval stamp;
729 
730  if (!isLogMask(level)) {
731  return false;
732  }
733 
734  gettimeofday(&stamp, NULL);
735 
736  if (format.empty()) {
737  strncpy(buffer, "Exception", sizeof(buffer));
738  } else {
739  va_start(arguments, format);
740  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
741  va_end(arguments);
742  }
743 
744  pthread_spin_lock(&mutex);
745 
746  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
747 
748  if (this->syslog) {
749  resize(text);
750  ::syslog(level, "%s", text.c_str());
751  } else {
752  ssize_t c; (void) c; // Suppress warning
753 
754  c = ::write(this->facility, text.c_str(), text.size());
755  c = ::write(this->facility, "\n", 1);
756  }
757 
758  pthread_spin_unlock(&mutex);
759 
760  return true;
761 }
762 
763 bool Log::write(int level, const char *func, const char *file, int line, const std::string &format, ...) throw () {
764  va_list arguments;
765  char buffer[BUFFER_SIZE];
766  struct timeval stamp;
767 
768  if (!isLogMask(level)) {
769  return false;
770  }
771 
772  gettimeofday(&stamp, NULL);
773 
774  va_start(arguments, format);
775  vsnprintf(buffer, sizeof(buffer), format.c_str(), arguments);
776  va_end(arguments);
777 
778  pthread_spin_lock(&mutex);
779 
780  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
781 
782  if (this->syslog) {
783  resize(text);
784  ::syslog(level, "%s", text.c_str());
785  } else {
786  ssize_t c; (void) c; // Suppress warning
787 
788  c = ::write(this->facility, text.c_str(), text.size());
789  c = ::write(this->facility, "\n", 1);
790  }
791 
792  pthread_spin_unlock(&mutex);
793 
794  return true;
795 }
796 
797 bool Log::write(int facility, int level, const char *func, const char *file, int line, const sella::Exception &e, const char *format, ...) throw () {
798  va_list arguments;
799  char buffer[BUFFER_SIZE];
800  struct timeval stamp;
801 
802  if (!isLogMask(level)) {
803  return false;
804  }
805 
806  gettimeofday(&stamp, NULL);
807 
808  if (format == NULL) {
809  buffer[0] = '\0';
810  } else if (format[0] == '\0') {
811  strncpy(buffer, "Exception", sizeof(buffer));
812  } else {
813  va_start(arguments, format);
814  vsnprintf(buffer, sizeof(buffer), format, arguments);
815  va_end(arguments);
816  }
817 
818  pthread_spin_lock(&mutex);
819 
820  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
821 
822  if (this->syslog) {
823  resize(text);
824  ::syslog(facility|level, "%s", text.c_str());
825  } else {
826  ssize_t c; (void) c; // Suppress warning
827 
828  c = ::write(this->facility, text.c_str(), text.size());
829  c = ::write(this->facility, "\n", 1);
830  }
831 
832  pthread_spin_unlock(&mutex);
833 
834  return true;
835 }
836 
837 bool Log::write(int facility, int level, const char *func, const char *file, int line, const char *format, ...) throw () {
838  va_list arguments;
839  char buffer[BUFFER_SIZE];
840  struct timeval stamp;
841 
842  if (!isLogMask(level)) {
843  return false;
844  }
845 
846  gettimeofday(&stamp, NULL);
847 
848  if (format == NULL) {
849  buffer[0] = '\0';
850  } else {
851  va_start(arguments, format);
852  vsnprintf(buffer, sizeof(buffer), format, arguments);
853  va_end(arguments);
854  }
855 
856  pthread_spin_lock(&mutex);
857 
858  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
859 
860  if (this->syslog) {
861  resize(text);
862  ::syslog(facility|level, "%s", text.c_str());
863  } else {
864  ssize_t c; (void) c; // Suppress warning
865 
866  c = ::write(this->facility, text.c_str(), text.size());
867  c = ::write(this->facility, "\n", 1);
868  }
869 
870  pthread_spin_unlock(&mutex);
871 
872  return true;
873 }
874 
875 bool Log::write(int level, const char *func, const char *file, int line, const sella::Exception &e, const char *format, ...) throw () {
876  va_list arguments;
877  char buffer[BUFFER_SIZE];
878  struct timeval stamp;
879 
880  if (!isLogMask(level)) {
881  return false;
882  }
883 
884  gettimeofday(&stamp, NULL);
885 
886  if (format == NULL) {
887  buffer[0] = '\0';
888  } else if (format[0] == '\0') {
889  strncpy(buffer, "Exception", sizeof(buffer));
890  } else {
891  va_start(arguments, format);
892  vsnprintf(buffer, sizeof(buffer), format, arguments);
893  va_end(arguments);
894  }
895 
896  pthread_spin_lock(&mutex);
897 
898  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
899 
900  if (this->syslog) {
901  resize(text);
902  ::syslog(level, "%s", text.c_str());
903  } else {
904  ssize_t c; (void) c; // Suppress warning
905 
906  c = ::write(this->facility, text.c_str(), text.size());
907  c = ::write(this->facility, "\n", 1);
908  }
909 
910  pthread_spin_unlock(&mutex);
911 
912  return true;
913 }
914 
915 bool Log::write(int level, const char *func, const char *file, int line, const char *format, ...) throw () {
916  va_list arguments;
917  char buffer[BUFFER_SIZE];
918  struct timeval stamp;
919 
920  if (!isLogMask(level)) {
921  return false;
922  }
923 
924  gettimeofday(&stamp, NULL);
925 
926  if (format == NULL) {
927  buffer[0] = '\0';
928  } else {
929  va_start(arguments, format);
930  vsnprintf(buffer, sizeof(buffer), format, arguments);
931  va_end(arguments);
932  }
933 
934  pthread_spin_lock(&mutex);
935 
936  std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
937 
938  if (this->syslog) {
939  resize(text);
940  ::syslog(level, "%s", text.c_str());
941  } else {
942  ssize_t c; (void) c; // Suppress warning
943 
944  c = ::write(this->facility, text.c_str(), text.size());
945  c = ::write(this->facility, "\n", 1);
946  }
947 
948  pthread_spin_unlock(&mutex);
949 
950  return true;
951 }
952 
953 void Log::resize(std::string &text) throw () {
954  if (text.size() > size) {
955  text.resize(size);
956  }
957 }
958 
959 Log::shared& Log::instance(const std::string &identifier) {
960  static Log::shared logger = Log::shared_ptr(identifier, LOG_LOCAL0, Log::WithStderrOption);
961 
962  return logger;
963 }
964 
965 /*
966 ** vim: noet ts=3 sw=3
967 */