#include <folly/experimental/logging/LogCategory.h>
#include <cstdio>
+#include <cstdlib>
#include <folly/ExceptionString.h>
+#include <folly/FileUtil.h>
#include <folly/experimental/logging/LogHandler.h>
#include <folly/experimental/logging/LogMessage.h>
#include <folly/experimental/logging/LogName.h>
parent_->firstChild_ = this;
}
+void LogCategory::admitMessage(const LogMessage& message) const {
+ processMessage(message);
+
+ // If this is a fatal message, flush the handlers to make sure the log
+ // message was written out, then crash.
+ if (isLogLevelFatal(message.getLevel())) {
+ auto numHandlers = db_->flushAllHandlers();
+ if (numHandlers == 0) {
+ // No log handlers were configured.
+ // Print the message to stderr, to make sure we always print the reason
+ // we are crashing somewhere.
+ auto msg = folly::to<std::string>(
+ "FATAL:",
+ message.getFileName(),
+ ":",
+ message.getLineNumber(),
+ ": ",
+ message.getMessage(),
+ "\n");
+ folly::writeFull(STDERR_FILENO, msg.data(), msg.size());
+ }
+ std::abort();
+ }
+}
+
void LogCategory::processMessage(const LogMessage& message) const {
// Make a copy of any attached LogHandlers, so we can release the handlers_
// lock before holding them.
for (size_t n = 0; n < numHandlers; ++n) {
try {
- handlers[n]->log(message, this);
+ handlers[n]->handleMessage(message, this);
} catch (const std::exception& ex) {
- // If a LogHandler throws an exception, complain about this fact on
- // stderr to avoid swallowing the error information completely. We
- // don't propagate the exception up to our caller: most code does not
- // prepare for log statements to throw. We also want to continue
- // trying to log the message to any other handlers attached to ourself
- // or one of our parent categories.
- fprintf(
- stderr,
- "WARNING: log handler for category %s threw an error: %s\n",
- name_.c_str(),
- folly::exceptionStr(ex).c_str());
+ // Use LoggerDB::internalWarning() to report the error, but continue
+ // trying to log the message to any other handlers attached to ourself or
+ // one of our parent categories.
+ LoggerDB::internalWarning(
+ __FILE__,
+ __LINE__,
+ "log handler for category \"",
+ name_,
+ "\" threw an error: ",
+ folly::exceptionStr(ex));
}
}
// LogHandler destructors.
}
+std::vector<std::shared_ptr<LogHandler>> LogCategory::getHandlers() const {
+ return *(handlers_.rlock());
+}
+
void LogCategory::setLevel(LogLevel level, bool inherit) {
// We have to set the level through LoggerDB, since we require holding
// the LoggerDB lock to iterate through our children in case our effective
}
void LogCategory::setLevelLocked(LogLevel level, bool inherit) {
- // Truncate to LogLevel::MAX_LEVEL to make sure it does not conflict
- // with our flag bits.
+ // Clamp the value to MIN_LEVEL and MAX_LEVEL.
+ //
+ // This makes sure that UNINITIALIZED is always less than any valid level
+ // value, and that level values cannot conflict with our flag bits.
if (level > LogLevel::MAX_LEVEL) {
level = LogLevel::MAX_LEVEL;
+ } else if (level < LogLevel::MIN_LEVEL) {
+ level = LogLevel::MIN_LEVEL;
}
+
// Make sure the inherit flag is always off for the root logger.
if (!parent_) {
inherit = false;
return;
}
+ // Update all of the values in xlogLevels_
+ for (auto* levelPtr : xlogLevels_) {
+ levelPtr->store(newEffectiveLevel, std::memory_order_release);
+ }
+
// Update all children loggers
LogCategory* child = firstChild_;
while (child != nullptr) {
auto newEffectiveLevel = std::min(myLevel, parentEffectiveLevel);
updateEffectiveLevel(newEffectiveLevel);
}
+
+void LogCategory::registerXlogLevel(std::atomic<LogLevel>* levelPtr) {
+ xlogLevels_.push_back(levelPtr);
+}
}