25 using std::shared_ptr;
37 switch (value.type()) {
53 return "unknown type";
70 if (value.isString()) {
71 auto levelString = value.asString();
75 }
catch (
const std::exception&) {
76 throw LogConfigParseError{to<string>(
77 "invalid log level \"",
83 }
else if (value.isInt()) {
84 auto level =
static_cast<LogLevel>(value.asInt());
86 throw LogConfigParseError{to<string>(
91 "\": outside of valid range")};
100 LogCategoryConfig parseJsonCategoryConfig(
101 const dynamic& value,
107 if (!value.isObject()) {
108 if (!parseJsonLevel(value, categoryName, config.level)) {
109 throw LogConfigParseError{to<string>(
110 "unexpected data type for configuration of category \"",
113 dynamicTypename(value),
114 ", expected an object, string, or integer")};
119 auto* level = value.get_ptr(
"level");
122 throw LogConfigParseError{to<string>(
123 "no log level specified for category \"", categoryName,
"\"")};
125 if (!parseJsonLevel(*level, categoryName, config.level)) {
126 throw LogConfigParseError{to<string>(
127 "unexpected data type for level field of category \"",
130 dynamicTypename(*level),
131 ", expected a string or integer")};
134 auto* inherit = value.get_ptr(
"inherit");
136 if (!inherit->isBool()) {
137 throw LogConfigParseError{to<string>(
138 "unexpected data type for inherit field of category \"",
141 dynamicTypename(*inherit),
142 ", expected a boolean")};
144 config.inheritParentLevel = inherit->asBool();
147 auto* handlers = value.get_ptr(
"handlers");
149 if (!handlers->isArray()) {
150 throw LogConfigParseError{to<string>(
151 "the \"handlers\" field for category ",
155 config.handlers = std::vector<std::string>{};
156 for (
const auto& item : *handlers) {
157 if (!item.isString()) {
158 throw LogConfigParseError{to<string>(
159 "the \"handlers\" list for category ",
161 " must be contain only strings")};
163 config.handlers->push_back(item.asString());
170 LogHandlerConfig parseJsonHandlerConfig(
171 const dynamic& value,
173 if (!value.isObject()) {
174 throw LogConfigParseError{to<string>(
175 "unexpected data type for configuration of handler \"",
178 dynamicTypename(value),
179 ", expected an object")};
183 auto*
type = value.get_ptr(
"type");
185 throw LogConfigParseError{to<string>(
186 "no handler type specified for log handler \"", handlerName,
"\"")};
188 if (!type->isString()) {
189 throw LogConfigParseError{to<string>(
190 "unexpected data type for \"type\" field of handler \"",
193 dynamicTypename(*type),
194 ", expected a string")};
196 LogHandlerConfig config{type->asString()};
199 auto* options = value.get_ptr(
"options");
201 if (!options->isObject()) {
202 throw LogConfigParseError{to<string>(
203 "unexpected data type for \"options\" field of handler \"",
206 dynamicTypename(*options),
207 ", expected an object")};
210 for (
const auto& item : options->items()) {
211 if (!item.first.isString()) {
214 throw LogConfigParseError{to<string>(
215 "unexpected data type for option of handler \"",
218 dynamicTypename(item.first),
219 ", expected string")};
221 if (!item.second.isString()) {
222 throw LogConfigParseError{to<string>(
223 "unexpected data type for option \"",
224 item.first.asString(),
228 dynamicTypename(item.second),
229 ", expected a string")};
231 config.options[item.first.asString()] = item.second.asString();
244 return categoryConfigs;
247 std::unordered_map<string, string> seenCategories;
248 std::vector<StringPiece> pieces;
250 for (
const auto& piece : pieces) {
251 LogCategoryConfig categoryConfig;
255 auto equalIndex = piece.
find(
'=');
262 categoryName = piece.subpiece(0, equalIndex);
263 configString = piece.subpiece(equalIndex + 1);
267 if (categoryName.endsWith(
':')) {
268 categoryConfig.inheritParentLevel =
false;
269 categoryName.subtract(1);
277 std::vector<StringPiece> handlerPieces;
280 handlerPieces.size() >= 1,
281 "folly::split() always returns a list of length 1");
284 bool hasHandlerConfig = handlerPieces.size() > 1;
289 categoryConfig.handlers = std::vector<std::string>{};
290 }
else if (hasHandlerConfig) {
291 categoryConfig.handlers = std::vector<std::string>{};
292 for (
size_t n = 1; n < handlerPieces.size(); ++n) {
294 if (handlerName.empty()) {
295 throw LogConfigParseError{to<string>(
296 "error parsing configuration for log category \"",
298 "\": log handler name cannot be empty")};
300 categoryConfig.handlers->push_back(handlerName.str());
308 }
catch (
const std::exception&) {
309 throw LogConfigParseError{to<string>(
310 "invalid log level \"",
312 "\" for category \"",
320 auto ret = seenCategories.emplace(canonicalName, categoryName.str());
322 throw LogConfigParseError{to<string>(
325 "\" listed multiple times under different names: \"",
333 categoryConfigs.emplace(canonicalName,
std::move(categoryConfig));
335 emplaceResult.second,
336 "category name must be new since it was not in seenCategories");
339 return categoryConfigs;
346 size_t equalIndex = input.find(
'=');
359 std::pair<std::string, LogHandlerConfig> parseHandlerConfig(
StringPiece value) {
361 auto colonIndex = value.find(
':');
372 Optional<StringPiece> handlerType(
in_place);
373 if (!splitNameValue(namePortion, &handlerName, &handlerType.value())) {
382 if (handlerName.empty()) {
383 throw LogConfigParseError{
384 "error parsing log handler configuration: empty log handler name"};
386 if (handlerName.contains(
',')) {
387 throw LogConfigParseError{to<string>(
388 "error parsing configuration for log handler \"",
390 "\": name cannot contain a comma when using the basic config format")};
392 if (handlerType.hasValue()) {
393 if (handlerType->empty()) {
394 throw LogConfigParseError{to<string>(
395 "error parsing configuration for log handler \"",
397 "\": empty log handler type")};
399 if (handlerType->contains(
',')) {
400 throw LogConfigParseError{to<string>(
401 "error parsing configuration for log handler \"",
403 "\": invalid type \"",
405 "\": type name cannot contain a comma when using " 406 "the basic config format")};
411 LogHandlerConfig config{handlerType};
413 if (!optionsStr.empty()) {
414 std::vector<StringPiece> pieces;
417 pieces.size() >= 1,
"folly::split() always returns a list of length 1");
419 for (
const auto& piece : pieces) {
422 if (!splitNameValue(piece, &optionName, &optionValue)) {
423 throw LogConfigParseError{to<string>(
424 "error parsing configuration for log handler \"",
426 "\": options must be of the form NAME=VALUE")};
429 auto ret = config.options.emplace(optionName.str(), optionValue.str());
431 throw LogConfigParseError{to<string>(
432 "error parsing configuration for log handler \"",
434 "\": duplicate configuration for option \"",
441 return std::make_pair(handlerName.str(),
std::move(config));
455 std::vector<StringPiece> pieces;
458 pieces.size() >= 1,
"folly::split() always returns a list of length 1");
460 auto categoryConfigs = parseCategoryConfigs(pieces[0]);
462 for (
size_t n = 1; n < pieces.size(); ++n) {
463 auto handlerInfo = parseHandlerConfig(pieces[n]);
464 auto ret = handlerConfigs.emplace(
465 handlerInfo.first,
std::move(handlerInfo.second));
468 "configuration for log category \"",
470 "\" specified multiple times")};
489 std::unordered_map<string, string> seenCategories;
491 auto* categories = value.
get_ptr(
"categories");
493 if (!categories->isObject()) {
495 "unexpected data type for log categories config: got ",
496 dynamicTypename(*categories),
497 ", expected an object")};
500 for (
const auto& entry : categories->items()) {
501 if (!entry.first.isString()) {
506 auto categoryName = entry.first.asString();
507 auto categoryConfig = parseJsonCategoryConfig(entry.second, categoryName);
512 auto ret = seenCategories.emplace(canonicalName, categoryName);
517 "\" listed multiple times under different names: \"",
524 categoryConfigs[canonicalName] =
std::move(categoryConfig);
529 auto* handlers = value.
get_ptr(
"handlers");
531 if (!handlers->isObject()) {
533 "unexpected data type for log handlers config: got ",
534 dynamicTypename(*handlers),
535 ", expected an object")};
538 for (
const auto& entry : handlers->items()) {
539 if (!entry.first.isString()) {
544 auto handlerName = entry.first.asString();
545 handlerConfigs.emplace(
546 handlerName, parseJsonHandlerConfig(entry.second, handlerName));
570 for (
const auto& opt : config.
options) {
571 options.
insert(opt.first, opt.second);
586 handlers.push_back(handlerName);
static ObjectMaker object()
dynamic parseJson(StringPiece range)
const CategoryConfigMap & getCategoryConfigs() const
constexpr detail::Map< Move > move
size_type find(const_range_type str) const
Optional< std::vector< std::string > > handlers
std::string stripComments(StringPiece jsonC)
—— Concurrent Priority Queue Implementation ——
in_place_tag in_place(in_place_tag={})
LogConfig parseLogConfig(StringPiece value)
Optional< std::string > type
LogLevel stringToLogLevel(StringPiece name)
string logLevelToString(LogLevel level)
void split(const Delim &delimiter, const String &input, std::vector< OutputType > &out, bool ignoreEmpty)
constexpr bool empty() const
std::unordered_map< std::string, LogCategoryConfig > CategoryConfigMap
static std::string canonicalize(folly::StringPiece name)
bool allow_trailing_comma
FOLLY_CPP14_CONSTEXPR bool hasValue() const noexcept
void insert(K &&, V &&val)
LogConfig parseLogConfigDynamic(const dynamic &value)
std::unordered_map< std::string, LogHandlerConfig > HandlerConfigMap
constexpr Iter begin() const
bool startsWith(const const_range_type &other) const
static const size_type npos
dynamic logConfigToDynamic(const LogConfig &config)
static void array(EmptyArrayTag)
StringPiece trimWhitespace(StringPiece sp)
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
const HandlerConfigMap & getHandlerConfigs() const
FOLLY_CPP14_CONSTEXPR const Value & value() const &
LogConfig parseLogConfigJson(StringPiece value)
Range< const char * > StringPiece
#define FOLLY_SAFE_DCHECK(expr, msg)
const dynamic * get_ptr(json_pointer const &) const &