category->setLevelLocked(level, inherit);
}
-std::vector<std::string> LoggerDB::processConfigString(
- folly::StringPiece config) {
- std::vector<std::string> errors;
- if (config.empty()) {
- return errors;
- }
-
- std::vector<StringPiece> pieces;
- folly::split(",", config, pieces);
- for (const auto& p : pieces) {
- auto idx = p.rfind('=');
- if (idx == folly::StringPiece::npos) {
- errors.emplace_back(
- folly::sformat("missing '=' in logger configuration: \"{}\"", p));
- continue;
- }
-
- auto category = p.subpiece(0, idx);
- auto level_str = p.subpiece(idx + 1);
- LogLevel level;
- try {
- level = stringToLogLevel(level_str);
- } catch (const std::exception&) {
- errors.emplace_back(folly::sformat(
- "invalid log level \"{}\" for category \"{}\"", level_str, category));
- continue;
- }
-
- setLevel(category, level);
- }
-
- return errors;
-}
-
LogConfig LoggerDB::getConfig() const {
auto handlerInfo = handlerInfo_.rlock();
// Create all of the new LogHandlers needed from this configuration
for (const auto& entry : config.getHandlerConfigs()) {
- // Look up the LogHandlerFactory
- auto factoryIter = handlerInfo->factories.find(entry.second.type);
- if (factoryIter == handlerInfo->factories.end()) {
- throw std::invalid_argument(to<std::string>(
- "unknown log handler type \"", entry.second.type, "\""));
- }
-
// Check to see if there is an existing LogHandler with this name
std::shared_ptr<LogHandler> oldHandler;
auto iter = handlers->find(entry.first);
oldHandler = iter->second;
}
+ LogHandlerConfig updatedConfig;
+ const LogHandlerConfig* handlerConfig;
+ if (entry.second.type.hasValue()) {
+ handlerConfig = &entry.second;
+ } else {
+ // This configuration is intended to update an existing LogHandler
+ if (!oldHandler) {
+ throw std::invalid_argument(to<std::string>(
+ "cannot update unknown log handler \"", entry.first, "\""));
+ }
+
+ updatedConfig = oldHandler->getConfig();
+ if (!updatedConfig.type.hasValue()) {
+ // This normally should not happen unless someone improperly manually
+ // constructed a LogHandler object. All existing LogHandler objects
+ // should indicate their type.
+ throw std::invalid_argument(to<std::string>(
+ "existing log handler \"",
+ entry.first,
+ "\" is missing type information"));
+ }
+ updatedConfig.update(entry.second);
+ handlerConfig = &updatedConfig;
+ }
+
+ // Look up the LogHandlerFactory
+ auto factoryIter = handlerInfo->factories.find(handlerConfig->type.value());
+ if (factoryIter == handlerInfo->factories.end()) {
+ throw std::invalid_argument(to<std::string>(
+ "unknown log handler type \"", handlerConfig->type.value(), "\""));
+ }
+
// Create the new log handler
const auto& factory = factoryIter->second;
std::shared_ptr<LogHandler> handler;
- if (oldHandler) {
- handler = factory->updateHandler(oldHandler, entry.second.options);
- if (handler != oldHandler) {
- oldToNewHandlerMap->emplace(oldHandler, handler);
+ try {
+ if (oldHandler) {
+ handler = factory->updateHandler(oldHandler, handlerConfig->options);
+ if (handler != oldHandler) {
+ oldToNewHandlerMap->emplace(oldHandler, handler);
+ }
+ } else {
+ handler = factory->createHandler(handlerConfig->options);
}
- } else {
- handler = factory->createHandler(entry.second.options);
+ } catch (const std::exception& ex) {
+ // Errors creating or updating the the log handler are generally due to
+ // bad configuration options. It is useful to update the exception
+ // message to include the name of the log handler we were trying to
+ // update or create.
+ throw std::invalid_argument(to<string>(
+ "error ",
+ oldHandler ? "updating" : "creating",
+ " log handler \"",
+ entry.first,
+ "\": ",
+ exceptionStr(ex)));
}
handlerInfo->handlers[entry.first] = handler;
(*handlers)[entry.first] = handler;