9 static const char rcsid[] __attribute__((used)) =
"$Id: Log.cpp 1653 2016-02-28 19:54:59Z sella $";
12 #include "LogException.h"
13 #include "LogFormat.h"
15 #include "../Exception.h"
27 #define BUFFER_SIZE (64 * 1024)
29 using namespace sella::util;
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";
40 Log::shared libutilxx__log __attribute__((init_priority(101)));
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))),
46 identifier(identifier),
53 allTraceOptions(
false)
55 pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);
56 this->format = format.clone();
59 if (identifier.empty()) {
60 this->identifier = Process::getBaseName();
63 ::openlog(this->identifier.c_str(), option, facility);
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))),
70 facility(::open(file.c_str(), O_APPEND|O_CREAT|O_NONBLOCK, S_IRWXU)),
76 allTraceOptions(
false)
78 pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);
79 this->format = format.clone();
82 if (this->facility < 0) {
83 THROW(LogException,
"failed to open file '%s' for logging", file.c_str());
87 Log::Log(
const Log &other)
throw () :
88 references(other.references),
91 identifier(other.identifier),
92 facility(other.facility),
97 syslogMask(other.syslogMask),
100 traceOptions(other.traceOptions),
101 allTraceOptions(other.allTraceOptions)
103 pthread_spin_init(&mutex, PTHREAD_PROCESS_PRIVATE);
104 this->references += 1;
105 this->format = other.format->clone();
108 Log::~Log() throw () {
109 if ((--(this->references)) == 0) {
110 delete &(this->references);
111 delete &(this->everyN);
117 close(this->facility);
121 pthread_spin_destroy(&mutex);
124 Log& Log::operator=(
const Log &other)
throw () {
125 if (
this != &other) {
126 pthread_spin_lock(&mutex);
128 this->references = other.references;
129 this->references += 1;
130 this->everyN = other.everyN;
132 this->identifier = other.identifier;
133 this->facility = other.facility;
134 this->option = other.option;
140 this->format = other.format->clone();
141 this->syslog = other.syslog;
142 this->syslogMask = other.syslogMask;
143 this->size = other.size;
145 this->traceOptions = other.traceOptions;
146 this->allTraceOptions = other.allTraceOptions;
148 pthread_spin_unlock(&mutex);
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);
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);
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;
184 void Log::setIdentifier(
const std::string &identifier)
throw () {
185 this->identifier = identifier;
187 ::openlog(identifier.c_str(), option, facility);
190 void Log::setFacility(
int facility)
throw () {
191 this->facility = facility;
193 ::openlog(identifier.c_str(), option, facility);
196 void Log::setOption(
int option)
throw () {
197 this->option = option;
199 ::openlog(identifier.c_str(), option, facility);
202 void Log::setFormat(
const LogFormat &format)
throw () {
203 pthread_spin_lock(&mutex);
209 this->format = format.clone();
211 pthread_spin_unlock(&mutex);
214 void Log::setLogLevel(
int level,
bool on)
throw () {
215 pthread_spin_lock(&mutex);
218 this->syslogMask |= LOG_MASK(level);
220 this->syslogMask &= ~LOG_MASK(level);
223 pthread_spin_unlock(&mutex);
226 int Log::setLogMask(
int mask)
throw () {
227 pthread_spin_lock(&mutex);
229 int prevMask = this->syslogMask;
230 this->syslogMask = mask;
232 pthread_spin_unlock(&mutex);
237 void Log::setLogSize(
size_t size)
throw () {
238 this->size = (size < BUFFER_SIZE) ? size : BUFFER_SIZE;
241 int Log::getLogMask(
void) throw () {
242 return this->syslogMask;
245 bool Log::isLogMask(
int level)
throw () {
246 return (this->syslogMask & LOG_MASK(level));
249 size_t Log::getLogSize(
void) throw () {
253 void Log::setTraceOption(
const std::string &option,
bool on)
throw () {
255 if (option.compare(
"all") == 0) {
256 allTraceOptions = on;
261 pthread_spin_lock(&mutex);
264 traceOptions.insert(option);
266 traceOptions.erase(option);
269 pthread_spin_unlock(&mutex);
272 void Log::setTraceOption(
const std::vector<std::string> &options,
bool on)
throw () {
273 setTraceOptions(options, on);
276 void Log::setTraceOption(
const std::list<std::string> &options,
bool on)
throw () {
277 setTraceOptions(options, on);
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);
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);
292 bool Log::isTraceOption(
const char* option)
throw () {
296 if (allTraceOptions) {
298 }
else if (traceOptions.empty()) {
302 pthread_spin_lock(&mutex);
304 if (traceOptions.find(option) == traceOptions.end()) {
305 pthread_spin_unlock(&mutex);
310 pthread_spin_unlock(&mutex);
315 bool Log::isTraceOption(
const std::string &option)
throw () {
317 if (allTraceOptions) {
319 }
else if (traceOptions.empty()) {
323 pthread_spin_lock(&mutex);
325 if (traceOptions.find(option) == traceOptions.end()) {
326 pthread_spin_unlock(&mutex);
331 pthread_spin_unlock(&mutex);
336 bool Log::isTraceOption(
const std::vector<std::string> &options)
throw () {
337 for (
auto &&o: options) {
338 if (isTraceOption(o)) {
346 bool Log::isTraceOption(
const std::list<std::string> &options)
throw () {
347 for (
auto &&o: options) {
348 if (isTraceOption(o)) {
356 bool Log::hasTraceOptions(
void) throw () {
357 return (allTraceOptions || traceOptions.empty());
360 void Log::clearTraceOptions(
void) throw () {
361 pthread_spin_lock(&mutex);
363 allTraceOptions =
false;
364 traceOptions.clear();
366 pthread_spin_unlock(&mutex);
369 bool Log::isTime(time_t &next,
int sec)
throw () {
370 time_t now = time(NULL);
372 if (time(NULL) >= next) {
381 bool Log::incEveryN(uint64_t n)
throw () {
382 pthread_spin_lock(&mutex);
384 bool result = (everyN++ % n == 0);
386 pthread_spin_unlock(&mutex);
391 bool Log::incFirstN(uint64_t n)
throw () {
392 pthread_spin_lock(&mutex);
394 bool result = (everyN++ <= n);
396 pthread_spin_unlock(&mutex);
401 void Log::resetEveryN(
void) throw () {
402 pthread_spin_lock(&mutex);
406 pthread_spin_unlock(&mutex);
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;
412 char buffer[BUFFER_SIZE];
413 struct timeval stamp;
415 gettimeofday(&stamp, NULL);
417 if (format == NULL) {
420 va_start(arguments, format);
421 vsnprintf(buffer,
sizeof(buffer), format, arguments);
425 pthread_spin_lock(&mutex);
427 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option, buffer);
431 ::syslog(facility|level,
"%s", text.c_str());
435 c = ::write(this->facility, text.c_str(), text.size());
436 c = ::write(this->facility,
"\n", 1);
439 pthread_spin_unlock(&mutex);
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;
447 char buffer[BUFFER_SIZE];
448 struct timeval stamp;
450 gettimeofday(&stamp, NULL);
452 if (format == NULL) {
455 va_start(arguments, format);
456 vsnprintf(buffer,
sizeof(buffer), format, arguments);
460 pthread_spin_lock(&mutex);
462 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option.c_str(), buffer);
466 ::syslog(facility|level,
"%s", text.c_str());
470 c = ::write(this->facility, text.c_str(), text.size());
471 c = ::write(this->facility,
"\n", 1);
474 pthread_spin_unlock(&mutex);
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;
482 char buffer[BUFFER_SIZE];
483 struct timeval stamp;
485 gettimeofday(&stamp, NULL);
487 va_start(arguments, format);
488 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
491 pthread_spin_lock(&mutex);
493 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option, buffer);
497 ::syslog(facility|level,
"%s", text.c_str());
501 c = ::write(this->facility, text.c_str(), text.size());
502 c = ::write(this->facility,
"\n", 1);
505 pthread_spin_unlock(&mutex);
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;
513 char buffer[BUFFER_SIZE];
514 struct timeval stamp;
516 gettimeofday(&stamp, NULL);
518 va_start(arguments, format);
519 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
522 pthread_spin_lock(&mutex);
524 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, option.c_str(), buffer);
528 ::syslog(facility|level,
"%s", text.c_str());
532 c = ::write(this->facility, text.c_str(), text.size());
533 c = ::write(this->facility,
"\n", 1);
536 pthread_spin_unlock(&mutex);
541 bool Log::trace(
const std::vector<std::string> &options,
const char *func,
const char *file,
int line,
const char *format, ...) throw () {
544 char buffer[BUFFER_SIZE];
546 for (
auto &&o: options) {
553 if (format == NULL) {
556 va_start(arguments, format);
557 vsnprintf(buffer,
sizeof(buffer), format, arguments);
561 return trace(ops, func, file, line, buffer);
564 bool Log::trace(
const std::vector<std::string> &options,
const char *func,
const char *file,
int line,
const std::string &format, ...) throw () {
567 char buffer[BUFFER_SIZE];
569 for (
auto &&o: options) {
576 va_start(arguments, format);
577 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
580 return trace(ops, func, file, line, buffer);
583 bool Log::trace(
const std::list<std::string> &options,
const char *func,
const char *file,
int line,
const char *format, ...) throw () {
586 char buffer[BUFFER_SIZE];
588 for (
auto &&o: options) {
595 if (format == NULL) {
598 va_start(arguments, format);
599 vsnprintf(buffer,
sizeof(buffer), format, arguments);
603 return trace(ops, func, file, line, buffer);
606 bool Log::trace(
const std::list<std::string> &options,
const char *func,
const char *file,
int line,
const std::string &format, ...) throw () {
609 char buffer[BUFFER_SIZE];
611 for (
auto &&o: options) {
618 va_start(arguments, format);
619 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
622 return trace(ops, func, file, line, buffer);
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 () {
627 char buffer[BUFFER_SIZE];
628 struct timeval stamp;
630 if (!isLogMask(level)) {
634 gettimeofday(&stamp, NULL);
636 if (format.empty()) {
637 strncpy(buffer,
"Exception",
sizeof(buffer));
639 va_start(arguments, format);
640 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
644 pthread_spin_lock(&mutex);
646 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
650 ::syslog(facility|level,
"%s", text.c_str());
654 c = ::write(this->facility, text.c_str(), text.size());
655 c = ::write(this->facility,
"\n", 1);
658 pthread_spin_unlock(&mutex);
663 bool Log::write(
int facility,
int level,
const char *func,
const char *file,
int line,
const std::string &format, ...) throw () {
665 char buffer[BUFFER_SIZE];
666 struct timeval stamp;
668 if (!isLogMask(level)) {
672 gettimeofday(&stamp, NULL);
674 va_start(arguments, format);
675 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
678 pthread_spin_lock(&mutex);
680 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
684 ::syslog(facility|level,
"%s", text.c_str());
688 c = ::write(this->facility, text.c_str(), text.size());
689 c = ::write(this->facility,
"\n", 1);
692 pthread_spin_unlock(&mutex);
697 bool Log::write(
int level,
const char *func,
const char *file,
int line,
const sella::Exception &e)
throw () {
698 struct timeval stamp;
700 if (!isLogMask(level)) {
704 gettimeofday(&stamp, NULL);
706 pthread_spin_lock(&mutex);
708 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, NULL);
712 ::syslog(level,
"%s", text.c_str());
716 c = ::write(this->facility, text.c_str(), text.size());
717 c = ::write(this->facility,
"\n", 1);
720 pthread_spin_unlock(&mutex);
725 bool Log::write(
int level,
const char *func,
const char *file,
int line,
const sella::Exception &e,
const std::string &format, ...) throw () {
727 char buffer[BUFFER_SIZE];
728 struct timeval stamp;
730 if (!isLogMask(level)) {
734 gettimeofday(&stamp, NULL);
736 if (format.empty()) {
737 strncpy(buffer,
"Exception",
sizeof(buffer));
739 va_start(arguments, format);
740 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
744 pthread_spin_lock(&mutex);
746 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
750 ::syslog(level,
"%s", text.c_str());
754 c = ::write(this->facility, text.c_str(), text.size());
755 c = ::write(this->facility,
"\n", 1);
758 pthread_spin_unlock(&mutex);
763 bool Log::write(
int level,
const char *func,
const char *file,
int line,
const std::string &format, ...) throw () {
765 char buffer[BUFFER_SIZE];
766 struct timeval stamp;
768 if (!isLogMask(level)) {
772 gettimeofday(&stamp, NULL);
774 va_start(arguments, format);
775 vsnprintf(buffer,
sizeof(buffer), format.c_str(), arguments);
778 pthread_spin_lock(&mutex);
780 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
784 ::syslog(level,
"%s", text.c_str());
788 c = ::write(this->facility, text.c_str(), text.size());
789 c = ::write(this->facility,
"\n", 1);
792 pthread_spin_unlock(&mutex);
797 bool Log::write(
int facility,
int level,
const char *func,
const char *file,
int line,
const sella::Exception &e,
const char *format, ...) throw () {
799 char buffer[BUFFER_SIZE];
800 struct timeval stamp;
802 if (!isLogMask(level)) {
806 gettimeofday(&stamp, NULL);
808 if (format == NULL) {
810 }
else if (format[0] ==
'\0') {
811 strncpy(buffer,
"Exception",
sizeof(buffer));
813 va_start(arguments, format);
814 vsnprintf(buffer,
sizeof(buffer), format, arguments);
818 pthread_spin_lock(&mutex);
820 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
824 ::syslog(facility|level,
"%s", text.c_str());
828 c = ::write(this->facility, text.c_str(), text.size());
829 c = ::write(this->facility,
"\n", 1);
832 pthread_spin_unlock(&mutex);
837 bool Log::write(
int facility,
int level,
const char *func,
const char *file,
int line,
const char *format, ...) throw () {
839 char buffer[BUFFER_SIZE];
840 struct timeval stamp;
842 if (!isLogMask(level)) {
846 gettimeofday(&stamp, NULL);
848 if (format == NULL) {
851 va_start(arguments, format);
852 vsnprintf(buffer,
sizeof(buffer), format, arguments);
856 pthread_spin_lock(&mutex);
858 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
862 ::syslog(facility|level,
"%s", text.c_str());
866 c = ::write(this->facility, text.c_str(), text.size());
867 c = ::write(this->facility,
"\n", 1);
870 pthread_spin_unlock(&mutex);
875 bool Log::write(
int level,
const char *func,
const char *file,
int line,
const sella::Exception &e,
const char *format, ...) throw () {
877 char buffer[BUFFER_SIZE];
878 struct timeval stamp;
880 if (!isLogMask(level)) {
884 gettimeofday(&stamp, NULL);
886 if (format == NULL) {
888 }
else if (format[0] ==
'\0') {
889 strncpy(buffer,
"Exception",
sizeof(buffer));
891 va_start(arguments, format);
892 vsnprintf(buffer,
sizeof(buffer), format, arguments);
896 pthread_spin_lock(&mutex);
898 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, e, buffer);
902 ::syslog(level,
"%s", text.c_str());
906 c = ::write(this->facility, text.c_str(), text.size());
907 c = ::write(this->facility,
"\n", 1);
910 pthread_spin_unlock(&mutex);
915 bool Log::write(
int level,
const char *func,
const char *file,
int line,
const char *format, ...) throw () {
917 char buffer[BUFFER_SIZE];
918 struct timeval stamp;
920 if (!isLogMask(level)) {
924 gettimeofday(&stamp, NULL);
926 if (format == NULL) {
929 va_start(arguments, format);
930 vsnprintf(buffer,
sizeof(buffer), format, arguments);
934 pthread_spin_lock(&mutex);
936 std::string text = this->format->format(level, this->format->format(stamp).c_str(), func, file, line, buffer);
940 ::syslog(level,
"%s", text.c_str());
944 c = ::write(this->facility, text.c_str(), text.size());
945 c = ::write(this->facility,
"\n", 1);
948 pthread_spin_unlock(&mutex);
953 void Log::resize(std::string &text)
throw () {
954 if (text.size() > size) {
959 Log::shared& Log::instance(
const std::string &identifier) {
960 static Log::shared logger = Log::shared_ptr(identifier, LOG_LOCAL0, Log::WithStderrOption);