Skip to content

Commit 7e20016

Browse files
Vrishal Kulkarnimeta-codesync[bot]
authored andcommitted
Log duplicate string map option keys
Summary: Review context This child responds to the following comment from Anton (`alikhtarov`) on D113813215: > Consider logging on duplicates/empty keys to MC_FAILURES or similar What this addresses: `parseStringMapOption()` resolves duplicate keys silently — regular `string_map` options keep the first value, `--additional-config-params` keeps the last. Neither policy surfaced the discarded value, so a config typo, or a template that substitutes into a key already present (e.g. `%PROC_NAME%:a,cmd:b` when the process is named `cmd`), just disappeared. Duplicates are now logged as a `Category::kInvalidOption` failure naming the key, the value used, and the value ignored. Detection uses a `find()` before insert instead of branching between `emplace()` and `insert_or_assign()`, so both parsing policies share one log statement. Which value wins is unchanged. Where these land, and a caveat: `LOG_FAILURE` reaches `mc_failures` through `ScubaFailureLogger` once `initFailureLogger()` has registered the `scubaMcFailure` handler. String map options are parsed before that point — `updateFromDict()` and the `--additional-config-params` merge both run earlier in `setupStandaloneMcrouter()`, and embedded clients build `McrouterOptions` before `CarbonRouterInstance::init()`. So at standalone startup these reach stderr/glog, not scuba. That is the same behavior as every other option-parse failure: the `Unknown option name` `LOG_FAILURE` in `updateFromDict()` has the identical ordering. I prototyped deferring just these reports through a collect-and-flush helper, but it meant process-wide state and a lock that no other log site here needs, for one call site. The fix that actually pays for itself is buffering pre-handler failures inside `LogFailure` and replaying them to handlers as they register, which fixes the whole class at once — happy to write that as a follow-up if you want duplicates in scuba specifically. What this does not address: Empty pairs, the other half of the comment. They already throw for regular `string_map` options; the silent skip is limited to `--additional-config-params`. Happy to add that too. Reviewed By: djvaporize Differential Revision: D114799408 fbshipit-source-id: 76daf3d0029f7aed85e56f2901db91fb504fc556
1 parent 95c4ee0 commit 7e20016

1 file changed

Lines changed: 14 additions & 3 deletions

File tree

mcrouter/options.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,21 @@ unordered_map<string, string> parseStringMapOption(
5151
auto key = substituteTemplates(pair.subpiece(0, delimiter).str());
5252
checkLogic(!key.empty(), "Empty key in string map pair: '{}'.", pair);
5353
auto value = substituteTemplates(pair.subpiece(delimiter + 1).str());
54-
if (parseOptions.overwriteDuplicateKeys) {
55-
result.insert_or_assign(std::move(key), std::move(value));
56-
} else {
54+
auto duplicate = result.find(key);
55+
if (duplicate == result.end()) {
5756
result.emplace(std::move(key), std::move(value));
57+
continue;
58+
}
59+
const bool overwrite = parseOptions.overwriteDuplicateKeys;
60+
LOG_FAILURE(
61+
"mcrouter",
62+
failure::Category::kInvalidOption,
63+
"Duplicate key '{}' in string map option: using value '{}', ignoring '{}'.",
64+
key,
65+
overwrite ? value : duplicate->second,
66+
overwrite ? duplicate->second : value);
67+
if (overwrite) {
68+
duplicate->second = std::move(value);
5869
}
5970
}
6071
return result;

0 commit comments

Comments
 (0)