easylogging++.cc
Go to the documentation of this file.
1 //
2 // Bismillah ar-Rahmaan ar-Raheem
3 //
4 // Easylogging++ v9.96.5
5 // Cross-platform logging library for C++ applications
6 //
7 // Copyright (c) 2012-2018 Muflihun Labs
8 // Copyright (c) 2012-2018 @abumusamq
9 //
10 // This library is released under the MIT Licence.
11 // https://github.com/muflihun/easyloggingpp/blob/master/LICENSE
12 //
13 // https://github.com/muflihun/easyloggingpp
14 // https://muflihun.github.io/easyloggingpp
15 // http://muflihun.com
16 //
17 
18 #include "easylogging++.h"
19 #ifdef ANDROID
20 #include <android/log.h>
21 #endif
22 
23 #if defined(AUTO_INITIALIZE_EASYLOGGINGPP)
25 #endif
26 
27 namespace el {
28 
29 // el::base
30 namespace base {
31 // el::base::consts
32 namespace consts {
33 
34 // Level log values - These are values that are replaced in place of %level format specifier
35 // Extra spaces after format specifiers are only for readability purposes in log files
42  ELPP_LITERAL("VERBOSE"); // will become VERBOSE-x where x = verbose level
51 // Format specifiers - These are used to define log format
67 static const char* kDateTimeFormatSpecifierForFilename = "%datetime";
68 // Date/time
69 static const char* kDays[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
70 static const char* kDaysAbbrev[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
71 static const char* kMonths[12] = { "January", "February", "March", "Apri", "May", "June", "July", "August",
72  "September", "October", "November", "December"
73  };
74 static const char* kMonthsAbbrev[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
75 static const char* kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g";
76 static const char* kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m";
77 static const int kYearBase = 1900;
78 static const char* kAm = "AM";
79 static const char* kPm = "PM";
80 // Miscellaneous constants
81 
82 static const char* kNullPointer = "nullptr";
83 #if ELPP_VARIADIC_TEMPLATES_SUPPORTED
84 #endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
86 static const char* kUnknownUser = "user";
87 static const char* kUnknownHost = "unknown-host";
88 
89 
90 //---------------- DEFAULT LOG FILE -----------------------
91 
92 #if defined(ELPP_NO_DEFAULT_LOG_FILE)
93 # if ELPP_OS_UNIX
94 static const char* kDefaultLogFile = "/dev/null";
95 # elif ELPP_OS_WINDOWS
96 static const char* kDefaultLogFile = "nul";
97 # endif // ELPP_OS_UNIX
98 #elif defined(ELPP_DEFAULT_LOG_FILE)
99 static const char* kDefaultLogFile = ELPP_DEFAULT_LOG_FILE;
100 #else
101 static const char* kDefaultLogFile = "myeasylog.log";
102 #endif // defined(ELPP_NO_DEFAULT_LOG_FILE)
103 
104 
105 #if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
106 static const char* kDefaultLogFileParam = "--default-log-file";
107 #endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
108 #if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
109 static const char* kLoggingFlagsParam = "--logging-flags";
110 #endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
111 static const char* kValidLoggerIdSymbols =
112  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
113 static const char* kConfigurationComment = "##";
114 static const char* kConfigurationLevel = "*";
115 static const char* kConfigurationLoggerId = "--";
116 }
117 // el::base::utils
118 namespace utils {
119 
121 static void abort(int status, const std::string& reason) {
122  // Both status and reason params are there for debugging with tools like gdb etc
123  ELPP_UNUSED(status);
124  ELPP_UNUSED(reason);
125 #if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
126  // Ignore msvc critical error dialog - break instead (on debug mode)
127  _asm int 3
128 #else
129  ::abort();
130 #endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
131 }
132 
133 } // namespace utils
134 } // namespace base
135 
136 // el
137 
138 // LevelHelper
139 
141  // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
142  if (level == Level::Global) return "GLOBAL";
143  if (level == Level::Debug) return "DEBUG";
144  if (level == Level::Info) return "INFO";
145  if (level == Level::Warning) return "WARNING";
146  if (level == Level::Error) return "ERROR";
147  if (level == Level::Fatal) return "FATAL";
148  if (level == Level::Verbose) return "VERBOSE";
149  if (level == Level::Trace) return "TRACE";
150  return "UNKNOWN";
151 }
152 
154  const char* levelString;
156 };
157 
159  { "global", Level::Global },
160  { "debug", Level::Debug },
161  { "info", Level::Info },
162  { "warning", Level::Warning },
163  { "error", Level::Error },
164  { "fatal", Level::Fatal },
165  { "verbose", Level::Verbose },
166  { "trace", Level::Trace }
167 };
168 
169 Level LevelHelper::convertFromString(const char* levelStr) {
170  for (auto& item : stringToLevelMap) {
171  if (base::utils::Str::cStringCaseEq(levelStr, item.levelString)) {
172  return item.level;
173  }
174  }
175  return Level::Unknown;
176 }
177 
178 void LevelHelper::forEachLevel(base::type::EnumType* startIndex, const std::function<bool(void)>& fn) {
180  do {
181  if (fn()) {
182  break;
183  }
184  *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
185  } while (*startIndex <= lIndexMax);
186 }
187 
188 // ConfigurationTypeHelper
189 
191  // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
192  if (configurationType == ConfigurationType::Enabled) return "ENABLED";
193  if (configurationType == ConfigurationType::Filename) return "FILENAME";
194  if (configurationType == ConfigurationType::Format) return "FORMAT";
195  if (configurationType == ConfigurationType::ToFile) return "TO_FILE";
196  if (configurationType == ConfigurationType::ToStandardOutput) return "TO_STANDARD_OUTPUT";
197  if (configurationType == ConfigurationType::SubsecondPrecision) return "SUBSECOND_PRECISION";
198  if (configurationType == ConfigurationType::PerformanceTracking) return "PERFORMANCE_TRACKING";
199  if (configurationType == ConfigurationType::MaxLogFileSize) return "MAX_LOG_FILE_SIZE";
200  if (configurationType == ConfigurationType::LogFlushThreshold) return "LOG_FLUSH_THRESHOLD";
201  return "UNKNOWN";
202 }
203 
205  const char* configString;
207 };
208 
210  { "enabled", ConfigurationType::Enabled },
211  { "to_file", ConfigurationType::ToFile },
212  { "to_standard_output", ConfigurationType::ToStandardOutput },
213  { "format", ConfigurationType::Format },
214  { "filename", ConfigurationType::Filename },
215  { "subsecond_precision", ConfigurationType::SubsecondPrecision },
216  { "milliseconds_width", ConfigurationType::MillisecondsWidth },
217  { "performance_tracking", ConfigurationType::PerformanceTracking },
218  { "max_log_file_size", ConfigurationType::MaxLogFileSize },
219  { "log_flush_threshold", ConfigurationType::LogFlushThreshold },
220 };
221 
223  for (auto& item : configStringToTypeMap) {
224  if (base::utils::Str::cStringCaseEq(configStr, item.configString)) {
225  return item.configType;
226  }
227  }
229 }
230 
231 void ConfigurationTypeHelper::forEachConfigType(base::type::EnumType* startIndex, const std::function<bool(void)>& fn) {
233  do {
234  if (fn()) {
235  break;
236  }
237  *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
238  } while (*startIndex <= cIndexMax);
239 }
240 
241 // Configuration
242 
244  m_level(c.m_level),
245  m_configurationType(c.m_configurationType),
246  m_value(c.m_value) {
247 }
248 
250  if (&c != this) {
251  m_level = c.m_level;
253  m_value = c.m_value;
254  }
255  return *this;
256 }
257 
260  m_level(level),
261  m_configurationType(configurationType),
262  m_value(value) {
263 }
264 
268  << ELPP_LITERAL(" = ") << m_value.c_str();
269 }
270 
273  m_level(level),
274  m_configurationType(configurationType) {
275 }
276 
278  return ((conf != nullptr) && (conf->level() == m_level) && (conf->configurationType() == m_configurationType));
279 }
280 
281 // Configurations
282 
284  m_configurationFile(std::string()),
285  m_isFromFile(false) {
286 }
287 
288 Configurations::Configurations(const std::string& configurationFile, bool useDefaultsForRemaining,
289  Configurations* base) :
290  m_configurationFile(configurationFile),
291  m_isFromFile(false) {
292  parseFromFile(configurationFile, base);
293  if (useDefaultsForRemaining) {
295  }
296 }
297 
299  // We initial assertion with true because if we have assertion diabled, we want to pass this
300  // check and if assertion is enabled we will have values re-assigned any way.
301  bool assertionPassed = true;
302  ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(configurationFile.c_str(), true)) == true,
303  "Configuration file [" << configurationFile << "] does not exist!");
304  if (!assertionPassed) {
305  return false;
306  }
307  bool success = Parser::parseFromFile(configurationFile, this, base);
309  return success;
310 }
311 
312 bool Configurations::parseFromText(const std::string& configurationsString, Configurations* base) {
313  bool success = Parser::parseFromText(configurationsString, this, base);
314  if (success) {
315  m_isFromFile = false;
316  }
317  return success;
318 }
319 
321  if (base == nullptr || base == this) {
322  return;
323  }
324  base::threading::ScopedLock scopedLock(base->lock());
325  for (Configuration*& conf : base->list()) {
326  set(conf);
327  }
328 }
329 
332  bool result = false;
333  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
334  if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) {
335  result = true;
336  }
337  return result;
338  });
339  return result;
340 }
341 
343  base::threading::ScopedLock scopedLock(lock());
344 #if ELPP_COMPILER_INTEL
345  // We cant specify template types here, Intel C++ throws compilation error
346  // "error: type name is not allowed"
347  return RegistryWithPred::get(level, configurationType) != nullptr;
348 #else
349  return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType) != nullptr;
350 #endif // ELPP_COMPILER_INTEL
351 }
352 
354  base::threading::ScopedLock scopedLock(lock());
355  unsafeSet(level, configurationType, value); // This is not unsafe anymore as we have locked mutex
356  if (level == Level::Global) {
357  unsafeSetGlobally(configurationType, value, false); // Again this is not unsafe either
358  }
359 }
360 
362  if (conf == nullptr) {
363  return;
364  }
365  set(conf->level(), conf->configurationType(), conf->value());
366 }
367 
371 #if defined(ELPP_NO_LOG_TO_FILE)
373 #else
375 #endif // defined(ELPP_NO_LOG_TO_FILE)
381 
382  setGlobally(ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"), true);
384  std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
385  // INFO and WARNING are set to default by Level::Global
386  set(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
387  set(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
388  set(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg"));
389  set(Level::Trace, ConfigurationType::Format, std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
390 }
391 
393  base::threading::ScopedLock scopedLock(lock());
394 #if defined(ELPP_NO_LOG_TO_FILE)
396 #else
398 #endif // defined(ELPP_NO_LOG_TO_FILE)
404  unsafeSetIfNotExist(Level::Global, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
406  std::string("%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
407  // INFO and WARNING are set to default by Level::Global
408  unsafeSetIfNotExist(Level::Error, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
409  unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format, std::string("%datetime %level [%logger] %msg"));
410  unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format, std::string("%datetime %level-%vlevel [%logger] %msg"));
412  std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
413 }
414 
416  Configurations* base) {
417  sender->setFromBase(base);
418  std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in);
419  ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file [" << configurationFile << "] for parsing.");
420  bool parsedSuccessfully = false;
422  Level currLevel = Level::Unknown;
423  std::string currConfigStr = std::string();
424  std::string currLevelStr = std::string();
425  while (fileStream_.good()) {
426  std::getline(fileStream_, line);
427  parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
428  ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line);
429  }
430  return parsedSuccessfully;
431 }
432 
433 bool Configurations::Parser::parseFromText(const std::string& configurationsString, Configurations* sender,
434  Configurations* base) {
435  sender->setFromBase(base);
436  bool parsedSuccessfully = false;
437  std::stringstream ss(configurationsString);
439  Level currLevel = Level::Unknown;
440  std::string currConfigStr = std::string();
441  std::string currLevelStr = std::string();
442  while (std::getline(ss, line)) {
443  parsedSuccessfully = parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
444  ELPP_ASSERT(parsedSuccessfully, "Unable to parse configuration line: " << line);
445  }
446  return parsedSuccessfully;
447 }
448 
450  std::size_t foundAt = 0;
451  std::size_t quotesStart = line->find("\"");
452  std::size_t quotesEnd = std::string::npos;
453  if (quotesStart != std::string::npos) {
454  quotesEnd = line->find("\"", quotesStart + 1);
455  while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') {
456  // Do not erase slash yet - we will erase it in parseLine(..) while loop
457  quotesEnd = line->find("\"", quotesEnd + 2);
458  }
459  }
460  if ((foundAt = line->find(base::consts::kConfigurationComment)) != std::string::npos) {
461  if (foundAt < quotesEnd) {
462  foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1);
463  }
464  *line = line->substr(0, foundAt);
465  }
466 }
467 
470 }
471 
474 }
475 
477  std::size_t assignment = line.find('=');
478  return line != "" &&
479  ((line[0] >= 'A' && line[0] <= 'Z') || (line[0] >= 'a' && line[0] <= 'z')) &&
480  (assignment != std::string::npos) &&
481  (line.size() > assignment);
482 }
483 
485  Level* currLevel,
486  Configurations* conf) {
488  std::string currValue = std::string();
489  *line = base::utils::Str::trim(*line);
490  if (isComment(*line)) return true;
491  ignoreComments(line);
492  *line = base::utils::Str::trim(*line);
493  if (line->empty()) {
494  // Comment ignored
495  return true;
496  }
497  if (isLevel(*line)) {
498  if (line->size() <= 2) {
499  return true;
500  }
501  *currLevelStr = line->substr(1, line->size() - 2);
502  *currLevelStr = base::utils::Str::toUpper(*currLevelStr);
503  *currLevelStr = base::utils::Str::trim(*currLevelStr);
504  *currLevel = LevelHelper::convertFromString(currLevelStr->c_str());
505  return true;
506  }
507  if (isConfig(*line)) {
508  std::size_t assignment = line->find('=');
509  *currConfigStr = line->substr(0, assignment);
510  *currConfigStr = base::utils::Str::toUpper(*currConfigStr);
511  *currConfigStr = base::utils::Str::trim(*currConfigStr);
512  currConfig = ConfigurationTypeHelper::convertFromString(currConfigStr->c_str());
513  currValue = line->substr(assignment + 1);
514  currValue = base::utils::Str::trim(currValue);
515  std::size_t quotesStart = currValue.find("\"", 0);
516  std::size_t quotesEnd = std::string::npos;
517  if (quotesStart != std::string::npos) {
518  quotesEnd = currValue.find("\"", quotesStart + 1);
519  while (quotesEnd != std::string::npos && currValue.at(quotesEnd - 1) == '\\') {
520  currValue = currValue.erase(quotesEnd - 1, 1);
521  quotesEnd = currValue.find("\"", quotesEnd + 2);
522  }
523  }
524  if (quotesStart != std::string::npos && quotesEnd != std::string::npos) {
525  // Quote provided - check and strip if valid
526  ELPP_ASSERT((quotesStart < quotesEnd), "Configuration error - No ending quote found in ["
527  << currConfigStr << "]");
528  ELPP_ASSERT((quotesStart + 1 != quotesEnd), "Empty configuration value for [" << currConfigStr << "]");
529  if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) {
530  // Explicit check in case if assertion is disabled
531  currValue = currValue.substr(quotesStart + 1, quotesEnd - 1);
532  }
533  }
534  }
535  ELPP_ASSERT(*currLevel != Level::Unknown, "Unrecognized severity level [" << *currLevelStr << "]");
536  ELPP_ASSERT(currConfig != ConfigurationType::Unknown, "Unrecognized configuration [" << *currConfigStr << "]");
537  if (*currLevel == Level::Unknown || currConfig == ConfigurationType::Unknown) {
538  return false; // unrecognizable level or config
539  }
540  conf->set(*currLevel, currConfig, currValue);
541  return true;
542 }
543 
546  if (conf == nullptr) {
547  unsafeSet(level, configurationType, value);
548  }
549 }
550 
553  if (conf == nullptr) {
554  registerNew(new Configuration(level, configurationType, value));
555  } else {
556  conf->setValue(value);
557  }
558  if (level == Level::Global) {
559  unsafeSetGlobally(configurationType, value, false);
560  }
561 }
562 
564  bool includeGlobalLevel) {
565  if (includeGlobalLevel) {
566  set(Level::Global, configurationType, value);
567  }
569  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
570  set(LevelHelper::castFromInt(lIndex), configurationType, value);
571  return false; // Do not break lambda function yet as we need to set all levels regardless
572  });
573 }
574 
576  bool includeGlobalLevel) {
577  if (includeGlobalLevel) {
578  unsafeSet(Level::Global, configurationType, value);
579  }
581  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
582  unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value);
583  return false; // Do not break lambda function yet as we need to set all levels regardless
584  });
585 }
586 
587 // LogBuilder
588 
590  if (!m_termSupportsColor) return;
591  const base::type::char_t* resetColor = ELPP_LITERAL("\x1b[0m");
592  if (level == Level::Error || level == Level::Fatal)
593  *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor;
594  else if (level == Level::Warning)
595  *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor;
596  else if (level == Level::Debug)
597  *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor;
598  else if (level == Level::Info)
599  *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor;
600  else if (level == Level::Trace)
601  *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor;
602 }
603 
604 // Logger
605 
606 Logger::Logger(const std::string& id, base::LogStreamsReferenceMap* logStreamsReference) :
607  m_id(id),
608  m_typedConfigurations(nullptr),
609  m_parentApplicationName(std::string()),
610  m_isConfigured(false),
611  m_logStreamsReference(logStreamsReference) {
613 }
614 
616  base::LogStreamsReferenceMap* logStreamsReference) :
617  m_id(id),
618  m_typedConfigurations(nullptr),
620  m_isConfigured(false),
621  m_logStreamsReference(logStreamsReference) {
623  configure(configurations);
624 }
625 
626 Logger::Logger(const Logger& logger) {
628  m_id = logger.m_id;
635 }
636 
637 Logger& Logger::operator=(const Logger& logger) {
638  if (&logger != this) {
640  m_id = logger.m_id;
647  }
648  return *this;
649 }
650 
652 #if ELPP_ASYNC_LOGGING
653  if (ELPP) {
654  base::threading::ScopedLock scopedLockConfig(ELPP->configLock());
655  performConfig(configurations);
656  }
657  else
658  performConfig(configurations);
659 #else
660  performConfig(configurations);
661 #endif // ELPP_ASYNC_LOGGING
662 }
663 
665  m_isConfigured = false; // we set it to false in case if we fail
667  if (m_typedConfigurations != nullptr) {
670  flush();
671  }
672  }
673  base::threading::ScopedLock scopedLock(lock());
674  if (m_configurations != configurations) {
675  m_configurations.setFromBase(const_cast<Configurations*>(&configurations));
676  }
680  m_isConfigured = true;
681 }
682 
684  ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]");
686 }
687 
689  for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) {
691  return false;
692  }
693  }
694  return true;
695 }
696 
697 void Logger::flush(void) {
698  ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels");
699  base::threading::ScopedLock scopedLock(lock());
701  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
702  flush(LevelHelper::castFromInt(lIndex), nullptr);
703  return false;
704  });
705 }
706 
708  if (fs == nullptr && m_typedConfigurations->toFile(level)) {
709  fs = m_typedConfigurations->fileStream(level);
710  }
711  if (fs != nullptr) {
712  fs->flush();
713  std::unordered_map<Level, unsigned int>::iterator iter = m_unflushedCount.find(level);
714  if (iter != m_unflushedCount.end()) {
715  iter->second = 0;
716  }
717  Helpers::validateFileRolling(this, level);
718  }
719 }
720 
722  m_unflushedCount.clear();
724  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
725  m_unflushedCount.insert(std::make_pair(LevelHelper::castFromInt(lIndex), 0));
726  return false;
727  });
728 }
729 
732  LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
733  base::LogFormat* logFormat =
736  return false;
737  });
738 }
739 
740 // el::base
741 namespace base {
742 
743 // el::base::utils
744 namespace utils {
745 
746 // File
747 
748 base::type::fstream_t* File::newFileStream(const std::string& filename) {
749  base::type::fstream_t *fs = new base::type::fstream_t(filename.c_str(),
751 #if !defined(ELPP_FRESH_LOG_FILE)
752  | base::type::fstream_t::app
753 #endif
754  );
755 #if defined(ELPP_UNICODE)
756  std::locale elppUnicodeLocale("");
757 # if ELPP_OS_WINDOWS
758  std::locale elppUnicodeLocaleWindows(elppUnicodeLocale, new std::codecvt_utf8_utf16<wchar_t>);
759  elppUnicodeLocale = elppUnicodeLocaleWindows;
760 # endif // ELPP_OS_WINDOWS
761  fs->imbue(elppUnicodeLocale);
762 #endif // defined(ELPP_UNICODE)
763  if (fs->is_open()) {
764  fs->flush();
765  } else {
767  ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true);
768  }
769  return fs;
770 }
771 
772 std::size_t File::getSizeOfFile(base::type::fstream_t* fs) {
773  if (fs == nullptr) {
774  return 0;
775  }
776  // Since the file stream is appended to or truncated, the current
777  // offset is the file size.
778  std::size_t size = static_cast<std::size_t>(fs->tellg());
779  return size;
780 }
781 
782 bool File::pathExists(const char* path, bool considerFile) {
783  if (path == nullptr) {
784  return false;
785  }
786 #if ELPP_OS_UNIX
787  ELPP_UNUSED(considerFile);
788  struct stat st;
789  return (stat(path, &st) == 0);
790 #elif ELPP_OS_WINDOWS
791  DWORD fileType = GetFileAttributesA(path);
792  if (fileType == INVALID_FILE_ATTRIBUTES) {
793  return false;
794  }
795  return considerFile ? true : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true);
796 #endif // ELPP_OS_UNIX
797 }
798 
799 bool File::createPath(const std::string& path) {
800  if (path.empty()) {
801  return false;
802  }
803  if (base::utils::File::pathExists(path.c_str())) {
804  return true;
805  }
806  int status = -1;
807 
808  char* currPath = const_cast<char*>(path.c_str());
809  std::string builtPath = std::string();
810 #if ELPP_OS_UNIX
811  if (path[0] == '/') {
812  builtPath = "/";
813  }
814  currPath = STRTOK(currPath, base::consts::kFilePathSeperator, 0);
815 #elif ELPP_OS_WINDOWS
816  // Use secure functions API
817  char* nextTok_ = nullptr;
818  currPath = STRTOK(currPath, base::consts::kFilePathSeperator, &nextTok_);
819  ELPP_UNUSED(nextTok_);
820 #endif // ELPP_OS_UNIX
821  while (currPath != nullptr) {
822  builtPath.append(currPath);
823  builtPath.append(base::consts::kFilePathSeperator);
824 #if ELPP_OS_UNIX
825  status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS);
826  currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, 0);
827 #elif ELPP_OS_WINDOWS
828  status = _mkdir(builtPath.c_str());
829  currPath = STRTOK(nullptr, base::consts::kFilePathSeperator, &nextTok_);
830 #endif // ELPP_OS_UNIX
831  }
832  if (status == -1) {
833  ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true);
834  return false;
835  }
836  return true;
837 }
838 
839 std::string File::extractPathFromFilename(const std::string& fullPath, const char* separator) {
840  if ((fullPath == "") || (fullPath.find(separator) == std::string::npos)) {
841  return fullPath;
842  }
843  std::size_t lastSlashAt = fullPath.find_last_of(separator);
844  if (lastSlashAt == 0) {
845  return std::string(separator);
846  }
847  return fullPath.substr(0, lastSlashAt + 1);
848 }
849 
850 void File::buildStrippedFilename(const char* filename, char buff[], std::size_t limit) {
851  std::size_t sizeOfFilename = strlen(filename);
852  if (sizeOfFilename >= limit) {
853  filename += (sizeOfFilename - limit);
854  if (filename[0] != '.' && filename[1] != '.') { // prepend if not already
855  filename += 3; // 3 = '..'
856  STRCAT(buff, "..", limit);
857  }
858  }
859  STRCAT(buff, filename, limit);
860 }
861 
862 void File::buildBaseFilename(const std::string& fullPath, char buff[], std::size_t limit, const char* separator) {
863  const char *filename = fullPath.c_str();
864  std::size_t lastSlashAt = fullPath.find_last_of(separator);
865  filename += lastSlashAt ? lastSlashAt+1 : 0;
866  std::size_t sizeOfFilename = strlen(filename);
867  if (sizeOfFilename >= limit) {
868  filename += (sizeOfFilename - limit);
869  if (filename[0] != '.' && filename[1] != '.') { // prepend if not already
870  filename += 3; // 3 = '..'
871  STRCAT(buff, "..", limit);
872  }
873  }
874  STRCAT(buff, filename, limit);
875 }
876 
877 // Str
878 
879 bool Str::wildCardMatch(const char* str, const char* pattern) {
880  while (*pattern) {
881  switch (*pattern) {
882  case '?':
883  if (!*str)
884  return false;
885  ++str;
886  ++pattern;
887  break;
888  case '*':
889  if (wildCardMatch(str, pattern + 1))
890  return true;
891  if (*str && wildCardMatch(str + 1, pattern))
892  return true;
893  return false;
894  default:
895  if (*str++ != *pattern++)
896  return false;
897  break;
898  }
899  }
900  return !*str && !*pattern;
901 }
902 
903 std::string& Str::ltrim(std::string& str) {
904  str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](char c) {
905  return !std::isspace(c);
906  } ));
907  return str;
908 }
909 
910 std::string& Str::rtrim(std::string& str) {
911  str.erase(std::find_if(str.rbegin(), str.rend(), [](char c) {
912  return !std::isspace(c);
913  }).base(), str.end());
914  return str;
915 }
916 
918  return ltrim(rtrim(str));
919 }
920 
922  return (str.length() >= start.length()) && (str.compare(0, start.length(), start) == 0);
923 }
924 
926  return (str.length() >= end.length()) && (str.compare(str.length() - end.length(), end.length(), end) == 0);
927 }
928 
929 std::string& Str::replaceAll(std::string& str, char replaceWhat, char replaceWith) {
930  std::replace(str.begin(), str.end(), replaceWhat, replaceWith);
931  return str;
932 }
933 
934 std::string& Str::replaceAll(std::string& str, const std::string& replaceWhat,
935  const std::string& replaceWith) {
936  if (replaceWhat == replaceWith)
937  return str;
938  std::size_t foundAt = std::string::npos;
939  while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) {
940  str.replace(foundAt, replaceWhat.length(), replaceWith);
941  }
942  return str;
943 }
944 
945 void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
946  const base::type::string_t& replaceWith) {
947  std::size_t foundAt = base::type::string_t::npos;
948  while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) {
949  if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) {
950  str.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
951  ++foundAt;
952  } else {
953  str.replace(foundAt, replaceWhat.length(), replaceWith);
954  return;
955  }
956  }
957 }
958 #if defined(ELPP_UNICODE)
959 void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
960  const std::string& replaceWith) {
961  replaceFirstWithEscape(str, replaceWhat, base::type::string_t(replaceWith.begin(), replaceWith.end()));
962 }
963 #endif // defined(ELPP_UNICODE)
964 
965 std::string& Str::toUpper(std::string& str) {
966  std::transform(str.begin(), str.end(), str.begin(),
967  [](char c) {
968  return static_cast<char>(::toupper(c));
969  });
970  return str;
971 }
972 
973 bool Str::cStringEq(const char* s1, const char* s2) {
974  if (s1 == nullptr && s2 == nullptr) return true;
975  if (s1 == nullptr || s2 == nullptr) return false;
976  return strcmp(s1, s2) == 0;
977 }
978 
979 bool Str::cStringCaseEq(const char* s1, const char* s2) {
980  if (s1 == nullptr && s2 == nullptr) return true;
981  if (s1 == nullptr || s2 == nullptr) return false;
982 
983  // With thanks to cygwin for this code
984  int d = 0;
985 
986  while (true) {
987  const int c1 = toupper(*s1++);
988  const int c2 = toupper(*s2++);
989 
990  if (((d = c1 - c2) != 0) || (c2 == '\0')) {
991  break;
992  }
993  }
994 
995  return d == 0;
996 }
997 
998 bool Str::contains(const char* str, char c) {
999  for (; *str; ++str) {
1000  if (*str == c)
1001  return true;
1002  }
1003  return false;
1004 }
1005 
1006 char* Str::convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded) {
1007  char localBuff[10] = "";
1008  char* p = localBuff + sizeof(localBuff) - 2;
1009  if (n > 0) {
1010  for (; n > 0 && p > localBuff && len > 0; n /= 10, --len)
1011  *--p = static_cast<char>(n % 10 + '0');
1012  } else {
1013  *--p = '0';
1014  --len;
1015  }
1016  if (zeroPadded)
1017  while (p > localBuff && len-- > 0) *--p = static_cast<char>('0');
1018  return addToBuff(p, buf, bufLim);
1019 }
1020 
1021 char* Str::addToBuff(const char* str, char* buf, const char* bufLim) {
1022  while ((buf < bufLim) && ((*buf = *str++) != '\0'))
1023  ++buf;
1024  return buf;
1025 }
1026 
1027 char* Str::clearBuff(char buff[], std::size_t lim) {
1028  STRCPY(buff, "", lim);
1029  ELPP_UNUSED(lim); // For *nix we dont have anything using lim in above STRCPY macro
1030  return buff;
1031 }
1032 
1035 char* Str::wcharPtrToCharPtr(const wchar_t* line) {
1036  std::size_t len_ = wcslen(line) + 1;
1037  char* buff_ = static_cast<char*>(malloc(len_ + 1));
1038 # if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
1039  std::wcstombs(buff_, line, len_);
1040 # elif ELPP_OS_WINDOWS
1041  std::size_t convCount_ = 0;
1042  mbstate_t mbState_;
1043  ::memset(static_cast<void*>(&mbState_), 0, sizeof(mbState_));
1044  wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_);
1045 # endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
1046  return buff_;
1047 }
1048 
1049 // OS
1050 
1051 #if ELPP_OS_WINDOWS
1052 const char* OS::getWindowsEnvironmentVariable(const char* varname) {
1057  const DWORD bufferLen = 50;
1058  static char buffer[bufferLen];
1059  if (GetEnvironmentVariableA(varname, buffer, bufferLen)) {
1060  return buffer;
1061  }
1062  return nullptr;
1063 }
1064 #endif // ELPP_OS_WINDOWS
1065 #if ELPP_OS_ANDROID
1066 std::string OS::getProperty(const char* prop) {
1067  char propVal[PROP_VALUE_MAX + 1];
1068  int ret = __system_property_get(prop, propVal);
1069  return ret == 0 ? std::string() : std::string(propVal);
1070 }
1071 
1072 std::string OS::getDeviceName(void) {
1073  std::stringstream ss;
1074  std::string manufacturer = getProperty("ro.product.manufacturer");
1075  std::string model = getProperty("ro.product.model");
1076  if (manufacturer.empty() || model.empty()) {
1077  return std::string();
1078  }
1079  ss << manufacturer << "-" << model;
1080  return ss.str();
1081 }
1082 #endif // ELPP_OS_ANDROID
1083 
1084 const std::string OS::getBashOutput(const char* command) {
1085 #if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
1086  if (command == nullptr) {
1087  return std::string();
1088  }
1089  FILE* proc = nullptr;
1090  if ((proc = popen(command, "r")) == nullptr) {
1091  ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true);
1092  return std::string();
1093  }
1094  char hBuff[4096];
1095  if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) {
1096  pclose(proc);
1097  const std::size_t buffLen = strlen(hBuff);
1098  if (buffLen > 0 && hBuff[buffLen - 1] == '\n') {
1099  hBuff[buffLen - 1] = '\0';
1100  }
1101  return std::string(hBuff);
1102  } else {
1103  pclose(proc);
1104  }
1105  return std::string();
1106 #else
1107  ELPP_UNUSED(command);
1108  return std::string();
1109 #endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
1110 }
1111 
1112 std::string OS::getEnvironmentVariable(const char* variableName, const char* defaultVal,
1113  const char* alternativeBashCommand) {
1114 #if ELPP_OS_UNIX
1115  const char* val = getenv(variableName);
1116 #elif ELPP_OS_WINDOWS
1117  const char* val = getWindowsEnvironmentVariable(variableName);
1118 #endif // ELPP_OS_UNIX
1119  if ((val == nullptr) || ((strcmp(val, "") == 0))) {
1120 #if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
1121  // Try harder on unix-based systems
1122  std::string valBash = base::utils::OS::getBashOutput(alternativeBashCommand);
1123  if (valBash.empty()) {
1124  return std::string(defaultVal);
1125  } else {
1126  return valBash;
1127  }
1128 #elif ELPP_OS_WINDOWS || ELPP_OS_UNIX
1129  ELPP_UNUSED(alternativeBashCommand);
1130  return std::string(defaultVal);
1131 #endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
1132  }
1133  return std::string(val);
1134 }
1135 
1136 std::string OS::currentUser(void) {
1137 #if ELPP_OS_UNIX && !ELPP_OS_ANDROID
1138  return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami");
1139 #elif ELPP_OS_WINDOWS
1140  return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser);
1141 #elif ELPP_OS_ANDROID
1143  return std::string("android");
1144 #else
1145  return std::string();
1146 #endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
1147 }
1148 
1149 std::string OS::currentHost(void) {
1150 #if ELPP_OS_UNIX && !ELPP_OS_ANDROID
1151  return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost, "hostname");
1152 #elif ELPP_OS_WINDOWS
1153  return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost);
1154 #elif ELPP_OS_ANDROID
1156  return getDeviceName();
1157 #else
1158  return std::string();
1159 #endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
1160 }
1161 
1162 bool OS::termSupportsColor(void) {
1163  std::string term = getEnvironmentVariable("TERM", "");
1164  return term == "xterm" || term == "xterm-color" || term == "xterm-256color"
1165  || term == "screen" || term == "linux" || term == "cygwin"
1166  || term == "screen-256color";
1167 }
1168 
1169 // DateTime
1170 
1171 void DateTime::gettimeofday(struct timeval* tv) {
1172 #if ELPP_OS_WINDOWS
1173  if (tv != nullptr) {
1174 # if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
1175  const unsigned __int64 delta_ = 11644473600000000Ui64;
1176 # else
1177  const unsigned __int64 delta_ = 11644473600000000ULL;
1178 # endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
1179  const double secOffSet = 0.000001;
1180  const unsigned long usecOffSet = 1000000;
1181  FILETIME fileTime;
1182  GetSystemTimeAsFileTime(&fileTime);
1183  unsigned __int64 present = 0;
1184  present |= fileTime.dwHighDateTime;
1185  present = present << 32;
1186  present |= fileTime.dwLowDateTime;
1187  present /= 10; // mic-sec
1188  // Subtract the difference
1189  present -= delta_;
1190  tv->tv_sec = static_cast<long>(present * secOffSet);
1191  tv->tv_usec = static_cast<long>(present % usecOffSet);
1192  }
1193 #else
1194  ::gettimeofday(tv, nullptr);
1195 #endif // ELPP_OS_WINDOWS
1196 }
1197 
1198 std::string DateTime::getDateTime(const char* format, const base::SubsecondPrecision* ssPrec) {
1199  struct timeval currTime;
1200  gettimeofday(&currTime);
1201  return timevalToString(currTime, format, ssPrec);
1202 }
1203 
1204 std::string DateTime::timevalToString(struct timeval tval, const char* format,
1205  const el::base::SubsecondPrecision* ssPrec) {
1206  struct ::tm timeInfo;
1207  buildTimeInfo(&tval, &timeInfo);
1208  const int kBuffSize = 30;
1209  char buff_[kBuffSize] = "";
1210  parseFormat(buff_, kBuffSize, format, &timeInfo, static_cast<std::size_t>(tval.tv_usec / ssPrec->m_offset),
1211  ssPrec);
1212  return std::string(buff_);
1213 }
1214 
1215 base::type::string_t DateTime::formatTime(unsigned long long time, base::TimestampUnit timestampUnit) {
1216  base::type::EnumType start = static_cast<base::type::EnumType>(timestampUnit);
1218  for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1; ++i) {
1219  if (time <= base::consts::kTimeFormats[i].value) {
1220  break;
1221  }
1222  if (base::consts::kTimeFormats[i].value == 1000.0f && time / 1000.0f < 1.9f) {
1223  break;
1224  }
1225  time /= static_cast<decltype(time)>(base::consts::kTimeFormats[i].value);
1226  unit = base::consts::kTimeFormats[i + 1].unit;
1227  }
1229  ss << time << " " << unit;
1230  return ss.str();
1231 }
1232 
1233 unsigned long long DateTime::getTimeDifference(const struct timeval& endTime, const struct timeval& startTime,
1234  base::TimestampUnit timestampUnit) {
1235  if (timestampUnit == base::TimestampUnit::Microsecond) {
1236  return static_cast<unsigned long long>(static_cast<unsigned long long>(1000000 * endTime.tv_sec + endTime.tv_usec) -
1237  static_cast<unsigned long long>(1000000 * startTime.tv_sec + startTime.tv_usec));
1238  }
1239  // milliseconds
1240  auto conv = [](const struct timeval& tim) {
1241  return static_cast<unsigned long long>((tim.tv_sec * 1000) + (tim.tv_usec / 1000));
1242  };
1243  return static_cast<unsigned long long>(conv(endTime) - conv(startTime));
1244 }
1245 
1246 struct ::tm* DateTime::buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo) {
1247 #if ELPP_OS_UNIX
1248  time_t rawTime = currTime->tv_sec;
1249  ::elpptime_r(&rawTime, timeInfo);
1250  return timeInfo;
1251 #else
1252 # if ELPP_COMPILER_MSVC
1253  ELPP_UNUSED(currTime);
1254  time_t t;
1255 # if defined(_USE_32BIT_TIME_T)
1256  _time32(&t);
1257 # else
1258  _time64(&t);
1259 # endif
1260  elpptime_s(timeInfo, &t);
1261  return timeInfo;
1262 # else
1263  // For any other compilers that don't have CRT warnings issue e.g, MinGW or TDM GCC- we use different method
1264  time_t rawTime = currTime->tv_sec;
1265  struct tm* tmInf = elpptime(&rawTime);
1266  *timeInfo = *tmInf;
1267  return timeInfo;
1268 # endif // ELPP_COMPILER_MSVC
1269 #endif // ELPP_OS_UNIX
1270 }
1271 
1272 char* DateTime::parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
1273  std::size_t msec, const base::SubsecondPrecision* ssPrec) {
1274  const char* bufLim = buf + bufSz;
1275  for (; *format; ++format) {
1276  if (*format == base::consts::kFormatSpecifierChar) {
1277  switch (*++format) {
1278  case base::consts::kFormatSpecifierChar: // Escape
1279  break;
1280  case '\0': // End
1281  --format;
1282  break;
1283  case 'd': // Day
1284  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf, bufLim);
1285  continue;
1286  case 'a': // Day of week (short)
1287  buf = base::utils::Str::addToBuff(base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim);
1288  continue;
1289  case 'A': // Day of week (long)
1290  buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday], buf, bufLim);
1291  continue;
1292  case 'M': // month
1293  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf, bufLim);
1294  continue;
1295  case 'b': // month (short)
1296  buf = base::utils::Str::addToBuff(base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim);
1297  continue;
1298  case 'B': // month (long)
1299  buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon], buf, bufLim);
1300  continue;
1301  case 'y': // year (two digits)
1302  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim);
1303  continue;
1304  case 'Y': // year (four digits)
1305  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim);
1306  continue;
1307  case 'h': // hour (12-hour)
1308  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf, bufLim);
1309  continue;
1310  case 'H': // hour (24-hour)
1311  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf, bufLim);
1312  continue;
1313  case 'm': // minute
1314  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf, bufLim);
1315  continue;
1316  case 's': // second
1317  buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf, bufLim);
1318  continue;
1319  case 'z': // subsecond part
1320  case 'g':
1321  buf = base::utils::Str::convertAndAddToBuff(msec, ssPrec->m_width, buf, bufLim);
1322  continue;
1323  case 'F': // AM/PM
1324  buf = base::utils::Str::addToBuff((tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf, bufLim);
1325  continue;
1326  default:
1327  continue;
1328  }
1329  }
1330  if (buf == bufLim) break;
1331  *buf++ = *format;
1332  }
1333  return buf;
1334 }
1335 
1336 // CommandLineArgs
1337 
1338 void CommandLineArgs::setArgs(int argc, char** argv) {
1339  m_params.clear();
1340  m_paramsWithValue.clear();
1341  if (argc == 0 || argv == nullptr) {
1342  return;
1343  }
1344  m_argc = argc;
1345  m_argv = argv;
1346  for (int i = 1; i < m_argc; ++i) {
1347  const char* v = (strstr(m_argv[i], "="));
1348  if (v != nullptr && strlen(v) > 0) {
1349  std::string key = std::string(m_argv[i]);
1350  key = key.substr(0, key.find_first_of('='));
1351  if (hasParamWithValue(key.c_str())) {
1352  ELPP_INTERNAL_INFO(1, "Skipping [" << key << "] arg since it already has value ["
1353  << getParamValue(key.c_str()) << "]");
1354  } else {
1355  m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1)));
1356  }
1357  }
1358  if (v == nullptr) {
1359  if (hasParam(m_argv[i])) {
1360  ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i] << "] arg since it already exists");
1361  } else {
1362  m_params.push_back(std::string(m_argv[i]));
1363  }
1364  }
1365  }
1366 }
1367 
1368 bool CommandLineArgs::hasParamWithValue(const char* paramKey) const {
1369  return m_paramsWithValue.find(std::string(paramKey)) != m_paramsWithValue.end();
1370 }
1371 
1372 const char* CommandLineArgs::getParamValue(const char* paramKey) const {
1373  std::unordered_map<std::string, std::string>::const_iterator iter = m_paramsWithValue.find(std::string(paramKey));
1374  return iter != m_paramsWithValue.end() ? iter->second.c_str() : "";
1375 }
1376 
1377 bool CommandLineArgs::hasParam(const char* paramKey) const {
1378  return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) != m_params.end();
1379 }
1380 
1381 bool CommandLineArgs::empty(void) const {
1382  return m_params.empty() && m_paramsWithValue.empty();
1383 }
1384 
1385 std::size_t CommandLineArgs::size(void) const {
1386  return m_params.size() + m_paramsWithValue.size();
1387 }
1388 
1390  for (int i = 1; i < c.m_argc; ++i) {
1391  os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]");
1392  if (i < c.m_argc - 1) {
1393  os << ELPP_LITERAL(" ");
1394  }
1395  }
1396  return os;
1397 }
1398 
1399 } // namespace utils
1400 
1401 // el::base::threading
1402 namespace threading {
1403 
1404 #if ELPP_THREADING_ENABLED
1405 # if ELPP_USE_STD_THREADING
1406 # if ELPP_ASYNC_LOGGING
1407 static void msleep(int ms) {
1408  // Only when async logging enabled - this is because async is strict on compiler
1409 # if defined(ELPP_NO_SLEEP_FOR)
1410  usleep(ms * 1000);
1411 # else
1412  std::this_thread::sleep_for(std::chrono::milliseconds(ms));
1413 # endif // defined(ELPP_NO_SLEEP_FOR)
1414 }
1415 # endif // ELPP_ASYNC_LOGGING
1416 # endif // !ELPP_USE_STD_THREADING
1417 #endif // ELPP_THREADING_ENABLED
1418 
1419 } // namespace threading
1420 
1421 // el::base
1422 
1423 // SubsecondPrecision
1424 
1426  if (width < 1 || width > 6) {
1428  }
1429  m_width = width;
1430  switch (m_width) {
1431  case 3:
1432  m_offset = 1000;
1433  break;
1434  case 4:
1435  m_offset = 100;
1436  break;
1437  case 5:
1438  m_offset = 10;
1439  break;
1440  case 6:
1441  m_offset = 1;
1442  break;
1443  default:
1444  m_offset = 1000;
1445  break;
1446  }
1447 }
1448 
1449 // LogFormat
1450 
1451 LogFormat::LogFormat(void) :
1452  m_level(Level::Unknown),
1453  m_userFormat(base::type::string_t()),
1454  m_format(base::type::string_t()),
1455  m_dateTimeFormat(std::string()),
1456  m_flags(0x0),
1457  m_currentUser(base::utils::OS::currentUser()),
1458  m_currentHost(base::utils::OS::currentHost()) {
1459 }
1460 
1462  : m_level(level), m_userFormat(format), m_currentUser(base::utils::OS::currentUser()),
1463  m_currentHost(base::utils::OS::currentHost()) {
1465 }
1466 
1468  m_level(logFormat.m_level),
1469  m_userFormat(logFormat.m_userFormat),
1470  m_format(logFormat.m_format),
1472  m_flags(logFormat.m_flags),
1473  m_currentUser(logFormat.m_currentUser),
1474  m_currentHost(logFormat.m_currentHost) {
1475 }
1476 
1478  m_level = std::move(logFormat.m_level);
1479  m_userFormat = std::move(logFormat.m_userFormat);
1480  m_format = std::move(logFormat.m_format);
1481  m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat);
1482  m_flags = std::move(logFormat.m_flags);
1483  m_currentUser = std::move(logFormat.m_currentUser);
1484  m_currentHost = std::move(logFormat.m_currentHost);
1485 }
1486 
1488  if (&logFormat != this) {
1489  m_level = logFormat.m_level;
1490  m_userFormat = logFormat.m_userFormat;
1491  m_dateTimeFormat = logFormat.m_dateTimeFormat;
1492  m_flags = logFormat.m_flags;
1493  m_currentUser = logFormat.m_currentUser;
1494  m_currentHost = logFormat.m_currentHost;
1495  }
1496  return *this;
1497 }
1498 
1499 bool LogFormat::operator==(const LogFormat& other) {
1500  return m_level == other.m_level && m_userFormat == other.m_userFormat && m_format == other.m_format &&
1501  m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags;
1502 }
1503 
1507  // We make copy because we will be changing the format
1508  // i.e, removing user provided date format from original format
1509  // and then storing it.
1510  base::type::string_t formatCopy = userFormat;
1511  m_flags = 0x0;
1512  auto conditionalAddFlag = [&](const base::type::char_t* specifier, base::FormatFlags flag) {
1513  std::size_t foundAt = base::type::string_t::npos;
1514  while ((foundAt = formatCopy.find(specifier, foundAt + 1)) != base::type::string_t::npos) {
1515  if (foundAt > 0 && formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) {
1516  if (hasFlag(flag)) {
1517  // If we already have flag we remove the escape chars so that '%%' is turned to '%'
1518  // even after specifier resolution - this is because we only replaceFirst specifier
1519  formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
1520  ++foundAt;
1521  }
1522  } else {
1523  if (!hasFlag(flag)) addFlag(flag);
1524  }
1525  }
1526  };
1541  // For date/time we need to extract user's date format first
1542  std::size_t dateIndex = std::string::npos;
1543  if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) != std::string::npos) {
1544  while (dateIndex > 0 && formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
1545  dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier, dateIndex + 1);
1546  }
1547  if (dateIndex != std::string::npos) {
1549  updateDateFormat(dateIndex, formatCopy);
1550  }
1551  }
1552  m_format = formatCopy;
1553  updateFormatSpec();
1554 }
1555 
1559  }
1560  const base::type::char_t* ptr = currFormat.c_str() + index;
1561  if ((currFormat.size() > index) && (ptr[0] == '{')) {
1562  // User has provided format for date/time
1563  ++ptr;
1564  int count = 1; // Start by 1 in order to remove starting brace
1565  std::stringstream ss;
1566  for (; *ptr; ++ptr, ++count) {
1567  if (*ptr == '}') {
1568  ++count; // In order to remove ending brace
1569  break;
1570  }
1571  ss << static_cast<char>(*ptr);
1572  }
1573  currFormat.erase(index, count);
1574  m_dateTimeFormat = ss.str();
1575  } else {
1576  // No format provided, use default
1579  }
1580  }
1581 }
1582 
1584  // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
1585  if (m_level == Level::Debug) {
1590  } else if (m_level == Level::Info) {
1595  } else if (m_level == Level::Warning) {
1600  } else if (m_level == Level::Error) {
1605  } else if (m_level == Level::Fatal) {
1610  } else if (m_level == Level::Verbose) {
1615  } else if (m_level == Level::Trace) {
1620  }
1623  m_currentUser);
1624  }
1627  m_currentHost);
1628  }
1629  // Ignore Level::Global and Level::Unknown
1630 }
1631 
1632 // TypedConfigurations
1633 
1635  base::LogStreamsReferenceMap* logStreamsReference) {
1636  m_configurations = configurations;
1637  m_logStreamsReference = logStreamsReference;
1638  build(m_configurations);
1639 }
1640 
1642  this->m_configurations = other.m_configurations;
1643  this->m_logStreamsReference = other.m_logStreamsReference;
1644  build(m_configurations);
1645 }
1646 
1648  return getConfigByVal<bool>(level, &m_enabledMap, "enabled");
1649 }
1650 
1652  return getConfigByVal<bool>(level, &m_toFileMap, "toFile");
1653 }
1654 
1656  return getConfigByRef<std::string>(level, &m_filenameMap, "filename");
1657 }
1658 
1660  return getConfigByVal<bool>(level, &m_toStandardOutputMap, "toStandardOutput");
1661 }
1662 
1664  return getConfigByRef<base::LogFormat>(level, &m_logFormatMap, "logFormat");
1665 }
1666 
1668  return getConfigByRef<base::SubsecondPrecision>(level, &m_subsecondPrecisionMap, "subsecondPrecision");
1669 }
1670 
1672  return getConfigByRef<base::MillisecondsWidth>(level, &m_subsecondPrecisionMap, "millisecondsWidth");
1673 }
1674 
1676  return getConfigByVal<bool>(level, &m_performanceTrackingMap, "performanceTracking");
1677 }
1678 
1680  return getConfigByRef<base::FileStreamPtr>(level, &m_fileStreamMap, "fileStream").get();
1681 }
1682 
1684  return getConfigByVal<std::size_t>(level, &m_maxLogFileSizeMap, "maxLogFileSize");
1685 }
1686 
1688  return getConfigByVal<std::size_t>(level, &m_logFlushThresholdMap, "logFlushThreshold");
1689 }
1690 
1692  base::threading::ScopedLock scopedLock(lock());
1693  auto getBool = [] (std::string boolStr) -> bool { // Pass by value for trimming
1694  base::utils::Str::trim(boolStr);
1695  return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1");
1696  };
1697  std::vector<Configuration*> withFileSizeLimit;
1698  for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) {
1699  Configuration* conf = *it;
1700  // We cannot use switch on strong enums because Intel C++ dont support them yet
1702  setValue(conf->level(), getBool(conf->value()), &m_enabledMap);
1703  } else if (conf->configurationType() == ConfigurationType::ToFile) {
1704  setValue(conf->level(), getBool(conf->value()), &m_toFileMap);
1706  setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap);
1707  } else if (conf->configurationType() == ConfigurationType::Filename) {
1708  // We do not yet configure filename but we will configure in another
1709  // loop. This is because if file cannot be created, we will force ToFile
1710  // to be false. Because configuring logger is not necessarily performance
1711  // sensative operation, we can live with another loop; (by the way this loop
1712  // is not very heavy either)
1713  } else if (conf->configurationType() == ConfigurationType::Format) {
1714  setValue(conf->level(), base::LogFormat(conf->level(),
1715  base::type::string_t(conf->value().begin(), conf->value().end())), &m_logFormatMap);
1717  setValue(Level::Global,
1718  base::SubsecondPrecision(static_cast<int>(getULong(conf->value()))), &m_subsecondPrecisionMap);
1720  setValue(Level::Global, getBool(conf->value()), &m_performanceTrackingMap);
1721  } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) {
1722  auto v = getULong(conf->value());
1723  setValue(conf->level(), static_cast<std::size_t>(v), &m_maxLogFileSizeMap);
1724  if (v != 0) {
1725  withFileSizeLimit.push_back(conf);
1726  }
1728  setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())), &m_logFlushThresholdMap);
1729  }
1730  }
1731  // As mentioned earlier, we will now set filename configuration in separate loop to deal with non-existent files
1732  for (Configurations::const_iterator it = configurations->begin(); it != configurations->end(); ++it) {
1733  Configuration* conf = *it;
1735  insertFile(conf->level(), conf->value());
1736  }
1737  }
1738  for (std::vector<Configuration*>::iterator conf = withFileSizeLimit.begin();
1739  conf != withFileSizeLimit.end(); ++conf) {
1740  // This is not unsafe as mutex is locked in currect scope
1741  unsafeValidateFileRolling((*conf)->level(), base::defaultPreRollOutCallback);
1742  }
1743 }
1744 
1746  bool valid = true;
1747  base::utils::Str::trim(confVal);
1748  valid = !confVal.empty() && std::find_if(confVal.begin(), confVal.end(),
1749  [](char c) {
1750  return !base::utils::Str::isDigit(c);
1751  }) == confVal.end();
1752  if (!valid) {
1753  valid = false;
1754  ELPP_ASSERT(valid, "Configuration value not a valid integer [" << confVal << "]");
1755  return 0;
1756  }
1757  return atol(confVal.c_str());
1758 }
1759 
1761  std::string resultingFilename = filename;
1762  std::size_t dateIndex = std::string::npos;
1764  if ((dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str())) != std::string::npos) {
1765  while (dateIndex > 0 && resultingFilename[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
1766  dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(), dateIndex + 1);
1767  }
1768  if (dateIndex != std::string::npos) {
1769  const char* ptr = resultingFilename.c_str() + dateIndex;
1770  // Goto end of specifier
1771  ptr += dateTimeFormatSpecifierStr.size();
1772  std::string fmt;
1773  if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) {
1774  // User has provided format for date/time
1775  ++ptr;
1776  int count = 1; // Start by 1 in order to remove starting brace
1777  std::stringstream ss;
1778  for (; *ptr; ++ptr, ++count) {
1779  if (*ptr == '}') {
1780  ++count; // In order to remove ending brace
1781  break;
1782  }
1783  ss << *ptr;
1784  }
1785  resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(), count);
1786  fmt = ss.str();
1787  } else {
1789  }
1790  base::SubsecondPrecision ssPrec(3);
1791  std::string now = base::utils::DateTime::getDateTime(fmt.c_str(), &ssPrec);
1792  base::utils::Str::replaceAll(now, '/', '-'); // Replace path element since we are dealing with filename
1793  base::utils::Str::replaceAll(resultingFilename, dateTimeFormatSpecifierStr, now);
1794  }
1795  }
1796  return resultingFilename;
1797 }
1798 
1800  std::string resolvedFilename = resolveFilename(fullFilename);
1801  if (resolvedFilename.empty()) {
1802  std::cerr << "Could not load empty file for logging, please re-check your configurations for level ["
1803  << LevelHelper::convertToString(level) << "]";
1804  }
1806  if (filePath.size() < resolvedFilename.size()) {
1808  }
1809  auto create = [&](Level level) {
1810  base::LogStreamsReferenceMap::iterator filestreamIter = m_logStreamsReference->find(resolvedFilename);
1811  base::type::fstream_t* fs = nullptr;
1812  if (filestreamIter == m_logStreamsReference->end()) {
1813  // We need a completely new stream, nothing to share with
1814  fs = base::utils::File::newFileStream(resolvedFilename);
1815  m_filenameMap.insert(std::make_pair(level, resolvedFilename));
1816  m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs)));
1817  m_logStreamsReference->insert(std::make_pair(resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level))));
1818  } else {
1819  // Woops! we have an existing one, share it!
1820  m_filenameMap.insert(std::make_pair(level, filestreamIter->first));
1821  m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(filestreamIter->second)));
1822  fs = filestreamIter->second.get();
1823  }
1824  if (fs == nullptr) {
1825  // We display bad file error from newFileStream()
1826  ELPP_INTERNAL_ERROR("Setting [TO_FILE] of ["
1827  << LevelHelper::convertToString(level) << "] to FALSE", false);
1828  setValue(level, false, &m_toFileMap);
1829  }
1830  };
1831  // If we dont have file conf for any level, create it for Level::Global first
1832  // otherwise create for specified level
1833  create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global : level);
1834 }
1835 
1837  base::type::fstream_t* fs = unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get();
1838  if (fs == nullptr) {
1839  return true;
1840  }
1841  std::size_t maxLogFileSize = unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize");
1842  std::size_t currFileSize = base::utils::File::getSizeOfFile(fs);
1843  if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) {
1844  std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename");
1845  ELPP_INTERNAL_INFO(1, "Truncating log file [" << fname << "] as a result of configurations for level ["
1846  << LevelHelper::convertToString(level) << "]");
1847  fs->close();
1848  preRollOutCallback(fname.c_str(), currFileSize);
1849  fs->open(fname, std::fstream::out | std::fstream::trunc);
1850  return true;
1851  }
1852  return false;
1853 }
1854 
1855 // RegisteredHitCounters
1856 
1857 bool RegisteredHitCounters::validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
1858  base::threading::ScopedLock scopedLock(lock());
1859  base::HitCounter* counter = get(filename, lineNumber);
1860  if (counter == nullptr) {
1861  registerNew(counter = new base::HitCounter(filename, lineNumber));
1862  }
1863  counter->validateHitCounts(n);
1864  bool result = (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0);
1865  return result;
1866 }
1867 
1870 bool RegisteredHitCounters::validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
1871  base::threading::ScopedLock scopedLock(lock());
1872  base::HitCounter* counter = get(filename, lineNumber);
1873  if (counter == nullptr) {
1874  registerNew(counter = new base::HitCounter(filename, lineNumber));
1875  }
1876  // Do not use validateHitCounts here since we do not want to reset counter here
1877  // Note the >= instead of > because we are incrementing
1878  // after this check
1879  if (counter->hitCounts() >= n)
1880  return true;
1881  counter->increment();
1882  return false;
1883 }
1884 
1887 bool RegisteredHitCounters::validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
1888  base::threading::ScopedLock scopedLock(lock());
1889  base::HitCounter* counter = get(filename, lineNumber);
1890  if (counter == nullptr) {
1891  registerNew(counter = new base::HitCounter(filename, lineNumber));
1892  }
1893  counter->increment();
1894  // Do not use validateHitCounts here since we do not want to reset counter here
1895  if (counter->hitCounts() <= n)
1896  return true;
1897  return false;
1898 }
1899 
1900 // RegisteredLoggers
1901 
1903  m_defaultLogBuilder(defaultLogBuilder) {
1905 }
1906 
1907 Logger* RegisteredLoggers::get(const std::string& id, bool forceCreation) {
1908  base::threading::ScopedLock scopedLock(lock());
1910  if (logger_ == nullptr && forceCreation) {
1911  bool validId = Logger::isValidId(id);
1912  if (!validId) {
1913  ELPP_ASSERT(validId, "Invalid logger ID [" << id << "]. Not registering this logger.");
1914  return nullptr;
1915  }
1917  logger_->m_logBuilder = m_defaultLogBuilder;
1918  registerNew(id, logger_);
1920  for (const std::pair<std::string, base::type::LoggerRegistrationCallbackPtr>& h
1922  callback = h.second.get();
1923  if (callback != nullptr && callback->enabled()) {
1924  callback->handle(logger_);
1925  }
1926  }
1927  }
1928  return logger_;
1929 }
1930 
1932  if (id == base::consts::kDefaultLoggerId) {
1933  return false;
1934  }
1935  // get has internal lock
1937  if (logger != nullptr) {
1938  // unregister has internal lock
1939  unregister(logger);
1940  }
1941  return true;
1942 }
1943 
1945  ELPP_INTERNAL_INFO(1, "Flushing all log files");
1946  for (base::LogStreamsReferenceMap::iterator it = m_logStreamsReference.begin();
1947  it != m_logStreamsReference.end(); ++it) {
1948  if (it->second.get() == nullptr) continue;
1949  it->second->flush();
1950  }
1951 }
1952 
1953 // VRegistry
1954 
1955 VRegistry::VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags) : m_level(level), m_pFlags(pFlags) {
1956 }
1957 
1960  base::threading::ScopedLock scopedLock(lock());
1961  if (level > 9)
1963  else
1964  m_level = level;
1965 }
1966 
1967 void VRegistry::setModules(const char* modules) {
1968  base::threading::ScopedLock scopedLock(lock());
1969  auto addSuffix = [](std::stringstream& ss, const char* sfx, const char* prev) {
1970  if (prev != nullptr && base::utils::Str::endsWith(ss.str(), std::string(prev))) {
1971  std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev)));
1972  ss.str(std::string(""));
1973  ss << chr;
1974  }
1975  if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) {
1976  std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx)));
1977  ss.str(std::string(""));
1978  ss << chr;
1979  }
1980  ss << sfx;
1981  };
1982  auto insert = [&](std::stringstream& ss, base::type::VerboseLevel level) {
1984  addSuffix(ss, ".h", nullptr);
1985  m_modules.insert(std::make_pair(ss.str(), level));
1986  addSuffix(ss, ".c", ".h");
1987  m_modules.insert(std::make_pair(ss.str(), level));
1988  addSuffix(ss, ".cpp", ".c");
1989  m_modules.insert(std::make_pair(ss.str(), level));
1990  addSuffix(ss, ".cc", ".cpp");
1991  m_modules.insert(std::make_pair(ss.str(), level));
1992  addSuffix(ss, ".cxx", ".cc");
1993  m_modules.insert(std::make_pair(ss.str(), level));
1994  addSuffix(ss, ".-inl.h", ".cxx");
1995  m_modules.insert(std::make_pair(ss.str(), level));
1996  addSuffix(ss, ".hxx", ".-inl.h");
1997  m_modules.insert(std::make_pair(ss.str(), level));
1998  addSuffix(ss, ".hpp", ".hxx");
1999  m_modules.insert(std::make_pair(ss.str(), level));
2000  addSuffix(ss, ".hh", ".hpp");
2001  }
2002  m_modules.insert(std::make_pair(ss.str(), level));
2003  };
2004  bool isMod = true;
2005  bool isLevel = false;
2006  std::stringstream ss;
2007  int level = -1;
2008  for (; *modules; ++modules) {
2009  switch (*modules) {
2010  case '=':
2011  isLevel = true;
2012  isMod = false;
2013  break;
2014  case ',':
2015  isLevel = false;
2016  isMod = true;
2017  if (!ss.str().empty() && level != -1) {
2018  insert(ss, static_cast<base::type::VerboseLevel>(level));
2019  ss.str(std::string(""));
2020  level = -1;
2021  }
2022  break;
2023  default:
2024  if (isMod) {
2025  ss << *modules;
2026  } else if (isLevel) {
2027  if (isdigit(*modules)) {
2028  level = static_cast<base::type::VerboseLevel>(*modules) - 48;
2029  }
2030  }
2031  break;
2032  }
2033  }
2034  if (!ss.str().empty() && level != -1) {
2035  insert(ss, static_cast<base::type::VerboseLevel>(level));
2036  }
2037 }
2038 
2039 bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char* file) {
2040  base::threading::ScopedLock scopedLock(lock());
2041  if (m_modules.empty() || file == nullptr) {
2042  return vlevel <= m_level;
2043  } else {
2044  char baseFilename[base::consts::kSourceFilenameMaxLength] = "";
2045  base::utils::File::buildBaseFilename(file, baseFilename);
2046  std::unordered_map<std::string, base::type::VerboseLevel>::iterator it = m_modules.begin();
2047  for (; it != m_modules.end(); ++it) {
2048  if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) {
2049  return vlevel <= it->second;
2050  }
2051  }
2053  return true;
2054  }
2055  return false;
2056  }
2057 }
2058 
2060  if (commandLineArgs->hasParam("-v") || commandLineArgs->hasParam("--verbose") ||
2061  commandLineArgs->hasParam("-V") || commandLineArgs->hasParam("--VERBOSE")) {
2063  } else if (commandLineArgs->hasParamWithValue("--v")) {
2064  setLevel(static_cast<base::type::VerboseLevel>(atoi(commandLineArgs->getParamValue("--v"))));
2065  } else if (commandLineArgs->hasParamWithValue("--V")) {
2066  setLevel(static_cast<base::type::VerboseLevel>(atoi(commandLineArgs->getParamValue("--V"))));
2067  } else if ((commandLineArgs->hasParamWithValue("-vmodule")) && vModulesEnabled()) {
2068  setModules(commandLineArgs->getParamValue("-vmodule"));
2069  } else if (commandLineArgs->hasParamWithValue("-VMODULE") && vModulesEnabled()) {
2070  setModules(commandLineArgs->getParamValue("-VMODULE"));
2071  }
2072 }
2073 
2074 #if !defined(ELPP_DEFAULT_LOGGING_FLAGS)
2075 # define ELPP_DEFAULT_LOGGING_FLAGS 0x0
2076 #endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS)
2077 // Storage
2078 #if ELPP_ASYNC_LOGGING
2079 Storage::Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker) :
2080 #else
2081 Storage::Storage(const LogBuilderPtr& defaultLogBuilder) :
2082 #endif // ELPP_ASYNC_LOGGING
2083  m_registeredHitCounters(new base::RegisteredHitCounters()),
2084  m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)),
2085  m_flags(ELPP_DEFAULT_LOGGING_FLAGS),
2086  m_vRegistry(new base::VRegistry(0, &m_flags)),
2088  m_asyncLogWriteQueue(new base::AsyncLogQueue()),
2089  m_asyncLogReadQueue(new base::AsyncLogQueue()),
2090  m_asyncDispatchWorker(asyncDispatchWorker),
2091 #endif // ELPP_ASYNC_LOGGING
2092  m_preRollOutCallback(base::defaultPreRollOutCallback) {
2093  // Register default logger
2094  m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId));
2095  // We register default logger anyway (worse case it's not going to register) just in case
2096  m_registeredLoggers->get("default");
2097  // Register performance logger and reconfigure format
2098  Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId));
2099  m_registeredLoggers->get("performance");
2100  performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg"));
2101  performanceLogger->reconfigure();
2102 #if defined(ELPP_SYSLOG)
2103  // Register syslog logger and reconfigure format
2104  Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId));
2105  sysLogLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%level: %msg"));
2106  sysLogLogger->reconfigure();
2107 #endif // defined(ELPP_SYSLOG)
2109 #if ELPP_ASYNC_LOGGING
2110  installLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
2111  ELPP_INTERNAL_INFO(1, "ELPP ASYNC logger selected");
2112 #else
2113  installLogDispatchCallback<base::DefaultLogDispatchCallback>(std::string("DefaultLogDispatchCallback"));
2114  ELPP_INTERNAL_INFO(1, "ELPP sync logger selected");
2115 #endif // ELPP_ASYNC_LOGGING
2116 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
2117  installPerformanceTrackingCallback<base::DefaultPerformanceTrackingCallback>
2118  (std::string("DefaultPerformanceTrackingCallback"));
2119 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
2120  ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized");
2121 #if ELPP_ASYNC_LOGGING
2122  m_asyncDispatchWorker->start();
2123 #endif // ELPP_ASYNC_LOGGING
2124 }
2125 
2127  ELPP_INTERNAL_INFO(4, "Destroying storage");
2128 #if ELPP_ASYNC_LOGGING
2129  ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous");
2130  uninstallLogDispatchCallback<base::AsyncLogDispatchCallback>(std::string("AsyncLogDispatchCallback"));
2131  installLogDispatchCallback<base::DefaultLogDispatchCallback>(std::string("DefaultLogDispatchCallback"));
2132  ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker");
2133  base::utils::safeDelete(m_asyncDispatchWorker);
2134  ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueues");
2135  base::utils::safeDelete(m_asyncLogWriteQueue);
2136  base::utils::safeDelete(m_asyncLogReadQueue);
2137 #endif // ELPP_ASYNC_LOGGING
2138  ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters");
2139  base::utils::safeDelete(m_registeredHitCounters);
2140  ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers");
2141  base::utils::safeDelete(m_registeredLoggers);
2142  ELPP_INTERNAL_INFO(5, "Destroying vRegistry");
2143  base::utils::safeDelete(m_vRegistry);
2144 }
2145 
2146 bool Storage::hasCustomFormatSpecifier(const char* formatSpecifier) {
2147  base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
2148  return std::find(m_customFormatSpecifiers.begin(), m_customFormatSpecifiers.end(),
2149  formatSpecifier) != m_customFormatSpecifiers.end();
2150 }
2151 
2153  if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) {
2154  return;
2155  }
2156  base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
2157  m_customFormatSpecifiers.push_back(customFormatSpecifier);
2158 }
2159 
2160 bool Storage::uninstallCustomFormatSpecifier(const char* formatSpecifier) {
2161  base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
2162  std::vector<CustomFormatSpecifier>::iterator it = std::find(m_customFormatSpecifiers.begin(),
2163  m_customFormatSpecifiers.end(), formatSpecifier);
2164  if (it != m_customFormatSpecifiers.end() && strcmp(formatSpecifier, it->formatSpecifier()) == 0) {
2165  m_customFormatSpecifiers.erase(it);
2166  return true;
2167  }
2168  return false;
2169 }
2170 
2171 void Storage::setApplicationArguments(int argc, char** argv) {
2172  m_commandLineArgs.setArgs(argc, argv);
2173  m_vRegistry->setFromArgs(commandLineArgs());
2174  // default log file
2175 #if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
2176  if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) {
2177  Configurations c;
2179  std::string(m_commandLineArgs.getParamValue(base::consts::kDefaultLogFileParam)));
2180  registeredLoggers()->setDefaultConfigurations(c);
2181  for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin();
2182  it != registeredLoggers()->end(); ++it) {
2183  it->second->configure(c);
2184  }
2185  }
2186 #endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
2187 #if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
2188  if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) {
2189  int userInput = atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam));
2190  if (ELPP_DEFAULT_LOGGING_FLAGS == 0x0) {
2191  m_flags = userInput;
2192  } else {
2193  base::utils::addFlag<base::type::EnumType>(userInput, &m_flags);
2194  }
2195  }
2196 #endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
2197 }
2198 
2199 } // namespace base
2200 
2201 // LogDispatchCallback
2203 #if defined(ELPP_THREAD_SAFE)
2204  base::threading::ScopedLock scopedLock(m_fileLocksMapLock);
2206  auto lock = m_fileLocks.find(filename);
2207  if (lock == m_fileLocks.end()) {
2208  m_fileLocks.emplace(std::make_pair(filename, std::unique_ptr<base::threading::Mutex>(new base::threading::Mutex)));
2209  }
2210 #endif
2211 }
2212 
2214  auto it = m_fileLocks.find(data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level()));
2215  return *(it->second.get());
2216 }
2217 
2218 namespace base {
2219 // DefaultLogDispatchCallback
2220 
2222 #if defined(ELPP_THREAD_SAFE)
2224  base::threading::ScopedLock scopedLock(fileHandle(data));
2225 #endif
2226  m_data = data;
2227  dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(),
2228  m_data->dispatchAction() == base::DispatchAction::NormalLog));
2229 }
2230 
2232 #ifdef ANDROID
2233  if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) {
2234  int androidLogPriority = ANDROID_LOG_FATAL;
2235  if (m_data->logMessage()->level() == Level::Fatal)
2236  androidLogPriority = ANDROID_LOG_FATAL;
2237  else if (m_data->logMessage()->level() == Level::Error)
2238  androidLogPriority = ANDROID_LOG_ERROR;
2239  else if (m_data->logMessage()->level() == Level::Warning)
2240  androidLogPriority = ANDROID_LOG_WARN;
2241  else if (m_data->logMessage()->level() == Level::Info)
2242  androidLogPriority = ANDROID_LOG_INFO;
2243  else if (m_data->logMessage()->level() == Level::Debug)
2244  androidLogPriority = ANDROID_LOG_DEBUG;
2245  else
2246  androidLogPriority = ANDROID_LOG_FATAL;
2247 
2248  __android_log_print(androidLogPriority, "librealsense", "%s", logLine.c_str());
2249  }
2250 #endif
2251 
2252  if (m_data->dispatchAction() == base::DispatchAction::NormalLog) {
2253  if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
2254  base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream(
2255  m_data->logMessage()->level());
2256  if (fs != nullptr) {
2257  fs->write(logLine.c_str(), logLine.size());
2258  if (fs->fail()) {
2259  ELPP_INTERNAL_ERROR("Unable to write log to file ["
2260  << m_data->logMessage()->logger()->m_typedConfigurations->filename(m_data->logMessage()->level()) << "].\n"
2261  << "Few possible reasons (could be something else):\n" << " * Permission denied\n"
2262  << " * Disk full\n" << " * Disk is not writable", true);
2263  } else {
2264  if (ELPP->hasFlag(LoggingFlag::ImmediateFlush)
2265  || (m_data->logMessage()->logger()->isFlushNeeded(m_data->logMessage()->level()))) {
2266  m_data->logMessage()->logger()->flush(m_data->logMessage()->level(), fs);
2267  }
2268  }
2269  } else {
2270  ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(m_data->logMessage()->level()) << "] "
2271  << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: "
2272  << m_data->logMessage()->logger()->id() << "]", false);
2273  }
2274  }
2275  if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) {
2277  m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level());
2278  ELPP_COUT << ELPP_COUT_LINE(logLine);
2279  }
2280  }
2281 #if defined(ELPP_SYSLOG)
2282  else if (m_data->dispatchAction() == base::DispatchAction::SysLog) {
2283  // Determine syslog priority
2284  int sysLogPriority = 0;
2285  if (m_data->logMessage()->level() == Level::Fatal)
2286  sysLogPriority = LOG_EMERG;
2287  else if (m_data->logMessage()->level() == Level::Error)
2288  sysLogPriority = LOG_ERR;
2289  else if (m_data->logMessage()->level() == Level::Warning)
2290  sysLogPriority = LOG_WARNING;
2291  else if (m_data->logMessage()->level() == Level::Info)
2292  sysLogPriority = LOG_INFO;
2293  else if (m_data->logMessage()->level() == Level::Debug)
2294  sysLogPriority = LOG_DEBUG;
2295  else
2296  sysLogPriority = LOG_NOTICE;
2297 # if defined(ELPP_UNICODE)
2298  char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
2299  syslog(sysLogPriority, "%s", line);
2300  free(line);
2301 # else
2302  syslog(sysLogPriority, "%s", logLine.c_str());
2303 # endif
2304  }
2305 #endif // defined(ELPP_SYSLOG)
2306 }
2307 
2308 #if ELPP_ASYNC_LOGGING
2309 
2310 // AsyncLogDispatchCallback
2311 
2313  base::type::string_t logLine = data->logMessage()->logger()->logBuilder()->build(data->logMessage(),
2315  // Save resources and only queue if we want to write to file otherwise just ignore handler
2316  auto conf = data->logMessage()->logger()->typedConfigurations();
2317  if (conf->toStandardOutput(data->logMessage()->level()) ||
2318  conf->toFile(data->logMessage()->level())) {
2319  ELPP->asyncLogWriteQueue()->push(AsyncLogItem(*(data->logMessage()), *data, logLine));
2320  }
2321 }
2322 
2323 // AsyncDispatchWorker
2324 AsyncDispatchWorker::AsyncDispatchWorker() {
2325  setContinueRunning(false);
2326 }
2327 
2328 AsyncDispatchWorker::~AsyncDispatchWorker() {
2329  setContinueRunning(false);
2330  ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue");
2331  if (m_asyncWorkerThread.joinable())
2332  m_asyncWorkerThread.join();
2333  else
2334  ELPP_INTERNAL_INFO(6, "logger not joinable");
2335  clean();
2336  ELPP_INTERNAL_INFO(6, "Log queue cleaned");
2337 }
2338 
2339 bool AsyncDispatchWorker::clean(void) {
2340  std::unique_lock<std::mutex> lk(_mtx);
2341  try
2342  {
2343  fetchLogQueue();
2344  emptyQueue();
2345  }
2346  catch(...){}
2347  lk.unlock();
2348  cv.notify_one();
2349  return (ELPP && ELPP->asyncLogWriteQueue() && ELPP->asyncLogWriteQueue()->empty() && ELPP->asyncLogReadQueue() && ELPP->asyncLogReadQueue()->empty());
2350 }
2351 
2352 void AsyncDispatchWorker::emptyQueue(void) {
2353  if (ELPP && ELPP->asyncLogReadQueue()) {
2354  for (auto i=0UL; i < ELPP->asyncLogReadQueue()->size(); i++) {
2355  AsyncLogItem data = ELPP->asyncLogReadQueue()->next();
2356  handle(&data);
2357  }
2358  }
2359 }
2360 
2361 void AsyncDispatchWorker::start(void) {
2362  setContinueRunning(true);
2363  m_asyncWorkerThread = std::thread(&AsyncDispatchWorker::run, this);
2364 }
2365 
2366 void AsyncDispatchWorker::handle(AsyncLogItem* logItem) {
2367  LogDispatchData* data = logItem->data();
2368  LogMessage* logMessage = logItem->logMessage();
2369  Logger* logger = logMessage->logger();
2370  //base::threading::ScopedLock scopedLock(logger->lock());
2372  base::type::string_t logLine = logItem->logLine();
2374  if (conf) {
2375  if (conf->toFile(logMessage->level())) {
2376  base::type::fstream_t* fs = conf->fileStream(logMessage->level());
2377  if (fs != nullptr) {
2378  fs->write(logLine.c_str(), logLine.size());
2379  if (fs->fail()) {
2380  ELPP_INTERNAL_ERROR("Unable to write log to file ["
2381  << conf->filename(logMessage->level()) << "].\n"
2382  << "Few possible reasons (could be something else):\n" << " * Permission denied\n"
2383  << " * Disk full\n" << " * Disk is not writable", true);
2384  }
2385  else {
2386  if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) || (logger->isFlushNeeded(logMessage->level()))) {
2387  logger->flush(logMessage->level(), fs);
2388  }
2389  }
2390 
2391  }
2392  else {
2393  ELPP_INTERNAL_ERROR("Log file for [" << LevelHelper::convertToString(logMessage->level()) << "] "
2394  << "has not been configured but [TO_FILE] is configured to TRUE. [Logger ID: " << logger->id() << "]", false);
2395  }
2396  }
2397  else if (conf->toStandardOutput(logMessage->level())) {
2398  ELPP_COUT << ELPP_COUT_LINE(logLine);
2399  }
2400  }
2401  }
2402 # if defined(ELPP_SYSLOG)
2403  else if (data->dispatchAction() == base::DispatchAction::SysLog) {
2404  // Determine syslog priority
2405  int sysLogPriority = 0;
2406  if (logMessage->level() == Level::Fatal)
2407  sysLogPriority = LOG_EMERG;
2408  else if (logMessage->level() == Level::Error)
2409  sysLogPriority = LOG_ERR;
2410  else if (logMessage->level() == Level::Warning)
2411  sysLogPriority = LOG_WARNING;
2412  else if (logMessage->level() == Level::Info)
2413  sysLogPriority = LOG_INFO;
2414  else if (logMessage->level() == Level::Debug)
2415  sysLogPriority = LOG_DEBUG;
2416  else
2417  sysLogPriority = LOG_NOTICE;
2418 # if defined(ELPP_UNICODE)
2419  char* line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
2420  syslog(sysLogPriority, "%s", line);
2421  free(line);
2422 # else
2423  syslog(sysLogPriority, "%s", logLine.c_str());
2424 # endif
2425  }
2426 # endif // defined(ELPP_SYSLOG)
2427 }
2428 
2429 // This method is used in order to transfer all the logs:
2430 // from the "write queue" - queue in which all the logs are added by the other threads
2431 // to the "read queue" - queue from which the logs are read and dispatched by the async logger's thread
2432 // This double buffer mechanism minimizes the inter-thread locking time, improving log's bandwidth and
2433 // preventing costly stalls due to log flushes to HD.
2434 void AsyncDispatchWorker::fetchLogQueue()
2435 {
2436  if (ELPP && ELPP->asyncLogWriteQueue() && ELPP->asyncLogWriteQueue()->size()) {
2437  base::threading::ScopedLock scopedLockW(ELPP->asyncLogWriteQueue()->lock());
2438  base::threading::ScopedLock scopedLockR(ELPP->asyncLogReadQueue()->lock());
2439  ELPP->asyncLogWriteQueue()->appendTo(ELPP->asyncLogReadQueue());
2440  ELPP->asyncLogWriteQueue()->clear();
2441  }
2442 }
2443 
2444 void AsyncDispatchWorker::run(void) {
2445  while (continueRunning()) {
2446  if (ELPP) {
2447  base::threading::ScopedLock scopedLock(ELPP->configLock());
2448  emptyQueue();
2449  }
2450  std::this_thread::sleep_for(std::chrono::milliseconds(5));
2451  fetchLogQueue();
2452  }
2453 }
2454 #endif // ELPP_ASYNC_LOGGING
2455 
2456 // DefaultLogBuilder
2457 
2458 base::type::string_t DefaultLogBuilder::build(const LogMessage* logMessage, bool appendNewLine) const {
2460  const base::LogFormat* logFormat = &tc->logFormat(logMessage->level());
2461  base::type::string_t logLine = logFormat->format();
2463  const char* bufLim = buff + sizeof(buff);
2464  if (logFormat->hasFlag(base::FormatFlags::AppName)) {
2465  // App name
2467  logMessage->logger()->parentApplicationName());
2468  }
2469  if (logFormat->hasFlag(base::FormatFlags::ThreadId)) {
2470  // Thread ID
2472  ELPP->getThreadName(base::threading::getCurrentThreadId()));
2473  }
2474  if (logFormat->hasFlag(base::FormatFlags::DateTime)) {
2475  // DateTime
2478  &tc->subsecondPrecision(logMessage->level())));
2479  }
2480  if (logFormat->hasFlag(base::FormatFlags::Function)) {
2481  // Function
2483  }
2484  if (logFormat->hasFlag(base::FormatFlags::File)) {
2485  // File
2487  base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
2489  }
2490  if (logFormat->hasFlag(base::FormatFlags::FileBase)) {
2491  // FileBase
2493  base::utils::File::buildBaseFilename(logMessage->file(), buff);
2495  }
2496  if (logFormat->hasFlag(base::FormatFlags::Line)) {
2497  // Line
2501  }
2502  if (logFormat->hasFlag(base::FormatFlags::Location)) {
2503  // Location
2504  char* buf = base::utils::Str::clearBuff(buff,
2506  base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
2507  buf = base::utils::Str::addToBuff(buff, buf, bufLim);
2508  buf = base::utils::Str::addToBuff(":", buf, bufLim);
2510  false);
2512  }
2513  if (logMessage->level() == Level::Verbose && logFormat->hasFlag(base::FormatFlags::VerboseLevel)) {
2514  // Verbose level
2515  char* buf = base::utils::Str::clearBuff(buff, 1);
2516  buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1, buf, bufLim, false);
2518  }
2519  if (logFormat->hasFlag(base::FormatFlags::LogMessage)) {
2520  // Log message
2522  }
2523 #if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
2524  el::base::threading::ScopedLock lock_(ELPP->customFormatSpecifiersLock());
2525  ELPP_UNUSED(lock_);
2526  for (std::vector<CustomFormatSpecifier>::const_iterator it = ELPP->customFormatSpecifiers()->begin();
2527  it != ELPP->customFormatSpecifiers()->end(); ++it) {
2528  std::string fs(it->formatSpecifier());
2529  base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end());
2530  base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier, it->resolver()(logMessage));
2531  }
2532 #endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
2533  if (appendNewLine) logLine += ELPP_LITERAL("\n");
2534  return logLine;
2535 }
2536 
2537 // LogDispatcher
2538 
2540  if (m_proceed && m_dispatchAction == base::DispatchAction::None) {
2541  m_proceed = false;
2542  }
2543  if (!m_proceed) {
2544  return;
2545  }
2546 #ifndef ELPP_NO_GLOBAL_LOCK
2547  // see https://github.com/muflihun/easyloggingpp/issues/580
2548  // global lock is turned off by default unless
2549  // ELPP_NO_GLOBAL_LOCK is defined
2550  base::threading::ScopedLock scopedLock(ELPP->lock());
2551 #endif
2552  base::TypedConfigurations* tc = m_logMessage->logger()->m_typedConfigurations;
2553  if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) {
2554  tc->validateFileRolling(m_logMessage->level(), ELPP->preRollOutCallback());
2555  }
2556  LogDispatchCallback* callback = nullptr;
2558  for (const std::pair<std::string, base::type::LogDispatchCallbackPtr>& h
2559  : ELPP->m_logDispatchCallbacks) {
2560  callback = h.second.get();
2561  if (callback != nullptr && callback->enabled()) {
2562  data.setLogMessage(m_logMessage);
2563  data.setDispatchAction(m_dispatchAction);
2564  callback->handle(&data);
2565  }
2566  }
2567 }
2568 
2569 // MessageBuilder
2570 
2572  m_logger = logger;
2573  m_containerLogSeperator = ELPP->hasFlag(LoggingFlag::NewLineForContainer) ?
2574  ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");
2575 }
2576 
2578  if (msg == nullptr) {
2579  m_logger->stream() << base::consts::kNullPointer;
2580  return *this;
2581  }
2582 # if defined(ELPP_UNICODE)
2583  m_logger->stream() << msg;
2584 # else
2585  char* buff_ = base::utils::Str::wcharPtrToCharPtr(msg);
2586  m_logger->stream() << buff_;
2587  free(buff_);
2588 # endif
2589  if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
2590  m_logger->stream() << " ";
2591  }
2592  return *this;
2593 }
2594 
2595 // Writer
2596 
2597 Writer& Writer::construct(Logger* logger, bool needLock) {
2598  if (!ELPP) return *this;
2599  m_logger = logger;
2600  initializeLogger(logger->id(), false, needLock);
2601  m_messageBuilder.initialize(m_logger);
2602  return *this;
2603 }
2604 
2605 Writer& Writer::construct(int count, const char* loggerIds, ...) {
2606  if (!ELPP) return *this;
2607  if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
2608  va_list loggersList;
2609  va_start(loggersList, loggerIds);
2610  const char* id = loggerIds;
2611  m_loggerIds.reserve(count);
2612  for (int i = 0; i < count; ++i) {
2613  m_loggerIds.push_back(std::string(id));
2614  id = va_arg(loggersList, const char*);
2615  }
2616  va_end(loggersList);
2617  initializeLogger(m_loggerIds.at(0));
2618  } else {
2619  initializeLogger(std::string(loggerIds));
2620  }
2621  m_messageBuilder.initialize(m_logger);
2622  return *this;
2623 }
2624 
2625 void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) {
2626  if (lookup) {
2627  m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
2628  }
2629  if (m_logger == nullptr) {
2630  {
2631  if (!ELPP->registeredLoggers()->has(std::string(base::consts::kDefaultLoggerId))) {
2632  // Somehow default logger has been unregistered. Not good! Register again
2633  ELPP->registeredLoggers()->get(std::string(base::consts::kDefaultLoggerId));
2634  }
2635  }
2636  Writer(Level::Debug, m_file, m_line, m_func).construct(1, base::consts::kDefaultLoggerId)
2637  << "Logger [" << loggerId << "] is not registered yet!";
2638  m_proceed = false;
2639  } else {
2640  if (needLock) {
2641  m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because
2642  // m_proceed can be changed by lines below
2643  }
2644  if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) {
2645  m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) :
2647  } else {
2648  m_proceed = m_logger->enabled(m_level);
2649  }
2650  }
2651 }
2652 
2654  if (!ELPP) return;
2655 #if ELPP_LOGGING_ENABLED
2656  if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
2657  bool firstDispatched = false;
2658  base::type::string_t logMessage;
2659  std::size_t i = 0;
2660  do {
2661  if (m_proceed) {
2662  if (firstDispatched) {
2663  m_logger->stream() << logMessage;
2664  } else {
2665  firstDispatched = true;
2666  if (m_loggerIds.size() > 1) {
2667  logMessage = m_logger->stream().str();
2668  }
2669  }
2670  triggerDispatch();
2671  } else if (m_logger != nullptr) {
2672  m_logger->stream().str(ELPP_LITERAL(""));
2673  m_logger->releaseLock();
2674  }
2675  if (i + 1 < m_loggerIds.size()) {
2676  initializeLogger(m_loggerIds.at(i + 1));
2677  }
2678  } while (++i < m_loggerIds.size());
2679  } else {
2680  if (m_proceed) {
2681  triggerDispatch();
2682  } else if (m_logger != nullptr) {
2683  m_logger->stream().str(ELPP_LITERAL(""));
2684  m_logger->releaseLock();
2685  }
2686  }
2687 #else
2688  if (m_logger != nullptr) {
2689  m_logger->stream().str(ELPP_LITERAL(""));
2690  m_logger->releaseLock();
2691  }
2692 #endif // ELPP_LOGGING_ENABLED
2693 }
2694 
2696  if (m_proceed) {
2697  if (m_msg == nullptr) {
2698  LogMessage msg(m_level, m_file, m_line, m_func, m_verboseLevel,
2699  m_logger);
2700  base::LogDispatcher(m_proceed, &msg, m_dispatchAction).dispatch();
2701  } else {
2702  base::LogDispatcher(m_proceed, m_msg, m_dispatchAction).dispatch();
2703  }
2704  }
2705  if (m_logger != nullptr) {
2706  m_logger->stream().str(ELPP_LITERAL(""));
2707  m_logger->releaseLock();
2708  }
2709  if (m_proceed && m_level == Level::Fatal
2712  << "Aborting application. Reason: Fatal log at [" << m_file << ":" << m_line << "]";
2713  std::stringstream reasonStream;
2714  reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
2715  << " If you wish to disable 'abort on fatal log' please use "
2716  << "el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnFatalLog)";
2717  base::utils::abort(1, reasonStream.str());
2718  }
2719  m_proceed = false;
2720 }
2721 
2722 // PErrorWriter
2723 
2725  if (m_proceed) {
2726 #if ELPP_COMPILER_MSVC
2727  char buff[256];
2728  strerror_s(buff, 256, errno);
2729  m_logger->stream() << ": " << buff << " [" << errno << "]";
2730 #else
2731  m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]";
2732 #endif
2733  }
2734 }
2735 
2736 // PerformanceTracker
2737 
2738 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
2739 
2740 PerformanceTracker::PerformanceTracker(const std::string& blockName,
2741  base::TimestampUnit timestampUnit,
2742  const std::string& loggerId,
2743  bool scopedLog, Level level) :
2744  m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog),
2745  m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) {
2746 #if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
2747  // We store it locally so that if user happen to change configuration by the end of scope
2748  // or before calling checkpoint, we still depend on state of configuraton at time of construction
2749  el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
2750  m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level);
2751  if (m_enabled) {
2753  }
2754 #endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
2755 }
2756 
2757 PerformanceTracker::~PerformanceTracker(void) {
2758 #if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
2759  if (m_enabled) {
2760  base::threading::ScopedLock scopedLock(lock());
2761  if (m_scopedLog) {
2763  base::type::string_t formattedTime = getFormattedTimeTaken();
2764  PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
2765  data.init(this);
2766  data.m_formattedTimeTaken = formattedTime;
2768  for (const std::pair<std::string, base::type::PerformanceTrackingCallbackPtr>& h
2769  : ELPP->m_performanceTrackingCallbacks) {
2770  callback = h.second.get();
2771  if (callback != nullptr && callback->enabled()) {
2772  callback->handle(&data);
2773  }
2774  }
2775  }
2776  }
2777 #endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
2778 }
2779 
2780 void PerformanceTracker::checkpoint(const std::string& id, const char* file, base::type::LineNumber line,
2781  const char* func) {
2782 #if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
2783  if (m_enabled) {
2784  base::threading::ScopedLock scopedLock(lock());
2786  base::type::string_t formattedTime = m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime) : ELPP_LITERAL("");
2787  PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint);
2788  data.init(this);
2789  data.m_checkpointId = id;
2790  data.m_file = file;
2791  data.m_line = line;
2792  data.m_func = func;
2793  data.m_formattedTimeTaken = formattedTime;
2795  for (const std::pair<std::string, base::type::PerformanceTrackingCallbackPtr>& h
2796  : ELPP->m_performanceTrackingCallbacks) {
2797  callback = h.second.get();
2798  if (callback != nullptr && callback->enabled()) {
2799  callback->handle(&data);
2800  }
2801  }
2802  base::utils::DateTime::gettimeofday(&m_lastCheckpointTime);
2803  m_hasChecked = true;
2804  m_lastCheckpointId = id;
2805  }
2806 #endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
2807  ELPP_UNUSED(id);
2808  ELPP_UNUSED(file);
2809  ELPP_UNUSED(line);
2810  ELPP_UNUSED(func);
2811 }
2812 
2813 const base::type::string_t PerformanceTracker::getFormattedTimeTaken(struct timeval startTime) const {
2814  if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) {
2817  startTime, m_timestampUnit) << " " << base::consts::kTimeFormats[static_cast<base::type::EnumType>
2818  (m_timestampUnit)].unit;
2819  return ss.str();
2820  }
2822  startTime, m_timestampUnit), m_timestampUnit);
2823 }
2824 
2825 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
2826 
2827 namespace debug {
2828 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
2829 
2830 // StackTrace
2831 
2832 StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang,
2833  const std::string& hex,
2834  const std::string& addr) :
2835  m_index(index),
2836  m_location(loc),
2837  m_demangled(demang),
2838  m_hex(hex),
2839  m_addr(addr) {
2840 }
2841 
2842 std::ostream& operator<<(std::ostream& ss, const StackTrace::StackTraceEntry& si) {
2843  ss << "[" << si.m_index << "] " << si.m_location << (si.m_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr <<
2844  (si.m_demangled.empty() ? "" : ":") << si.m_demangled;
2845  return ss;
2846 }
2847 
2848 std::ostream& operator<<(std::ostream& os, const StackTrace& st) {
2849  std::vector<StackTrace::StackTraceEntry>::const_iterator it = st.m_stack.begin();
2850  while (it != st.m_stack.end()) {
2851  os << " " << *it++ << "\n";
2852  }
2853  return os;
2854 }
2855 
2856 void StackTrace::generateNew(void) {
2857 #if ELPP_STACKTRACE
2858  m_stack.clear();
2859  void* stack[kMaxStack];
2860  unsigned int size = backtrace(stack, kMaxStack);
2861  char** strings = backtrace_symbols(stack, size);
2862  if (size > kStackStart) { // Skip StackTrace c'tor and generateNew
2863  for (std::size_t i = kStackStart; i < size; ++i) {
2864  std::string mangName;
2866  std::string hex;
2867  std::string addr;
2868 
2869  // entry: 2 crash.cpp.bin 0x0000000101552be5 _ZN2el4base5debug10StackTraceC1Ev + 21
2870  const std::string line(strings[i]);
2871  auto p = line.find("_");
2872  if (p != std::string::npos) {
2873  mangName = line.substr(p);
2874  mangName = mangName.substr(0, mangName.find(" +"));
2875  }
2876  p = line.find("0x");
2877  if (p != std::string::npos) {
2878  addr = line.substr(p);
2879  addr = addr.substr(0, addr.find("_"));
2880  }
2881  // Perform demangling if parsed properly
2882  if (!mangName.empty()) {
2883  int status = 0;
2884  char* demangName = abi::__cxa_demangle(mangName.data(), 0, 0, &status);
2885  // if demangling is successful, output the demangled function name
2886  if (status == 0) {
2887  // Success (see http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
2888  StackTraceEntry entry(i - 1, location, demangName, hex, addr);
2889  m_stack.push_back(entry);
2890  } else {
2891  // Not successful - we will use mangled name
2892  StackTraceEntry entry(i - 1, location, mangName, hex, addr);
2893  m_stack.push_back(entry);
2894  }
2895  free(demangName);
2896  } else {
2897  StackTraceEntry entry(i - 1, line);
2898  m_stack.push_back(entry);
2899  }
2900  }
2901  }
2902  free(strings);
2903 #else
2904  ELPP_INTERNAL_INFO(1, "Stacktrace generation not supported for selected compiler");
2905 #endif // ELPP_STACKTRACE
2906 }
2907 
2908 // Static helper functions
2909 
2910 static std::string crashReason(int sig) {
2911  std::stringstream ss;
2912  bool foundReason = false;
2913  for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) {
2914  if (base::consts::kCrashSignals[i].numb == sig) {
2915  ss << "Application has crashed due to [" << base::consts::kCrashSignals[i].name << "] signal";
2917  ss << std::endl <<
2918  " " << base::consts::kCrashSignals[i].brief << std::endl <<
2919  " " << base::consts::kCrashSignals[i].detail;
2920  }
2921  foundReason = true;
2922  }
2923  }
2924  if (!foundReason) {
2925  ss << "Application has crashed due to unknown signal [" << sig << "]";
2926  }
2927  return ss.str();
2928 }
2930 static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) {
2931  if (sig == SIGINT && ELPP->hasFlag(el::LoggingFlag::IgnoreSigInt)) {
2932  return;
2933  }
2934  std::stringstream ss;
2935  ss << "CRASH HANDLED; ";
2936  ss << crashReason(sig);
2937 #if ELPP_STACKTRACE
2938  if (stackTraceIfAvailable) {
2939  ss << std::endl << " ======= Backtrace: =========" << std::endl << base::debug::StackTrace();
2940  }
2941 #else
2942  ELPP_UNUSED(stackTraceIfAvailable);
2943 #endif // ELPP_STACKTRACE
2945 }
2946 
2947 static inline void crashAbort(int sig) {
2949 }
2950 
2954 static inline void defaultCrashHandler(int sig) {
2955  base::debug::logCrashReason(sig, true, Level::Fatal, base::consts::kDefaultLoggerId);
2956  base::debug::crashAbort(sig);
2957 }
2958 
2959 // CrashHandler
2960 
2961 CrashHandler::CrashHandler(bool useDefault) {
2962  if (useDefault) {
2963  setHandler(defaultCrashHandler);
2964  }
2965 }
2966 
2967 void CrashHandler::setHandler(const Handler& cHandler) {
2968  m_handler = cHandler;
2969 #if defined(ELPP_HANDLE_SIGABRT)
2970  int i = 0; // SIGABRT is at base::consts::kCrashSignals[0]
2971 #else
2972  int i = 1;
2973 #endif // defined(ELPP_HANDLE_SIGABRT)
2974  for (; i < base::consts::kCrashSignalsCount; ++i) {
2975  m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler);
2976  }
2977 }
2978 
2979 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
2980 } // namespace debug
2981 } // namespace base
2982 
2983 // el
2984 
2985 // Helpers
2986 
2987 #if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
2988 
2989 void Helpers::crashAbort(int sig, const char* sourceFile, unsigned int long line) {
2990  std::stringstream ss;
2991  ss << base::debug::crashReason(sig).c_str();
2992  ss << " - [Called el::Helpers::crashAbort(" << sig << ")]";
2993  if (sourceFile != nullptr && strlen(sourceFile) > 0) {
2994  ss << " - Source: " << sourceFile;
2995  if (line > 0)
2996  ss << ":" << line;
2997  else
2998  ss << " (line number not specified)";
2999  }
3000  base::utils::abort(sig, ss.str());
3001 }
3002 
3003 void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level, const char* logger) {
3004  el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger);
3005 }
3006 
3007 #endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
3008 
3009 // Loggers
3010 
3011 Logger* Loggers::getLogger(const std::string& identity, bool registerIfNotAvailable) {
3012  return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable);
3013 }
3014 
3016  ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr);
3017 }
3018 
3020  return ELPP->registeredLoggers()->remove(identity);
3021 }
3022 
3023 bool Loggers::hasLogger(const std::string& identity) {
3024  return ELPP->registeredLoggers()->has(identity);
3025 }
3026 
3028  if (!logger) return nullptr;
3029  logger->configure(configurations);
3030  return logger;
3031 }
3032 
3034  return Loggers::reconfigureLogger(Loggers::getLogger(identity), configurations);
3035 }
3036 
3038  const std::string& value) {
3039  Logger* logger = Loggers::getLogger(identity);
3040  if (logger == nullptr) {
3041  return nullptr;
3042  }
3043  logger->configurations()->set(Level::Global, configurationType, value);
3044  logger->reconfigure();
3045  return logger;
3046 }
3047 
3049  for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin();
3050  it != ELPP->registeredLoggers()->end(); ++it) {
3051  Loggers::reconfigureLogger(it->second, configurations);
3052  }
3053 }
3054 
3056  const std::string& value) {
3057  for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->begin();
3058  it != ELPP->registeredLoggers()->end(); ++it) {
3059  Logger* logger = it->second;
3060  logger->configurations()->set(level, configurationType, value);
3061  logger->reconfigure();
3062  }
3063 }
3064 
3065 void Loggers::setDefaultConfigurations(const Configurations& configurations, bool reconfigureExistingLoggers) {
3066  ELPP->registeredLoggers()->setDefaultConfigurations(configurations);
3067  if (reconfigureExistingLoggers) {
3068  Loggers::reconfigureAllLoggers(configurations);
3069  }
3070 }
3071 
3073  return ELPP->registeredLoggers()->defaultConfigurations();
3074 }
3075 
3077  return ELPP->registeredLoggers()->logStreamsReference();
3078 }
3079 
3082  ELPP->registeredLoggers()->defaultConfigurations(),
3083  ELPP->registeredLoggers()->logStreamsReference());
3084 }
3085 
3086 std::vector<std::string>* Loggers::populateAllLoggerIds(std::vector<std::string>* targetList) {
3087  targetList->clear();
3088  for (base::RegisteredLoggers::iterator it = ELPP->registeredLoggers()->list().begin();
3089  it != ELPP->registeredLoggers()->list().end(); ++it) {
3090  targetList->push_back(it->first);
3091  }
3092  return targetList;
3093 }
3094 
3095 void Loggers::configureFromGlobal(const char* globalConfigurationFilePath) {
3096  std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in);
3097  ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file [" << globalConfigurationFilePath
3098  << "] for parsing.");
3099  std::string line = std::string();
3100  std::stringstream ss;
3101  Logger* logger = nullptr;
3102  auto configure = [&](void) {
3103  ELPP_INTERNAL_INFO(8, "Configuring logger: '" << logger->id() << "' with configurations \n" << ss.str()
3104  << "\n--------------");
3105  Configurations c;
3106  c.parseFromText(ss.str());
3107  logger->configure(c);
3108  };
3109  while (gcfStream.good()) {
3110  std::getline(gcfStream, line);
3111  ELPP_INTERNAL_INFO(1, "Parsing line: " << line);
3112  base::utils::Str::trim(line);
3113  if (Configurations::Parser::isComment(line)) continue;
3115  base::utils::Str::trim(line);
3117  if (!ss.str().empty() && logger != nullptr) {
3118  configure();
3119  }
3120  ss.str(std::string(""));
3121  line = line.substr(2);
3122  base::utils::Str::trim(line);
3123  if (line.size() > 1) {
3124  ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'");
3125  logger = getLogger(line);
3126  }
3127  } else {
3128  ss << line << "\n";
3129  }
3130  }
3131  if (!ss.str().empty() && logger != nullptr) {
3132  configure();
3133  }
3134 }
3135 
3136 bool Loggers::configureFromArg(const char* argKey) {
3137 #if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
3138  ELPP_UNUSED(argKey);
3139 #else
3140  if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) {
3141  return false;
3142  }
3143  configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey));
3144 #endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
3145  return true;
3146 }
3147 
3148 void Loggers::flushAll(void) {
3149 #if ELPP_ASYNC_LOGGING
3150  ELPP->asyncDispatchWorker()->clean();
3151 #endif
3152  ELPP->registeredLoggers()->flushAll();
3153 }
3154 
3156  ELPP->vRegistry()->setLevel(level);
3157 }
3158 
3160  return ELPP->vRegistry()->level();
3161 }
3162 
3163 void Loggers::setVModules(const char* modules) {
3164  if (ELPP->vRegistry()->vModulesEnabled()) {
3165  ELPP->vRegistry()->setModules(modules);
3166  }
3167 }
3168 
3170  ELPP->vRegistry()->clearModules();
3171 }
3172 
3173 // VersionInfo
3174 
3176  return std::string("9.96.5");
3177 }
3180  return std::string("07-09-2018 0950hrs");
3181 }
3182 
3183 } // namespace el
void convertToColoredOutput(base::type::string_t *logLine, Level level)
static void buildBaseFilename(const std::string &fullPath, char buff[], std::size_t limit=base::consts::kSourceFilenameMaxLength, const char *seperator=base::consts::kFilePathSeperator)
builds base filename and puts it in buff
virtual ~Storage(void)
static const textual_icon lock
Definition: model-views.h:218
const base::type::string_t & message(void) const
static const base::type::EnumType kMinValid
Represents minimum valid level. Useful when iterating through enum.
#define STRTOK(a, b, c)
std::shared_ptr< base::type::fstream_t > FileStreamPtr
Specifies precision of the subsecond part. It should be within range (1-6).
const std::string & configurationFile(void) const
Gets configuration file used in parsing this configurations.
static bool hasLogger(const std::string &identity)
Whether or not logger with id is registered.
GLint level
bool validateNTimes(const char *filename, base::type::LineNumber lineNumber, std::size_t n)
Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original ...
void flush(void)
Flushes logger to sync all log files for all levels.
void setModules(const char *modules)
const std::string & value(void) const
Gets string based configuration value.
void addFlag(base::FormatFlags flag)
GLuint GLuint end
static const char * kDefaultDateTimeFormat
bool validateEveryN(const char *filename, base::type::LineNumber lineNumber, std::size_t n)
Validates counter for every N, i.e, registers new if does not exist otherwise updates original one...
Determines whether or not corresponding level and logger of logging is enabled You may disable all lo...
Mutex wrapper used when multi-threading is disabled.
const base::LogFormat & logFormat(Level level)
std::fstream fstream_t
static Logger * reconfigureLogger(Logger *logger, const Configurations &configurations)
Reconfigures specified logger with new configurations.
Configuration(const Configuration &c)
virtual base::type::string_t build(const LogMessage *logMessage, bool appendNewLine) const =0
typedef void(APIENTRY *GLDEBUGPROC)(GLenum source
Determines whether or not performance tracking is enabled.
static const char * convertToString(ConfigurationType configurationType)
Converts configuration type to associated const char*.
bool hasParamWithValue(const char *paramKey) const
Returns true if arguments contain paramKey with a value (seperated by &#39;=&#39;)
Creates logger automatically when not available.
static std::vector< std::string > * populateAllLoggerIds(std::vector< std::string > *targetList)
Populates all logger IDs in current repository.
unsigned long getULong(std::string confVal)
static const char * kFilePathSeperator
bool hasParam(const char *paramKey) const
Return true if arguments has a param (not having a value) i,e without &#39;=&#39;.
GLenum const void * addr
Definition: glext.h:8864
const std::string & filename(Level level)
static std::string extractPathFromFilename(const std::string &fullPath, const char *seperator=base::consts::kFilePathSeperator)
Extracts path of filename with leading slash.
Information representing errors in application but application will keep running. ...
base::threading::Mutex & fileHandle(const LogDispatchData *data)
void dispatch(base::type::string_t &&logLine)
const std::unordered_map< std::string, base::type::VerboseLevel > & modules(void) const
Represents log format containing flags and date format. This is used internally to start initial log...
virtual void handle(const LogDispatchData *data)
T_Ptr * get(const T_Key &uniqKey)
Gets pointer from repository. If none found, nullptr is returned.
bool m_isConfigured
static const base::type::char_t * kCurrentUserFormatSpecifier
GLfloat GLfloat p
Definition: glext.h:12687
static const char * kValidLoggerIdSymbols
static const base::type::EnumType kMaxValid
Represents maximum valid configuration type. This is used internally and you should not need it...
static void setDefaultLogBuilder(el::LogBuilderPtr &logBuilderPtr)
Changes default log builder for future loggers.
static const base::type::char_t * kFatalLevelShortLogValue
static base::type::EnumType castToInt(Level level)
Casts level to int, useful for iterating through enum.
std::ostream ostream_t
#define LOG_WARNING(...)
Definition: src/types.h:241
std::size_t hitCounts(void) const
bool allowed(base::type::VerboseLevel vlevel, const char *file)
GLuint64 GLenum void * handle
Definition: glext.h:7785
static bool pathExists(const char *path, bool considerFile=false)
Determines whether or not provided path exist in current file system.
static const base::type::char_t * kTraceLevelLogValue
GLint location
#define elpptime
static const base::type::char_t * kAppNameFormatSpecifier
GLsizei const GLchar *const * path
Definition: glext.h:4276
void build(Configurations *configurations)
GLfloat value
static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit)
Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc...
#define ELPP
LogFormat & operator=(const LogFormat &logFormat)
Predicate(Level level, ConfigurationType configurationType)
Used to find configuration from configuration (pointers) repository. Avoid using it.
static char * convertAndAddToBuff(std::size_t n, int len, char *buf, const char *bufLim, bool zeroPadded=true)
static bool createPath(const std::string &path)
Creates specified path on file system.
static void setVerboseLevel(base::type::VerboseLevel level)
Sets verbose level on the fly.
Informational events most useful for developers to debug application.
base::type::VerboseLevel m_level
bool userInput(void)
void set(Level level, ConfigurationType configurationType, const std::string &value)
Sets value of configuration for specified level.
const base::MillisecondsWidth & millisecondsWidth(Level level=Level::Global)
Represents unknown configuration.
Severe error information that will presumably abort application.
Main entry point of each logging.
static const char * kMonthsAbbrev[12]
ConfigurationType m_configurationType
static Level castFromInt(base::type::EnumType l)
Casts int(ushort) to level, useful for iterating through enum.
bool parseFromFile(const std::string &configurationFile, Configurations *base=nullptr)
Parses configuration from file.
void insertFile(Level level, const std::string &fullFilename)
ConfigurationType m_configurationType
static void setDefaultConfigurations(const Configurations &configurations, bool reconfigureExistingLoggers=false)
Sets default configurations. This configuration is used for future (and conditionally for existing) l...
void setGlobally(ConfigurationType configurationType, const std::string &value)
Sets configuration for all levels.
base::type::fstream_t * fileStream(Level level)
bool remove(const std::string &id)
Easylogging++ entry namespace.
virtual void updateFormatSpec(void) ELPP_FINAL
Updates level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level.
Makes sure we have new line for each container log entry.
static const base::type::char_t * kTraceLevelShortLogValue
unsigned long int LineNumber
GLsizei const GLchar *const * string
static std::string getCurrentThreadId(void)
bool hasFlag(base::FormatFlags flag) const
base::DispatchAction dispatchAction(void) const
d
Definition: rmse.py:171
#define elpptime_s
const char * formatSpecifier(void) const
static const char * kNullPointer
static bool isComment(const std::string &line)
const struct el::base::consts::@14 kCrashSignals[]
#define ELPP_INTERNAL_INFO(lvl, msg)
GLuint entry
Definition: glext.h:10991
static char * clearBuff(char buff[], std::size_t lim)
static const char * convertToString(Level level)
Converts level to associated const char*.
static const char * kDefaultLogFile
virtual iterator end(void) ELPP_FINAL
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:1960
Represents unknown level.
const base::type::string_t & format(void) const
base::type::string_t m_format
GLdouble n
Definition: glext.h:1966
GLint limit
Definition: glext.h:9964
static const base::type::char_t * kInfoLevelLogValue
bool toStandardOutput(Level level)
GLenum GLfloat * buffer
Level
Represents enumeration for severity level used to determine level of logging.
static char * wcharPtrToCharPtr(const wchar_t *line)
Converst wchar* to char* NOTE: Need to free return value after use!
static const base::type::char_t * kVerboseLevelShortLogValue
static char * addToBuff(const char *str, char *buf, const char *bufLim)
static const base::type::char_t * kVerboseLevelLogValue
bool uninstallCustomFormatSpecifier(const char *formatSpecifier)
static std::size_t getSizeOfFile(base::type::fstream_t *fs)
Gets size of file provided in stream.
const LogMessage * logMessage(void) const
FormatFlags
Format flags used to determine specifiers that are active for performance improvements.
GLenum GLuint id
LogBuilderPtr m_logBuilder
status
Defines return codes that SDK interfaces use. Negative values indicate errors, a zero value indicates...
GLuint index
static void setVModules(const char *modules)
Sets vmodules as specified (on the fly)
Determines log file (full path) to write logs to for correponding level and logger.
GLdouble t
base::TypedConfigurations * m_typedConfigurations
void installCustomFormatSpecifier(const CustomFormatSpecifier &customFormatSpecifier)
#define elpptime_r
Level level(void) const
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLsizei len
Definition: glext.h:3285
GLuint GLfloat * val
GLuint64 key
Definition: glext.h:8966
static const unsigned int kDefaultSubsecondPrecision
Loggers repository.
static const char * kDefaultDateTimeFormatInFilename
static const base::type::char_t * kLogLocationFormatSpecifier
#define ELPP_INTERNAL_ERROR(msg, pe)
void setFromArgs(const base::utils::CommandLineArgs *commandLineArgs)
Adds spaces b/w logs that separated by left-shift operator.
static const base::type::char_t * kSeverityLevelShortFormatSpecifier
bool hasConfiguration(ConfigurationType configurationType)
Determines whether or not specified configuration type exists in the repository.
not_this_one begin(...)
static void defaultPreRollOutCallback(const char *, std::size_t)
static const int kCrashSignalsCount
const struct el::base::consts::@13 kTimeFormats[]
GLdouble f
Makes sure if -vmodule is used and does not specifies a module, then verbose logging is allowed via t...
void initialize(Logger *logger)
Information that can be highly useful and vary with verbose logging level.
static const char * kUnknownHost
void setDispatchAction(base::DispatchAction dispatchAction)
Determines format of logging corresponding level and logger.
RegisteredLoggers(const LogBuilderPtr &defaultLogBuilder)
Disable VModules extensions.
static std::string & replaceAll(std::string &str, char replaceWhat, char replaceWith)
Replaces all instances of replaceWhat with &#39;replaceWith&#39;. Original variable is changed for performanc...
const GLfloat * tc
Definition: glext.h:12710
bool contains(const std::shared_ptr< librealsense::device_info > &first, const std::shared_ptr< librealsense::device_info > &second)
Definition: context.cpp:49
#define STRCPY(a, b, len)
static bool contains(const char *str, char c)
Returns true if c exist in str.
const base::SubsecondPrecision & subsecondPrecision(Level level=Level::Global)
friend el::base::type::ostream_t & operator<<(el::base::type::ostream_t &os, const Loggable &loggable)
GLsizeiptr size
static base::TypedConfigurations defaultTypedConfigurations(void)
Default typed configuration based on existing defaultConf.
bool parseFromText(const std::string &configurationsString, Configurations *base=nullptr)
Parse configurations from configuration string.
#define INITIALIZE_EASYLOGGINGPP
base::TypedConfigurations * typedConfigurations(void)
static bool isValidId(const std::string &id)
static std::enable_if< std::is_pointer< T * >::value, void >::type safeDelete(T *&pointer)
Deletes memory safely and points to null.
std::unordered_map< Level, unsigned int > m_unflushedCount
static std::string & trim(std::string &str)
void initUnflushedCount(void)
const GLubyte * c
Definition: glext.h:12690
GLuint counter
Definition: glext.h:5684
TypedConfigurations(Configurations *configurations, base::LogStreamsReferenceMap *logStreamsReference)
Constructor to initialize (construct) the object off el::Configurations.
static const base::type::char_t * kWarningLevelShortLogValue
static struct StringToLevelItem stringToLevelMap[]
std::unordered_map< std::string, FileStreamPtr > LogStreamsReferenceMap
bool hasCustomFormatSpecifier(const char *formatSpecifier)
std::string resolveFilename(const std::string &filename)
#define STRCAT(a, b, len)
static void forEachLevel(base::type::EnumType *startIndex, const std::function< bool(void)> &fn)
Applies specified function to each level starting from startIndex.
static bool cStringCaseEq(const char *s1, const char *s2)
Compares cstring equality (case-insensitive) - uses toupper(char) Dont use strcasecmp because of CRT ...
base::LogStreamsReferenceMap m_logStreamsReference
virtual void handle(const T *handlePtr)=0
static bool isConfig(const std::string &line)
Preserves time format and does not convert it to sec, hour etc (performance tracking only) ...
unsigned int EnumType
void initializeLogger(const std::string &loggerId, bool lookup=true, bool needLock=true)
base::LogStreamsReferenceMap * m_logStreamsReference
virtual void updateDateFormat(std::size_t index, base::type::string_t &currFormat) ELPP_FINAL
Updates date time format if available in currFormat.
bool enabled(void) const
bool validateFileRolling(Level level, const PreRollOutCallback &preRollOutCallback)
static const char * kDefaultLoggerId
#define ELPP_STRLEN
void setLevel(base::type::VerboseLevel level)
Sets verbose level. Accepted range is 0-9.
bool isFlushNeeded(Level level)
std::string m_id
static void forEachConfigType(base::type::EnumType *startIndex, const std::function< bool(void)> &fn)
Applies specified function to each configuration type starting from startIndex.
static ConfigurationType convertFromString(const char *configStr)
Converts from configStr to ConfigurationType.
GLint GLint GLsizei GLint GLenum format
void unsafeSet(Level level, ConfigurationType configurationType, const std::string &value)
Thread unsafe set.
static void addFlag(Enum e, base::type::EnumType *flag)
static const base::type::char_t * kLoggerIdFormatSpecifier
Logger * get(const std::string &id, bool forceCreation=true)
def run(include_folder_path, addon_folder_path)
Definition: enums.py:46
std::string trim(std::string const &str)
Returns a new string without whitespace at the start/end.
Storage(const LogBuilderPtr &defaultLogBuilder)
bool endsWith(std::string const &s, std::string const &suffix)
static std::string & toUpper(std::string &str)
Converts string to uppercase.
static bool isDigit(char c)
Checks if character is digit. Dont use libc implementation of it to prevent locale issues...
void performConfig(const Configurations &configurations)
static const char * kPerformanceLoggerId
void reconfigure(void)
Reconfigures logger using existing configurations.
static const std::string releaseDate(void)
Release date of current version.
unsigned short VerboseLevel
void unregister(Logger *&logger)
#define ELPP_UNUSED(x)
static void flushAll(void)
Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered...
def find(dir, mask)
Definition: file.py:25
static const std::size_t kSourceFilenameMaxLength
static void abort(int status, const std::string &reason)
Aborts application due with user-defined status.
def callback(frame)
Definition: t265_stereo.py:91
static void reconfigureAllLoggers(const Configurations &configurations)
Reconfigures all the existing loggers with new configurations.
std::string m_currentUser
static bool hasFlag(Enum e, base::type::EnumType flag)
Configurations(void)
Default constructor with empty repository.
GLuint GLfloat x0
Definition: glext.h:9721
static const base::type::char_t * kLogFunctionFormatSpecifier
base::type::ostream_t & operator<<(base::type::ostream_t &os, const CommandLineArgs &c)
void init(void)
Definition: boing.c:180
GLuint start
void unsafeSetGlobally(ConfigurationType configurationType, const std::string &value, bool includeGlobalLevel)
Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true...
BOOST_DEDUCED_TYPENAME optional< T >::reference_const_type get(optional< T > const &opt)
static const char * kDateTimeFormatSpecifierForFilename
const std::string & parentApplicationName(void) const
bool unsafeValidateFileRolling(Level level, const PreRollOutCallback &preRollOutCallback)
Configurations with data types.
bool performanceTracking(Level level=Level::Global)
base::type::VerboseLevel verboseLevel(void) const
#define ELPP_ASYNC_LOGGING
Configurations * m_configurations
static const base::type::char_t * kLogFileFormatSpecifier
static const base::type::char_t * kLogLineFormatSpecifier
const base::type::char_t * unit
std::shared_ptr< LogBuilder > LogBuilderPtr
static const char * kDefaultLogFileParam
Alias of SubsecondPrecision (for backward compatibility)
Make terminal output colorful for supported terminals.
#define ELPP_LITERAL(txt)
Repository for hit counters used across the application.
Configurations m_defaultConfigurations
static void replaceFirstWithEscape(base::type::string_t &str, const base::type::string_t &replaceWhat, const base::type::string_t &replaceWith)
static const int kTimeFormatsCount
ConfigurationType configurationType(void) const
Gets configuration type of current configuration.
static void configureFromGlobal(const char *globalConfigurationFilePath)
Sets configurations from global configuration file.
static const std::string getBashOutput(const char *command)
Runs command on terminal and returns the output.
std::vector< std::pair< stream_profile, frame_callback > > configurations
Definition: recorder.h:485
GLsizei const GLchar *const * strings
Definition: glext.h:1891
User-provided custom format specifier.
void validateHitCounts(std::size_t n)
Validates hit counts and resets it if necessary.
Useful when application has potentially harmful situtaions.
static const char * kDays[7]
void handle(const LogDispatchData *data)
GLenum func
static bool wildCardMatch(const char *str, const char *pattern)
Matches wildcards, &#39;*&#39; and &#39;?&#39; only supported.
std::string string_t
When handling crashes by default, detailed crash reason will be logged as well.
Enables strict file rolling.
std::size_t maxLogFileSize(Level level)
static const base::type::char_t * kSeverityLevelFormatSpecifier
void setApplicationArguments(int argc, char **argv)
std::string m_parentApplicationName
void setRemainingToDefault(void)
Lets you set the remaining configurations to default.
virtual Container & list(void) ELPP_FINAL
Returns underlying container by reference.
LONG WINAPI CrashHandler(EXCEPTION_POINTERS *ep)
static const base::type::char_t * kErrorLevelLogValue
Level level(void) const
Gets level of current configuration.
MessageBuilder & operator<<(const std::string &msg)
const std::string & dateTimeFormat(void) const
static const base::type::char_t * kInfoLevelShortLogValue
Writer & construct(Logger *logger, bool needLock=true)
static const char * kConfigurationComment
LogBuilder * logBuilder(void) const
Flushes log with every log-entry (performance sensative) - Disabled by default.
const Configurations * configurations(void) const
void resolveLoggerFormatSpec(void) const
static bool unregisterLogger(const std::string &identity)
Unregisters logger - use it only when you know what you are doing, you may unregister loggers initial...
void configure(const Configurations &configurations)
Configures the logger using specified configurations.
LOG_INFO("Log message using LOG_INFO()")
Thread-safe Configuration repository.
Mainly useful to represent current progress of application.
void setValue(const std::string &value)
Set string based configuration value.
static const char * kPm
static const base::type::char_t * kFatalLevelLogValue
fname
Definition: rmse.py:13
Dispatches log messages.
static const base::LogStreamsReferenceMap * logStreamsReference(void)
Returns log stream reference pointer if needed by user.
static const base::type::char_t * kDebugLevelShortLogValue
static bool parseFromText(const std::string &configurationsString, Configurations *sender, Configurations *base=nullptr)
Parse configurations from configuration string.
std::function< void(const char *, std::size_t)> PreRollOutCallback
static bool parseFromFile(const std::string &configurationFile, Configurations *sender, Configurations *base=nullptr)
Parses configuration from file.
virtual ~PErrorWriter(void)
Configurations * configurations(void)
static const std::string version(void)
Current version number.
TimestampUnit
Enum to represent timestamp unit.
Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGI...
void triggerDispatch(void)
static bool endsWith(const std::string &str, const std::string &end)
Determines whether or not str ends with specified string.
static auto it
const char * getParamValue(const char *paramKey) const
Returns value of arguments.
static const char kFormatSpecifierChar
GLuint in
Definition: glext.h:8859
static const base::type::char_t * kVerboseLevelFormatSpecifier
GLenum type
static const base::type::VerboseLevel kMaxVerboseLevel
Specifies number of log entries to hold until we flush pending log data.
static bool parseLine(std::string *line, std::string *currConfigStr, std::string *currLevelStr, Level *currLevel, Configurations *conf)
std::string m_configurationFile
static bool configureFromArg(const char *argKey)
Configures loggers using command line arg. Ensure you have already set command line args...
base::type::string_t m_userFormat
std::unordered_map< std::string, base::type::LoggerRegistrationCallbackPtr > m_loggerRegistrationCallbacks
static const base::type::char_t * kDateTimeFormatSpecifier
static void validateFileRolling(Logger *logger, Level level)
Level level(void) const
Configurations m_configurations
base::type::EnumType m_flags
static Logger * getLogger(const std::string &identity, bool registerIfNotAvailable=true)
Gets existing or registers new logger.
static void gettimeofday(struct timeval *tv)
Cross platform gettimeofday for Windows and unix platform. This can be used to determine current micr...
static const base::type::char_t * kDebugLevelLogValue
GLint GLsizei count
static const base::type::char_t * kErrorLevelShortLogValue
static const el::base::utils::CommandLineArgs * commandLineArgs(void)
Returns command line arguments (pointer) provided to easylogging++.
bool vModulesEnabled(void)
Whether or not vModules enabled.
void setFromBase(Configurations *base)
Sets configuration based-off an existing configurations.
A subsecond precision class containing actual width and offset of the subsecond part.
static const int kYearBase
static const base::type::char_t * kMessageFormatSpecifier
static void buildStrippedFilename(const char *filename, char buff[], std::size_t limit=base::consts::kSourceFilenameMaxLength)
builds stripped filename and puts it in buff
const std::string & func(void) const
static const base::type::char_t * kCurrentHostFormatSpecifier
virtual iterator begin(void) ELPP_FINAL
typename::boost::move_detail::remove_reference< T >::type && move(T &&t) BOOST_NOEXCEPT
Configuration & operator=(const Configuration &c)
bool operator==(const LogFormat &other)
#define ELPP_WRITE_LOG(writer, level, dispatchAction,...)
static const std::size_t kSourceLineMaxLength
std::ostream & cerr()
std::string m_value
void parseFromFormat(const base::type::string_t &userFormat)
Updates format to be used while logging.
void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string &value)
Unsafely sets configuration if does not already exist.
std::unordered_map< std::string, base::type::VerboseLevel > m_modules
#define ELPP_ASSERT(expr, msg)
base::type::VerboseLevel level(void) const
static const base::type::char_t * kLogFileBaseFormatSpecifier
VRegistry(base::type::VerboseLevel level, base::type::EnumType *pFlags)
base::type::LineNumber line(void) const
Logger & operator=(const Logger &logger)
static const char * kConfigurationLoggerId
Generic level that represents all the levels. Useful when setting global configuration for all levels...
virtual void registerNew(const std::string &uniqKey, Logger *ptr) ELPP_FINAL
Registers new registry to repository.
static void ignoreComments(std::string *line)
static const char * kMonths[12]
int i
Whether or not to write corresponding log to log file.
static const Configurations * defaultConfigurations(void)
Returns current default.
Represents single configuration that has representing level, configuration type and a string based va...
static const char * kDaysAbbrev[7]
void setLogMessage(LogMessage *logMessage)
Logger(void)
static std::string getDateTime(const char *format, const base::SubsecondPrecision *ssPrec)
Gets current date and time with a subsecond part.
static bool isLevel(const std::string &line)
static base::type::fstream_t * newFileStream(const std::string &filename)
Creates new out file stream for specified filename.
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition: glext.h:9721
Whether or not to write corresponding level and logger log to standard output. By standard output mea...
GLushort pattern
Class that keeps record of current line hit for occasional logging.
GLuint GLenum GLenum transform
Definition: glext.h:11553
Represents a logger holding ID and configurations we need to write logs.
ConfigurationType
Represents enumeration of ConfigurationType used to configure or access certain aspect of logging...
base::type::string_t build(const LogMessage *logMessage, bool appendNewLine) const
#define ELPP_COUT_LINE(logLine)
Logger * logger(void) const
#define LOG_DEBUG(...)
Definition: src/types.h:239
static const base::type::char_t * kWarningLevelLogValue
static const base::type::EnumType kMaxValid
Represents maximum valid level. This is used internally and you should not need it.
Lock guard wrapper used when multi-threading is disabled.
static Level convertFromString(const char *levelStr)
Converts from levelStr to Level.
std::stringstream stringstream_t
std::string m_currentHost
static bool startsWith(const std::string &str, const std::string &start)
Determines whether or not str starts with specified string.
GLboolean * data
std::string m_dateTimeFormat
const std::string & file(void) const
const std::string & id(void) const
#define ELPP_COUT
GLuint64EXT * result
Definition: glext.h:10921
base::LogStreamsReferenceMap * m_logStreamsReference
bool validateAfterN(const char *filename, base::type::LineNumber lineNumber, std::size_t n)
Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one...
static const char * kUnknownUser
Enables hierarchical logging.
GLdouble v
virtual void log(el::base::type::ostream_t &os) const
static struct ConfigurationStringToTypeItem configStringToTypeMap[]
const base::type::string_t & userFormat(void) const
Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network") ...
Definition: parser.hpp:150
#define ELPP_DEFAULT_LOGGING_FLAGS
std::size_t logFlushThreshold(Level level)
static const char * kConfigurationLevel
bool operator()(const Configuration *conf) const
GLint GLsizei width
static const base::type::char_t * kThreadIdFormatSpecifier
static void clearVModules(void)
Clears vmodules.
Information that can be useful to back-trace certain events - mostly useful than debug logs...
virtual base::threading::Mutex & lock(void) ELPP_FINAL
Specifies log file max size.
const char * levelString
static unsigned long long getTimeDifference(const struct timeval &endTime, const struct timeval &startTime, base::TimestampUnit timestampUnit)
Gets time difference in milli/micro second depending on timestampUnit.
Represents registries for verbose logging.
static const char * kAm
void setToDefault(void)
Sets configurations to "factory based" configurations.
static base::type::VerboseLevel verboseLevel(void)
Gets current verbose level.
base::type::EnumType * m_pFlags
bool startsWith(std::string const &s, std::string const &prefix)
Easylogging++ management storage.
Allows to disable application abortion when logged using FATAL level.


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:13