proxygen
folly::LoggerDB Class Reference

#include <LoggerDB.h>

Classes

struct  HandlerInfo
 

Public Types

enum  TestConstructorArg { TESTING }
 
using InternalWarningHandler = void(*)(folly::StringPiece file, int lineNumber, std::string &&)
 

Public Member Functions

 ~LoggerDB ()
 
LogCategorygetCategory (folly::StringPiece name)
 
LogCategory *FOLLY_NULLABLE getCategoryOrNull (folly::StringPiece name)
 
void setLevel (folly::StringPiece name, LogLevel level, bool inherit=true)
 
void setLevel (LogCategory *category, LogLevel level, bool inherit=true)
 
LogConfig getConfig () const
 
LogConfig getFullConfig () const
 
void updateConfig (const LogConfig &config)
 
void resetConfig (const LogConfig &config)
 
void cleanupHandlers ()
 
size_t flushAllHandlers ()
 
void registerHandlerFactory (std::unique_ptr< LogHandlerFactory > factory, bool replaceExisting=false)
 
void unregisterHandlerFactory (folly::StringPiece type)
 
LogLevel xlogInit (folly::StringPiece categoryName, std::atomic< LogLevel > *xlogCategoryLevel, LogCategory **xlogCategory)
 
LogCategoryxlogInitCategory (folly::StringPiece categoryName, LogCategory **xlogCategory, std::atomic< bool > *isInitialized)
 
 LoggerDB (TestConstructorArg)
 

Static Public Member Functions

static LoggerDBget ()
 
template<typename... Args>
static void internalWarning (folly::StringPiece file, int lineNumber, Args &&...args) noexcept
 
static void setInternalWarningHandler (InternalWarningHandler handler)
 

Private Types

using LoggerNameMap = std::unordered_map< folly::StringPiece, std::unique_ptr< LogCategory >, LogName::Hash, LogName::Equals >
 
using HandlerFactoryMap = std::unordered_map< std::string, std::unique_ptr< LogHandlerFactory >>
 
using HandlerMap = std::unordered_map< std::string, std::weak_ptr< LogHandler >>
 
using NewHandlerMap = std::unordered_map< std::string, std::shared_ptr< LogHandler >>
 
using OldToNewHandlerMap = std::unordered_map< std::shared_ptr< LogHandler >, std::shared_ptr< LogHandler >>
 

Private Member Functions

 LoggerDB (LoggerDB const &)=delete
 
LoggerDBoperator= (LoggerDB const &)=delete
 
 LoggerDB ()
 
LogCategorygetOrCreateCategoryLocked (LoggerNameMap &loggersByName, folly::StringPiece name)
 
LogCategorycreateCategoryLocked (LoggerNameMap &loggersByName, folly::StringPiece name, LogCategory *parent)
 
LogConfig getConfigImpl (bool includeAllCategories) const
 
void startConfigUpdate (const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, const LogConfig &config, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
 
void finishConfigUpdate (const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
 
std::vector< std::shared_ptr< LogHandler > > buildCategoryHandlerList (const NewHandlerMap &handlerMap, StringPiece categoryName, const std::vector< std::string > &categoryHandlerNames)
 

Static Private Member Functions

static void internalWarningImpl (folly::StringPiece filename, int lineNumber, std::string &&msg) noexcept
 
static void defaultInternalWarningImpl (folly::StringPiece filename, int lineNumber, std::string &&msg) noexcept
 

Private Attributes

folly::Synchronized< LoggerNameMaploggersByName_
 
folly::Synchronized< HandlerInfohandlerInfo_
 

Static Private Attributes

static std::atomic< InternalWarningHandlerwarningHandler_
 

Detailed Description

LoggerDB stores the set of LogCategory objects.

Definition at line 40 of file LoggerDB.h.

Member Typedef Documentation

using folly::LoggerDB::HandlerFactoryMap = std::unordered_map<std::string, std::unique_ptr<LogHandlerFactory>>
private

Definition at line 234 of file LoggerDB.h.

using folly::LoggerDB::HandlerMap = std::unordered_map<std::string, std::weak_ptr<LogHandler>>
private

Definition at line 235 of file LoggerDB.h.

using folly::LoggerDB::InternalWarningHandler = void (*)(folly::StringPiece file, int lineNumber, std::string&&)

Definition at line 210 of file LoggerDB.h.

using folly::LoggerDB::LoggerNameMap = std::unordered_map< folly::StringPiece, std::unique_ptr<LogCategory>, LogName::Hash, LogName::Equals>
private

Definition at line 231 of file LoggerDB.h.

using folly::LoggerDB::NewHandlerMap = std::unordered_map<std::string, std::shared_ptr<LogHandler>>
private

Definition at line 255 of file LoggerDB.h.

using folly::LoggerDB::OldToNewHandlerMap = std:: unordered_map<std::shared_ptr<LogHandler>, std::shared_ptr<LogHandler>>
private

Definition at line 257 of file LoggerDB.h.

Member Enumeration Documentation

Enumerator
TESTING 

Definition at line 176 of file LoggerDB.h.

Constructor & Destructor Documentation

folly::LoggerDB::~LoggerDB ( )

Definition at line 131 of file LoggerDB.cpp.

131 {}
folly::LoggerDB::LoggerDB ( TestConstructorArg  )
explicit

Construct a LoggerDB for testing purposes.

Most callers should not need this function, and should use LoggerDB::get() to obtain the main LoggerDB singleton. This function exists mainly to allow testing LoggerDB objects in unit tests. It requires an explicit argument just to prevent callers from calling it unintentionally.

Definition at line 129 of file LoggerDB.cpp.

129 : LoggerDB() {}
folly::LoggerDB::LoggerDB ( LoggerDB const &  )
privatedelete
folly::LoggerDB::LoggerDB ( )
private

Definition at line 118 of file LoggerDB.cpp.

References folly::kDefaultLogLevel, and folly::gen::move.

118  {
119  // Create the root log category and set its log level
120  auto rootUptr = std::make_unique<LogCategory>(this);
121  LogCategory* root = rootUptr.get();
122  auto ret =
123  loggersByName_.wlock()->emplace(root->getName(), std::move(rootUptr));
124  DCHECK(ret.second);
125 
126  root->setLevelLocked(kDefaultLogLevel, false);
127 }
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
constexpr LogLevel kDefaultLogLevel
Definition: LogLevel.h:102

Member Function Documentation

std::vector< std::shared_ptr< LogHandler > > folly::LoggerDB::buildCategoryHandlerList ( const NewHandlerMap handlerMap,
StringPiece  categoryName,
const std::vector< std::string > &  categoryHandlerNames 
)
private

Definition at line 372 of file LoggerDB.cpp.

Referenced by resetConfig(), and updateConfig().

375  {
376  std::vector<std::shared_ptr<LogHandler>> catHandlers;
377  for (const auto& handlerName : categoryHandlerNames) {
378  auto iter = handlerMap.find(handlerName);
379  if (iter == handlerMap.end()) {
380  // This really shouldn't be possible; the checks in startConfigUpdate()
381  // should have already bailed out if there was an unknown handler.
382  throw std::invalid_argument(to<std::string>(
383  "bug: unknown log handler \"",
384  handlerName,
385  "\" configured for log category \"",
386  categoryName,
387  "\""));
388  }
389  catHandlers.push_back(iter->second);
390  }
391 
392  return catHandlers;
393 }
void folly::LoggerDB::cleanupHandlers ( )

Remove all registered LogHandlers on all LogCategory objects.

This is called on the main LoggerDB object during shutdown.

Definition at line 520 of file LoggerDB.cpp.

References handlerInfo_, and loggersByName_.

520  {
521  // Get a copy of all categories, so we can call clearHandlers() without
522  // holding the loggersByName_ lock. We don't need to worry about LogCategory
523  // lifetime, since LogCategory objects always live for the lifetime of the
524  // LoggerDB.
525  std::vector<LogCategory*> categories;
526  {
527  auto loggersByName = loggersByName_.wlock();
528  categories.reserve(loggersByName->size());
529  for (const auto& entry : *loggersByName) {
530  categories.push_back(entry.second.get());
531  }
532  }
533 
534  // Also extract our HandlerFactoryMap and HandlerMap, so we can clear them
535  // later without holding the handlerInfo_ lock.
536  HandlerFactoryMap factories;
537  HandlerMap handlers;
538  {
539  auto handlerInfo = handlerInfo_.wlock();
540  factories.swap(handlerInfo->factories);
541  handlers.swap(handlerInfo->handlers);
542  }
543 
544  // Remove all of the LogHandlers from all log categories,
545  // to drop any shared_ptr references to the LogHandlers
546  for (auto* category : categories) {
547  category->clearHandlers();
548  }
549 }
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
std::unordered_map< std::string, std::unique_ptr< LogHandlerFactory >> HandlerFactoryMap
Definition: LoggerDB.h:234
std::unordered_map< std::string, std::weak_ptr< LogHandler >> HandlerMap
Definition: LoggerDB.h:235
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
LogCategory * folly::LoggerDB::createCategoryLocked ( LoggerNameMap loggersByName,
folly::StringPiece  name,
LogCategory parent 
)
private

Definition at line 509 of file LoggerDB.cpp.

References folly::gen::move, name, and parent.

Referenced by getOrCreateCategoryLocked().

512  {
513  auto uptr = std::make_unique<LogCategory>(name, parent);
514  LogCategory* logger = uptr.get();
515  auto ret = loggersByName.emplace(logger->getName(), std::move(uptr));
516  DCHECK(ret.second);
517  return logger;
518 }
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const char * name
Definition: http_parser.c:437
folly::Function< void()> parent
Definition: AtFork.cpp:34
void folly::LoggerDB::defaultInternalWarningImpl ( folly::StringPiece  filename,
int  lineNumber,
std::string &&  msg 
)
staticprivatenoexcept

Definition at line 679 of file LoggerDB.cpp.

References folly::kIsDebug, and folly::writeFull().

Referenced by internalWarningImpl().

682  {
683  // Rate limit to 10 messages every 5 seconds.
684  //
685  // We intentonally use a leaky Meyer's singleton here over folly::Singleton:
686  // - We want this code to work even before main()
687  // - This singleton does not depend on any other singletons.
688  static auto* rateLimiter =
689  new logging::IntervalRateLimiter{10, std::chrono::seconds(5)};
690  if (!rateLimiter->check()) {
691  return;
692  }
693 
694  if (folly::kIsDebug) {
695  // Write directly to file descriptor 2.
696  //
697  // It's possible the application has closed fd 2 and is using it for
698  // something other than stderr. However we have no good way to detect
699  // this, which is the main reason we only write to stderr in debug build
700  // modes. assert() also writes directly to stderr on failure, which seems
701  // like a reasonable precedent.
702  //
703  // Another option would be to use openlog() and syslog(). However
704  // calling openlog() may inadvertently affect the behavior of other parts
705  // of the program also using syslog().
706  //
707  // We don't check for write errors here, since there's not much else we can
708  // do if it fails.
709  auto fullMsg = folly::to<std::string>(
710  "logging warning:", filename, ":", lineNumber, ": ", msg, "\n");
711  folly::writeFull(STDERR_FILENO, fullMsg.data(), fullMsg.size());
712  }
713 }
constexpr auto kIsDebug
Definition: Portability.h:264
ssize_t writeFull(int fd, const void *buf, size_t count)
Definition: FileUtil.cpp:134
void folly::LoggerDB::finishConfigUpdate ( const Synchronized< HandlerInfo >::LockedPtr handlerInfo,
NewHandlerMap handlers,
OldToNewHandlerMap oldToNewHandlerMap 
)
private

Update handlerInfo_ at the end of a config update operation.

Definition at line 346 of file LoggerDB.cpp.

References folly::Synchronized< T, Mutex >::swap().

Referenced by resetConfig(), and updateConfig().

349  {
350  // Build a new map to replace handlerInfo->handlers
351  // This will contain only the LogHandlers that are still in use by the
352  // current LogCategory settings.
353  std::unordered_map<std::string, std::weak_ptr<LogHandler>> newHandlerMap;
354  for (const auto& entry : *handlers) {
355  newHandlerMap.emplace(entry.first, entry.second);
356  }
357  // Drop all of our shared_ptr references to LogHandler objects,
358  // and then remove entries in newHandlerMap that are unreferenced.
359  handlers->clear();
360  oldToNewHandlerMap->clear();
361  handlerInfo->handlers.clear();
362  for (auto iter = newHandlerMap.begin(); iter != newHandlerMap.end(); ) {
363  if (iter->second.expired()) {
364  iter = newHandlerMap.erase(iter);
365  } else {
366  ++iter;
367  }
368  }
369  handlerInfo->handlers.swap(newHandlerMap);
370 }
size_t folly::LoggerDB::flushAllHandlers ( )

Call flush() on all LogHandler objects registered on any LogCategory in this LoggerDB.

Returns the number of registered LogHandlers.

Definition at line 551 of file LoggerDB.cpp.

References handler(), and loggersByName_.

Referenced by folly::LogCategory::admitMessage().

551  {
552  // Build a set of all LogHandlers. We use a set to avoid calling flush()
553  // more than once on the same handler if it is registered on multiple
554  // different categories.
555  std::set<std::shared_ptr<LogHandler>> handlers;
556  {
557  auto loggersByName = loggersByName_.wlock();
558  for (const auto& entry : *loggersByName) {
559  for (const auto& handler : entry.second->getHandlers()) {
560  handlers.emplace(handler);
561  }
562  }
563  }
564 
565  // Call flush() on each handler
566  for (const auto& handler : handlers) {
567  handler->flush();
568  }
569  return handlers.size();
570 }
void handler(int, siginfo_t *, void *)
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
LoggerDB & folly::LoggerDB::get ( )
static

Get the main LoggerDB singleton.

Definition at line 112 of file LoggerDB.cpp.

References folly::singleton.

Referenced by folly::XlogCategoryInfo< IsInHeaderFile >::init(), folly::initLogging(), folly::XlogLevelInfo< IsInHeaderFile >::loadLevelFull(), folly::Logger::Logger(), TEST(), and TEST_F().

112  {
113  // Intentionally leaky singleton
114  static LoggerDBSingleton singleton{new LoggerDB()};
115  return singleton.getDB();
116 }
static Singleton< ShutdownSocketSet, PrivateTag > singleton
LogCategory * folly::LoggerDB::getCategory ( folly::StringPiece  name)

Get the LogCategory for the specified name.

This creates the LogCategory for the specified name if it does not exist already.

Definition at line 133 of file LoggerDB.cpp.

References getOrCreateCategoryLocked(), loggersByName_, and name.

Referenced by folly::Logger::Logger(), and TEST_F().

133  {
135 }
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
const char * name
Definition: http_parser.c:437
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
LogCategory *FOLLY_NULLABLE folly::LoggerDB::getCategoryOrNull ( folly::StringPiece  name)

Get the LogCategory for the specified name, if it already exists.

This returns nullptr if no LogCategory has been created yet for the specified name.

Definition at line 137 of file LoggerDB.cpp.

References loggersByName_.

137  {
138  auto loggersByName = loggersByName_.rlock();
139 
140  auto it = loggersByName->find(name);
141  if (it == loggersByName->end()) {
142  return nullptr;
143  }
144  return it->second.get();
145 }
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
LogConfig folly::LoggerDB::getConfig ( ) const

Get a LogConfig object describing the current state of the LoggerDB.

Definition at line 158 of file LoggerDB.cpp.

References getConfigImpl().

Referenced by TEST().

158  {
159  return getConfigImpl(/* includeAllCategories = */ false);
160 }
LogConfig getConfigImpl(bool includeAllCategories) const
Definition: LoggerDB.cpp:166
LogConfig folly::LoggerDB::getConfigImpl ( bool  includeAllCategories) const
private

Definition at line 166 of file LoggerDB.cpp.

References handler(), handlerInfo_, loggersByName_, folly::MAX_LEVEL, folly::gen::move, and name.

Referenced by getConfig(), and getFullConfig().

166  {
167  auto handlerInfo = handlerInfo_.rlock();
168 
169  LogConfig::HandlerConfigMap handlerConfigs;
170  std::unordered_map<std::shared_ptr<LogHandler>, string> handlersToName;
171  for (const auto& entry : handlerInfo->handlers) {
172  auto handler = entry.second.lock();
173  if (!handler) {
174  continue;
175  }
176  handlersToName.emplace(handler, entry.first);
177  handlerConfigs.emplace(entry.first, handler->getConfig());
178  }
179 
180  size_t anonymousNameIndex = 1;
181  auto generateAnonymousHandlerName = [&]() {
182  // Return a unique name of the form "anonymousHandlerN"
183  // Keep incrementing N until we find a name that isn't currently taken.
184  while (true) {
185  auto name = to<string>("anonymousHandler", anonymousNameIndex);
186  ++anonymousNameIndex;
187  if (handlerInfo->handlers.find(name) == handlerInfo->handlers.end()) {
188  return name;
189  }
190  }
191  };
192 
193  LogConfig::CategoryConfigMap categoryConfigs;
194  {
195  auto loggersByName = loggersByName_.rlock();
196  for (const auto& entry : *loggersByName) {
197  auto* category = entry.second.get();
198  auto levelInfo = category->getLevelInfo();
199  auto handlers = category->getHandlers();
200 
201  // Don't report categories that have default settings
202  // if includeAllCategories is false
203  if (!includeAllCategories && handlers.empty() &&
204  levelInfo.first == LogLevel::MAX_LEVEL && levelInfo.second) {
205  continue;
206  }
207 
208  // Translate the handler pointers to names
209  std::vector<string> handlerNames;
210  for (const auto& handler : handlers) {
211  auto iter = handlersToName.find(handler);
212  if (iter == handlersToName.end()) {
213  // This LogHandler must have been manually attached to the category,
214  // rather than defined with `updateConfig()` or `resetConfig()`.
215  // Generate a unique name to use for reporting it in the config.
216  auto name = generateAnonymousHandlerName();
217  handlersToName.emplace(handler, name);
218  handlerConfigs.emplace(name, handler->getConfig());
219  handlerNames.emplace_back(name);
220  } else {
221  handlerNames.emplace_back(iter->second);
222  }
223  }
224 
225  LogCategoryConfig categoryConfig(
226  levelInfo.first, levelInfo.second, handlerNames);
227  categoryConfigs.emplace(category->getName(), std::move(categoryConfig));
228  }
229  }
230 
231  return LogConfig{std::move(handlerConfigs), std::move(categoryConfigs)};
232 }
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void handler(int, siginfo_t *, void *)
const char * name
Definition: http_parser.c:437
std::unordered_map< std::string, LogCategoryConfig > CategoryConfigMap
Definition: LogConfig.h:35
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
std::unordered_map< std::string, LogHandlerConfig > HandlerConfigMap
Definition: LogConfig.h:36
LogConfig folly::LoggerDB::getFullConfig ( ) const

Get a LogConfig object fully describing the state of the LoggerDB.

This is similar to getConfig(), but it returns LogCategoryConfig objects for all defined log categories, including ones that are using the default configuration settings.

Definition at line 162 of file LoggerDB.cpp.

References getConfigImpl().

162  {
163  return getConfigImpl(/* includeAllCategories = */ true);
164 }
LogConfig getConfigImpl(bool includeAllCategories) const
Definition: LoggerDB.cpp:166
LogCategory * folly::LoggerDB::getOrCreateCategoryLocked ( LoggerNameMap loggersByName,
folly::StringPiece  name 
)
private

Definition at line 496 of file LoggerDB.cpp.

References createCategoryLocked(), folly::LogName::getParent(), and parent.

Referenced by getCategory(), resetConfig(), setLevel(), updateConfig(), xlogInit(), and xlogInitCategory().

498  {
499  auto it = loggersByName.find(name);
500  if (it != loggersByName.end()) {
501  return it->second.get();
502  }
503 
504  StringPiece parentName = LogName::getParent(name);
505  LogCategory* parent = getOrCreateCategoryLocked(loggersByName, parentName);
506  return createCategoryLocked(loggersByName, name, parent);
507 }
static folly::StringPiece getParent(folly::StringPiece name)
Definition: LogName.cpp:126
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
LogCategory * createCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name, LogCategory *parent)
Definition: LoggerDB.cpp:509
Range< const char * > StringPiece
folly::Function< void()> parent
Definition: AtFork.cpp:34
template<typename... Args>
static void folly::LoggerDB::internalWarning ( folly::StringPiece  file,
int  lineNumber,
Args &&...  args 
)
inlinestaticnoexcept

internalWarning() is used to report a problem when something goes wrong internally in the logging library.

We can't log these messages through the normal logging flow since logging itself has failed.

Example scenarios where this is used:

  • We fail to write to a log file (for instance, when the disk is full)
  • A LogHandler throws an unexpected exception

Definition at line 201 of file LoggerDB.h.

Referenced by folly::AsyncFileWriter::onIoError(), folly::LogCategory::processMessage(), and folly::ImmediateFileWriter::writeMessage().

204  {
206  file, lineNumber, folly::to<std::string>(std::forward<Args>(args)...));
207  }
static void internalWarningImpl(folly::StringPiece filename, int lineNumber, std::string &&msg) noexcept
Definition: LoggerDB.cpp:644
void folly::LoggerDB::internalWarningImpl ( folly::StringPiece  filename,
int  lineNumber,
std::string &&  msg 
)
staticprivatenoexcept

Definition at line 644 of file LoggerDB.cpp.

References defaultInternalWarningImpl(), handler(), folly::gen::move, and warningHandler_.

647  {
648  auto handler = warningHandler_.load();
649  if (handler) {
650  handler(filename, lineNumber, std::move(msg));
651  } else {
652  defaultInternalWarningImpl(filename, lineNumber, std::move(msg));
653  }
654 }
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void handler(int, siginfo_t *, void *)
static void defaultInternalWarningImpl(folly::StringPiece filename, int lineNumber, std::string &&msg) noexcept
Definition: LoggerDB.cpp:679
static std::atomic< InternalWarningHandler > warningHandler_
Definition: LoggerDB.h:298
LoggerDB& folly::LoggerDB::operator= ( LoggerDB const &  )
privatedelete
void folly::LoggerDB::registerHandlerFactory ( std::unique_ptr< LogHandlerFactory factory,
bool  replaceExisting = false 
)

Register a LogHandlerFactory.

The LogHandlerFactory will be used to create LogHandler objects from a LogConfig object during updateConfig() and resetConfig() calls.

Only one factory can be registered for a given handler type name. LogHandlerFactory::getType() returns the handler type supported by this LogHandlerFactory.

If an existing LogHandlerFactory is already registered with this type name and replaceExisting is false a std::range_error will be thrown. Otherwise, if replaceExisting is true, the new factory will replace the existing factory.

Definition at line 572 of file LoggerDB.cpp.

References handlerInfo_, folly::gen::move, and type.

Referenced by folly::initializeLoggerDB().

574  {
575  auto type = factory->getType();
576  auto handlerInfo = handlerInfo_.wlock();
577  if (replaceExisting) {
578  handlerInfo->factories[type.str()] = std::move(factory);
579  } else {
580  auto ret = handlerInfo->factories.emplace(type.str(), std::move(factory));
581  if (!ret.second) {
582  throw std::range_error(to<std::string>(
583  "a LogHandlerFactory for the type \"", type, "\" already exists"));
584  }
585  }
586 }
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
PskType type
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
void folly::LoggerDB::resetConfig ( const LogConfig config)

Reset the current LoggerDB state to the specified LogConfig settings.

All LogCategories not mentioned in the new LogConfig will have all currently configured log handlers removed and their log level set to its default state. For the root category the default log level is kDefaultLogLevel (see LogLevel.h); for all other categories the default level is MAX_LEVEL with log level inheritance enabled.

LogCategories listed in the new config but without LogHandler information defined will have all existing handlers removed.

Definition at line 435 of file LoggerDB.cpp.

References buildCategoryHandlerList(), finishConfigUpdate(), folly::LogConfig::getCategoryConfigs(), getOrCreateCategoryLocked(), handlerInfo_, folly::kDefaultLogLevel, loggersByName_, folly::MAX_LEVEL, folly::gen::move, and startConfigUpdate().

435  {
436  // Grab the handlerInfo_ lock.
437  // We hold it in write mode for the entire config update operation. This
438  // ensures that only a single config update operation ever runs at once.
439  auto handlerInfo = handlerInfo_.wlock();
440 
441  NewHandlerMap handlers;
442  OldToNewHandlerMap oldToNewHandlerMap;
443  startConfigUpdate(handlerInfo, config, &handlers, &oldToNewHandlerMap);
444 
445  // Make sure all log categories mentioned in the new config exist.
446  // This ensures that we will cover them in our walk below.
447  LogCategory* rootCategory;
448  {
449  auto loggersByName = loggersByName_.wlock();
450  rootCategory = getOrCreateCategoryLocked(*loggersByName, "");
451  for (const auto& entry : config.getCategoryConfigs()) {
452  getOrCreateCategoryLocked(*loggersByName, entry.first);
453  }
454  }
455 
456  {
457  // Update all log categories
458  auto loggersByName = loggersByName_.rlock();
459  for (const auto& entry : *loggersByName) {
460  auto* category = entry.second.get();
461 
462  auto configIter = config.getCategoryConfigs().find(category->getName());
463  if (configIter == config.getCategoryConfigs().end()) {
464  // This category is not listed in the config settings.
465  // Reset it to the default settings.
466  category->clearHandlers();
467 
468  if (category == rootCategory) {
469  category->setLevelLocked(kDefaultLogLevel, false);
470  } else {
471  category->setLevelLocked(LogLevel::MAX_LEVEL, true);
472  }
473  continue;
474  }
475 
476  const auto& catConfig = configIter->second;
477 
478  // Update the category log level
479  category->setLevelLocked(catConfig.level, catConfig.inheritParentLevel);
480 
481  // Update the category handlers list.
482  // If the handler list is not set in the config, clear out any existing
483  // handlers rather than leaving it as-is.
484  std::vector<std::shared_ptr<LogHandler>> catHandlers;
485  if (catConfig.handlers.hasValue()) {
486  catHandlers = buildCategoryHandlerList(
487  handlers, entry.first, catConfig.handlers.value());
488  }
489  category->replaceHandlers(std::move(catHandlers));
490  }
491  }
492 
493  finishConfigUpdate(handlerInfo, &handlers, &oldToNewHandlerMap);
494 }
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
std::unordered_map< std::shared_ptr< LogHandler >, std::shared_ptr< LogHandler >> OldToNewHandlerMap
Definition: LoggerDB.h:257
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::vector< std::shared_ptr< LogHandler > > buildCategoryHandlerList(const NewHandlerMap &handlerMap, StringPiece categoryName, const std::vector< std::string > &categoryHandlerNames)
Definition: LoggerDB.cpp:372
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
AHArrayT::Config config
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
constexpr LogLevel kDefaultLogLevel
Definition: LogLevel.h:102
void startConfigUpdate(const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, const LogConfig &config, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
Definition: LoggerDB.cpp:237
void finishConfigUpdate(const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
Definition: LoggerDB.cpp:346
std::unordered_map< std::string, std::shared_ptr< LogHandler >> NewHandlerMap
Definition: LoggerDB.h:255
void folly::LoggerDB::setInternalWarningHandler ( InternalWarningHandler  handler)
static

Set a function to be called when the logging library generates an internal warning.

The supplied handler should never throw exceptions.

If a null handler is supplied, the default built-in handler will be used.

The default handler reports the message with _CrtDbgReport(_CRT_WARN) on Windows, and prints the message to stderr on other platforms. It also rate limits messages if they are arriving too quickly.

Definition at line 656 of file LoggerDB.cpp.

References warningHandler_.

Referenced by TEST().

656  {
657  // This API is intentionally pretty basic. It has a number of limitations:
658  //
659  // - We only support plain function pointers, and not full std::function
660  // objects. This makes it possible to use std::atomic to access the
661  // handler pointer, and also makes it safe to store in a zero-initialized
662  // file-static pointer.
663  //
664  // - We don't support any void* argument to the handler. The caller is
665  // responsible for storing any callback state themselves.
666  //
667  // - When replacing or unsetting a handler we don't make any guarantees about
668  // when the old handler will stop being called. It may still be called
669  // from other threads briefly even after setInternalWarningHandler()
670  // returns. This is also a consequence of using std::atomic rather than a
671  // full lock.
672  //
673  // This provides the minimum capabilities needed to customize the handler,
674  // while still keeping the implementation simple and safe to use even before
675  // main().
676  warningHandler_.store(handler);
677 }
void handler(int, siginfo_t *, void *)
static std::atomic< InternalWarningHandler > warningHandler_
Definition: LoggerDB.h:298
void folly::LoggerDB::setLevel ( folly::StringPiece  name,
LogLevel  level,
bool  inherit = true 
)

Set the log level for the specified category.

Messages logged to a specific log category will be ignored unless the message log level is greater than the LogCategory's effective log level.

If inherit is true, LogCategory's effective log level is the minimum of its level and it's parent category's effective log level. If inherit is false, the LogCategory's effective log level is simply its log level. (Setting inherit to false is necessary if you want a child LogCategory to use a less verbose level than its parent categories.)

Definition at line 147 of file LoggerDB.cpp.

References getOrCreateCategoryLocked(), loggersByName_, and folly::LogCategory::setLevelLocked().

Referenced by folly::LogCategory::setLevel(), and TEST_F().

147  {
148  auto loggersByName = loggersByName_.wlock();
149  LogCategory* category = getOrCreateCategoryLocked(*loggersByName, name);
150  category->setLevelLocked(level, inherit);
151 }
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
void folly::LoggerDB::setLevel ( LogCategory category,
LogLevel  level,
bool  inherit = true 
)

Definition at line 153 of file LoggerDB.cpp.

References loggersByName_, and folly::LogCategory::setLevelLocked().

153  {
154  auto loggersByName = loggersByName_.wlock();
155  category->setLevelLocked(level, inherit);
156 }
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
void folly::LoggerDB::startConfigUpdate ( const Synchronized< HandlerInfo >::LockedPtr handlerInfo,
const LogConfig config,
NewHandlerMap handlers,
OldToNewHandlerMap oldToNewHandlerMap 
)
private

Process handler config information when starting a config update operation.

Definition at line 237 of file LoggerDB.cpp.

References folly::exceptionStr(), folly::LogConfig::getCategoryConfigs(), folly::LogConfig::getHandlerConfigs(), handler(), folly::Optional< Value >::hasValue(), folly::gen::move, folly::LogHandlerConfig::options, folly::LogHandlerConfig::type, folly::LogHandlerConfig::update(), and folly::Optional< Value >::value().

Referenced by resetConfig(), and updateConfig().

241  {
242  // Get a map of all currently existing LogHandlers.
243  // This resolves weak_ptrs to shared_ptrs, and ignores expired weak_ptrs.
244  // This prevents any of these LogHandler pointers from expiring during the
245  // config update.
246  for (const auto& entry : handlerInfo->handlers) {
247  auto handler = entry.second.lock();
248  if (handler) {
249  handlers->emplace(entry.first, std::move(handler));
250  }
251  }
252 
253  // Create all of the new LogHandlers needed from this configuration
254  for (const auto& entry : config.getHandlerConfigs()) {
255  // Check to see if there is an existing LogHandler with this name
256  std::shared_ptr<LogHandler> oldHandler;
257  auto iter = handlers->find(entry.first);
258  if (iter != handlers->end()) {
259  oldHandler = iter->second;
260  }
261 
262  LogHandlerConfig updatedConfig;
263  const LogHandlerConfig* handlerConfig;
264  if (entry.second.type.hasValue()) {
265  handlerConfig = &entry.second;
266  } else {
267  // This configuration is intended to update an existing LogHandler
268  if (!oldHandler) {
269  throw std::invalid_argument(to<std::string>(
270  "cannot update unknown log handler \"", entry.first, "\""));
271  }
272 
273  updatedConfig = oldHandler->getConfig();
274  if (!updatedConfig.type.hasValue()) {
275  // This normally should not happen unless someone improperly manually
276  // constructed a LogHandler object. All existing LogHandler objects
277  // should indicate their type.
278  throw std::invalid_argument(to<std::string>(
279  "existing log handler \"",
280  entry.first,
281  "\" is missing type information"));
282  }
283  updatedConfig.update(entry.second);
284  handlerConfig = &updatedConfig;
285  }
286 
287  // Look up the LogHandlerFactory
288  auto factoryIter = handlerInfo->factories.find(handlerConfig->type.value());
289  if (factoryIter == handlerInfo->factories.end()) {
290  throw std::invalid_argument(to<std::string>(
291  "unknown log handler type \"", handlerConfig->type.value(), "\""));
292  }
293 
294  // Create the new log handler
295  const auto& factory = factoryIter->second;
296  std::shared_ptr<LogHandler> handler;
297  try {
298  if (oldHandler) {
299  handler = factory->updateHandler(oldHandler, handlerConfig->options);
300  if (handler != oldHandler) {
301  oldToNewHandlerMap->emplace(oldHandler, handler);
302  }
303  } else {
304  handler = factory->createHandler(handlerConfig->options);
305  }
306  } catch (const std::exception& ex) {
307  // Errors creating or updating the the log handler are generally due to
308  // bad configuration options. It is useful to update the exception
309  // message to include the name of the log handler we were trying to
310  // update or create.
311  throw std::invalid_argument(to<string>(
312  "error ",
313  oldHandler ? "updating" : "creating",
314  " log handler \"",
315  entry.first,
316  "\": ",
317  exceptionStr(ex)));
318  }
319  handlerInfo->handlers[entry.first] = handler;
320  (*handlers)[entry.first] = handler;
321  }
322 
323  // Before we start making any LogCategory changes, confirm that all handlers
324  // named in the category configs are known handlers.
325  for (const auto& entry : config.getCategoryConfigs()) {
326  if (!entry.second.handlers.hasValue()) {
327  continue;
328  }
329  for (const auto& handlerName : entry.second.handlers.value()) {
330  auto iter = handlers->find(handlerName);
331  if (iter == handlers->end()) {
332  throw std::invalid_argument(to<std::string>(
333  "unknown log handler \"",
334  handlerName,
335  "\" configured for log category \"",
336  entry.first,
337  "\""));
338  }
339  }
340  }
341 }
fbstring exceptionStr(const std::exception &e)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
AHArrayT::Config config
void handler(int, siginfo_t *, void *)
void folly::LoggerDB::unregisterHandlerFactory ( folly::StringPiece  type)

Remove a registered LogHandlerFactory.

The type parameter should be the name of the handler type, as returned by LogHandlerFactory::getType().

Throws std::range_error if no handler factory with this type name exists.

Definition at line 588 of file LoggerDB.cpp.

References handlerInfo_, and folly::Range< Iter >::str().

588  {
589  auto handlerInfo = handlerInfo_.wlock();
590  auto numRemoved = handlerInfo->factories.erase(type.str());
591  if (numRemoved != 1) {
592  throw std::range_error(
593  to<std::string>("no LogHandlerFactory for type \"", type, "\" found"));
594  }
595 }
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
std::string str() const
Definition: Range.h:591
void folly::LoggerDB::updateConfig ( const LogConfig config)

Update the current LoggerDB state with the specified LogConfig settings.

Log categories and handlers listed in the LogConfig object will be updated to the new state listed in the LogConfig. Settings on categories and handlers not listed in the config will be left as-is.

Definition at line 395 of file LoggerDB.cpp.

References buildCategoryHandlerList(), finishConfigUpdate(), folly::LogConfig::getCategoryConfigs(), getOrCreateCategoryLocked(), handlerInfo_, loggersByName_, folly::gen::move, folly::LogCategory::replaceHandlers(), folly::LogCategory::setLevelLocked(), and startConfigUpdate().

Referenced by folly::initializeLoggerDB(), and folly::initLogging().

395  {
396  // Grab the handlerInfo_ lock.
397  // We hold it in write mode for the entire config update operation. This
398  // ensures that only a single config update operation ever runs at once.
399  auto handlerInfo = handlerInfo_.wlock();
400 
401  NewHandlerMap handlers;
402  OldToNewHandlerMap oldToNewHandlerMap;
403  startConfigUpdate(handlerInfo, config, &handlers, &oldToNewHandlerMap);
404 
405  // If an existing LogHandler was replaced with a new one,
406  // walk all current LogCategories and replace this handler.
407  if (!oldToNewHandlerMap.empty()) {
408  auto loggerMap = loggersByName_.rlock();
409  for (const auto& entry : *loggerMap) {
410  entry.second->updateHandlers(oldToNewHandlerMap);
411  }
412  }
413 
414  // Update log levels and handlers mentioned in the config update
415  auto loggersByName = loggersByName_.wlock();
416  for (const auto& entry : config.getCategoryConfigs()) {
417  LogCategory* category =
418  getOrCreateCategoryLocked(*loggersByName, entry.first);
419 
420  // Update the log handlers
421  if (entry.second.handlers.hasValue()) {
422  auto catHandlers = buildCategoryHandlerList(
423  handlers, entry.first, entry.second.handlers.value());
424  category->replaceHandlers(std::move(catHandlers));
425  }
426 
427  // Update the level settings
428  category->setLevelLocked(
429  entry.second.level, entry.second.inheritParentLevel);
430  }
431 
432  finishConfigUpdate(handlerInfo, &handlers, &oldToNewHandlerMap);
433 }
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
std::unordered_map< std::shared_ptr< LogHandler >, std::shared_ptr< LogHandler >> OldToNewHandlerMap
Definition: LoggerDB.h:257
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::vector< std::shared_ptr< LogHandler > > buildCategoryHandlerList(const NewHandlerMap &handlerMap, StringPiece categoryName, const std::vector< std::string > &categoryHandlerNames)
Definition: LoggerDB.cpp:372
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
AHArrayT::Config config
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
void startConfigUpdate(const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, const LogConfig &config, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
Definition: LoggerDB.cpp:237
void finishConfigUpdate(const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
Definition: LoggerDB.cpp:346
std::unordered_map< std::string, std::shared_ptr< LogHandler >> NewHandlerMap
Definition: LoggerDB.h:255
LogLevel folly::LoggerDB::xlogInit ( folly::StringPiece  categoryName,
std::atomic< LogLevel > *  xlogCategoryLevel,
LogCategory **  xlogCategory 
)

Initialize the LogCategory* and std::atomic<LogLevel> used by an XLOG() statement.

Returns the current effective LogLevel of the category.

Definition at line 597 of file LoggerDB.cpp.

References folly::LogCategory::getEffectiveLevel(), getOrCreateCategoryLocked(), and loggersByName_.

Referenced by folly::XlogCategoryInfo< IsInHeaderFile >::init(), and folly::XlogLevelInfo< IsInHeaderFile >::loadLevelFull().

600  {
601  // Hold the lock for the duration of the operation
602  // xlogInit() may be called from multiple threads simultaneously.
603  // Only one needs to perform the initialization.
604  auto loggersByName = loggersByName_.wlock();
605  if (xlogCategory != nullptr && *xlogCategory != nullptr) {
606  // The xlogCategory was already initialized before we acquired the lock
607  return (*xlogCategory)->getEffectiveLevel();
608  }
609 
610  auto* category = getOrCreateCategoryLocked(*loggersByName, categoryName);
611  if (xlogCategory) {
612  // Set *xlogCategory before we update xlogCategoryLevel below.
613  // This is important, since the XLOG() macros check xlogCategoryLevel to
614  // tell if *xlogCategory has been initialized yet.
615  *xlogCategory = category;
616  }
617  auto level = category->getEffectiveLevel();
618  xlogCategoryLevel->store(level, std::memory_order_release);
619  category->registerXlogLevel(xlogCategoryLevel);
620  return level;
621 }
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288
LogCategory * folly::LoggerDB::xlogInitCategory ( folly::StringPiece  categoryName,
LogCategory **  xlogCategory,
std::atomic< bool > *  isInitialized 
)

Definition at line 623 of file LoggerDB.cpp.

References getOrCreateCategoryLocked(), loggersByName_, and warningHandler_.

Referenced by folly::XlogCategoryInfo< IsInHeaderFile >::init().

626  {
627  // Hold the lock for the duration of the operation
628  // xlogInitCategory() may be called from multiple threads simultaneously.
629  // Only one needs to perform the initialization.
630  auto loggersByName = loggersByName_.wlock();
631  if (isInitialized->load(std::memory_order_acquire)) {
632  // The xlogCategory was already initialized before we acquired the lock
633  return *xlogCategory;
634  }
635 
636  auto* category = getOrCreateCategoryLocked(*loggersByName, categoryName);
637  *xlogCategory = category;
638  isInitialized->store(true, std::memory_order_release);
639  return category;
640 }
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
folly::Synchronized< LoggerNameMap > loggersByName_
Definition: LoggerDB.h:288

Member Data Documentation

folly::Synchronized<HandlerInfo> folly::LoggerDB::handlerInfo_
private

The LogHandlers and LogHandlerFactories.

For lock ordering purposes, if you need to acquire both the loggersByName_ and handlerInfo_ locks, the handlerInfo_ lock must be acquired first.

Definition at line 296 of file LoggerDB.h.

Referenced by cleanupHandlers(), getConfigImpl(), registerHandlerFactory(), resetConfig(), unregisterHandlerFactory(), and updateConfig().

folly::Synchronized<LoggerNameMap> folly::LoggerDB::loggersByName_
private

A map of LogCategory objects by name.

Lookups can be performed using arbitrary StringPiece values that do not have to be in canonical form.

Definition at line 288 of file LoggerDB.h.

Referenced by cleanupHandlers(), flushAllHandlers(), getCategory(), getCategoryOrNull(), getConfigImpl(), resetConfig(), setLevel(), updateConfig(), xlogInit(), and xlogInitCategory().

std::atomic< LoggerDB::InternalWarningHandler > folly::LoggerDB::warningHandler_
staticprivate

Definition at line 298 of file LoggerDB.h.

Referenced by internalWarningImpl(), setInternalWarningHandler(), and xlogInitCategory().


The documentation for this class was generated from the following files: