proxygen
LoggerDB.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <folly/logging/LoggerDB.h>
17 
18 #include <set>
19 
20 #include <folly/CPortability.h>
21 #include <folly/Conv.h>
22 #include <folly/FileUtil.h>
23 #include <folly/String.h>
28 #include <folly/logging/LogLevel.h>
29 #include <folly/logging/Logger.h>
32 
33 using std::string;
34 
35 namespace folly {
36 
37 /*
38  * The default implementation of initializeLoggerDB().
39  *
40  * This is defined as a weak symbol to allow programs to provide their own
41  * alternative definition if desired.
42  */
44  // Register the StreamHandlerFactory
45  //
46  // This is the only LogHandlerFactory that we register by default. We
47  // intentionally do not register FileHandlerFactory, since this allows
48  // LoggerDB::updateConfig() to open and write to arbitrary files. This is
49  // potentially a security concern if programs accept user-customizable log
50  // configuration settings from untrusted sources.
51  //
52  // Users can always register additional LogHandlerFactory objects on their
53  // own inside their main() function.
54  db.registerHandlerFactory(std::make_unique<StreamHandlerFactory>());
55 
56  // Build a default LogConfig object.
57  // This writes messages to stderr synchronously (immediately, in the thread
58  // that generated the message), using the default GLOG-style formatter.
59  auto defaultHandlerConfig =
60  LogHandlerConfig("stream", {{"stream", "stderr"}, {"async", "false"}});
61  auto rootCategoryConfig =
62  LogCategoryConfig(kDefaultLogLevel, false, {"default"});
64  /* handlerConfigs */ {{"default", defaultHandlerConfig}},
65  /* categoryConfig */ {{"", rootCategoryConfig}});
66 
67  // Update the configuration
68  db.updateConfig(config);
69 }
70 
71 namespace {
72 class LoggerDBSingleton {
73  public:
74  explicit LoggerDBSingleton(LoggerDB* FOLLY_NONNULL db) : db_{db} {
75  // Call initializeLoggerDB() to apply some basic initial configuration.
77  }
78 
79  ~LoggerDBSingleton() {
80  // We intentionally leak the LoggerDB object on normal destruction.
81  // We want Logger objects to remain valid for the entire lifetime of the
82  // program, without having to worry about destruction ordering issues, or
83  // making the Logger perform reference counting on the LoggerDB.
84  //
85  // Therefore the main LoggerDB object, and all of the LogCategory objects
86  // it contains, are always intentionally leaked.
87  //
88  // However, we do call db_->cleanupHandlers() to destroy any registered
89  // LogHandler objects. The LogHandlers can be user-defined objects and may
90  // hold resources that should be cleaned up. This also ensures that the
91  // LogHandlers flush all outstanding messages before we exit.
92  db_->cleanupHandlers();
93 
94  // Store the released pointer in a static variable just to prevent ASAN
95  // from complaining that we are leaking data.
96  static LoggerDB* db = db_.release();
97  (void)db;
98  }
99 
100  LoggerDB& getDB() const {
101  return *db_;
102  }
103 
104  private:
105  // Store LoggerDB as a unique_ptr so it will be automatically destroyed if
106  // initializeLoggerDB() throws in the constructor. We will explicitly
107  // release this during the normal destructor.
108  std::unique_ptr<LoggerDB> db_;
109 };
110 } // namespace
111 
113  // Intentionally leaky singleton
114  static LoggerDBSingleton singleton{new LoggerDB()};
115  return singleton.getDB();
116 }
117 
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 }
128 
130 
132 
135 }
136 
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 }
146 
148  auto loggersByName = loggersByName_.wlock();
149  LogCategory* category = getOrCreateCategoryLocked(*loggersByName, name);
150  category->setLevelLocked(level, inherit);
151 }
152 
153 void LoggerDB::setLevel(LogCategory* category, LogLevel level, bool inherit) {
154  auto loggersByName = loggersByName_.wlock();
155  category->setLevelLocked(level, inherit);
156 }
157 
159  return getConfigImpl(/* includeAllCategories = */ false);
160 }
161 
163  return getConfigImpl(/* includeAllCategories = */ true);
164 }
165 
166 LogConfig LoggerDB::getConfigImpl(bool includeAllCategories) const {
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 }
233 
238  const Synchronized<HandlerInfo>::LockedPtr& handlerInfo,
239  const LogConfig& config,
240  NewHandlerMap* handlers,
241  OldToNewHandlerMap* oldToNewHandlerMap) {
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 }
342 
347  const Synchronized<HandlerInfo>::LockedPtr& handlerInfo,
348  NewHandlerMap* handlers,
349  OldToNewHandlerMap* oldToNewHandlerMap) {
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 }
371 
372 std::vector<std::shared_ptr<LogHandler>> LoggerDB::buildCategoryHandlerList(
373  const NewHandlerMap& handlerMap,
374  StringPiece categoryName,
375  const std::vector<std::string>& categoryHandlerNames) {
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 }
394 
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 }
434 
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 }
495 
497  LoggerNameMap& loggersByName,
498  StringPiece name) {
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 }
508 
510  LoggerNameMap& loggersByName,
512  LogCategory* parent) {
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 }
519 
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 }
550 
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 }
571 
573  std::unique_ptr<LogHandlerFactory> factory,
574  bool replaceExisting) {
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 }
587 
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 }
596 
598  StringPiece categoryName,
599  std::atomic<LogLevel>* xlogCategoryLevel,
600  LogCategory** xlogCategory) {
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 }
622 
624  StringPiece categoryName,
625  LogCategory** xlogCategory,
626  std::atomic<bool>* isInitialized) {
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 }
641 
642 std::atomic<LoggerDB::InternalWarningHandler> LoggerDB::warningHandler_;
643 
645  folly::StringPiece filename,
646  int lineNumber,
647  std::string&& msg) noexcept {
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 }
655 
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 }
678 
680  folly::StringPiece filename,
681  int lineNumber,
682  std::string&& msg) noexcept {
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 }
714 } // namespace folly
folly::Synchronized< HandlerInfo > handlerInfo_
Definition: LoggerDB.h:296
#define FOLLY_ATTR_WEAK
Definition: CPortability.h:167
FOLLY_ATTR_WEAK void initializeLoggerDB(LoggerDB &db)
Definition: LoggerDB.cpp:43
void unregisterHandlerFactory(folly::StringPiece type)
Definition: LoggerDB.cpp:588
static folly::StringPiece getParent(folly::StringPiece name)
Definition: LogName.cpp:126
std::string str() const
Definition: Range.h:591
LogCategory * getCategory(folly::StringPiece name)
Definition: LoggerDB.cpp:133
constexpr auto kIsDebug
Definition: Portability.h:264
static Singleton< ShutdownSocketSet, PrivateTag > singleton
void swap(Synchronized &rhs)
Definition: Synchronized.h:684
std::unordered_map< std::shared_ptr< LogHandler >, std::shared_ptr< LogHandler >> OldToNewHandlerMap
Definition: LoggerDB.h:257
void setLevelLocked(LogLevel level, bool inherit)
PskType type
const CategoryConfigMap & getCategoryConfigs() const
Definition: LogConfig.h:45
static void internalWarningImpl(folly::StringPiece filename, int lineNumber, std::string &&msg) noexcept
Definition: LoggerDB.cpp:644
fbstring exceptionStr(const std::exception &e)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::unordered_map< std::string, std::unique_ptr< LogHandlerFactory >> HandlerFactoryMap
Definition: LoggerDB.h:234
std::vector< std::shared_ptr< LogHandler > > buildCategoryHandlerList(const NewHandlerMap &handlerMap, StringPiece categoryName, const std::vector< std::string > &categoryHandlerNames)
Definition: LoggerDB.cpp:372
#define FOLLY_NULLABLE
LogCategory * getOrCreateCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name)
Definition: LoggerDB.cpp:496
LogConfig getConfig() const
Definition: LoggerDB.cpp:158
LogCategory * xlogInitCategory(folly::StringPiece categoryName, LogCategory **xlogCategory, std::atomic< bool > *isInitialized)
Definition: LoggerDB.cpp:623
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
void resetConfig(const LogConfig &config)
Definition: LoggerDB.cpp:435
Optional< std::string > type
AHArrayT::Config config
void handler(int, siginfo_t *, void *)
typename Base::LockedPtr LockedPtr
Definition: Synchronized.h:453
const char * name
Definition: http_parser.c:437
LogCategory * createCategoryLocked(LoggerNameMap &loggersByName, folly::StringPiece name, LogCategory *parent)
Definition: LoggerDB.cpp:509
std::unordered_map< std::string, std::weak_ptr< LogHandler >> HandlerMap
Definition: LoggerDB.h:235
std::unordered_map< std::string, LogCategoryConfig > CategoryConfigMap
Definition: LogConfig.h:35
std::unique_ptr< LoggerDB > db_
Definition: LoggerDB.cpp:108
void updateConfig(const LogConfig &config)
Definition: LoggerDB.cpp:395
LogLevel xlogInit(folly::StringPiece categoryName, std::atomic< LogLevel > *xlogCategoryLevel, LogCategory **xlogCategory)
Definition: LoggerDB.cpp:597
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
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
Definition: Optional.h:300
ssize_t writeFull(int fd, const void *buf, size_t count)
Definition: FileUtil.cpp:134
void finishConfigUpdate(const Synchronized< HandlerInfo >::LockedPtr &handlerInfo, NewHandlerMap *handlers, OldToNewHandlerMap *oldToNewHandlerMap)
Definition: LoggerDB.cpp:346
static void defaultInternalWarningImpl(folly::StringPiece filename, int lineNumber, std::string &&msg) noexcept
Definition: LoggerDB.cpp:679
LogLevel
Definition: LogLevel.h:38
LogCategory *FOLLY_NULLABLE getCategoryOrNull(folly::StringPiece name)
Definition: LoggerDB.cpp:137
std::unordered_map< std::string, LogHandlerConfig > HandlerConfigMap
Definition: LogConfig.h:36
static void setInternalWarningHandler(InternalWarningHandler handler)
Definition: LoggerDB.cpp:656
const char * string
Definition: Conv.cpp:212
void setLevel(folly::StringPiece name, LogLevel level, bool inherit=true)
Definition: LoggerDB.cpp:147
#define FOLLY_NONNULL
void cleanupHandlers()
Definition: LoggerDB.cpp:520
static std::atomic< InternalWarningHandler > warningHandler_
Definition: LoggerDB.h:298
LogLevel getEffectiveLevel() const
Definition: LogCategory.h:95
const HandlerConfigMap & getHandlerConfigs() const
Definition: LogConfig.h:48
void replaceHandlers(std::vector< std::shared_ptr< LogHandler >> handlers)
void registerHandlerFactory(std::unique_ptr< LogHandlerFactory > factory, bool replaceExisting=false)
Definition: LoggerDB.cpp:572
FOLLY_CPP14_CONSTEXPR const Value & value() const &
Definition: Optional.h:268
size_t flushAllHandlers()
Definition: LoggerDB.cpp:551
void(*)(folly::StringPiece file, int lineNumber, std::string &&) InternalWarningHandler
Definition: LoggerDB.h:210
LogConfig getConfigImpl(bool includeAllCategories) const
Definition: LoggerDB.cpp:166
void update(const LogHandlerConfig &other)
LogConfig getFullConfig() const
Definition: LoggerDB.cpp:162
folly::Function< void()> parent
Definition: AtFork.cpp:34
std::unordered_map< folly::StringPiece, std::unique_ptr< LogCategory >, LogName::Hash, LogName::Equals > LoggerNameMap
Definition: LoggerDB.h:231
std::unordered_map< std::string, std::shared_ptr< LogHandler >> NewHandlerMap
Definition: LoggerDB.h:255
static LoggerDB & get()
Definition: LoggerDB.cpp:112