Repository: kudu Updated Branches: refs/heads/master 337a731c4 -> 00c2754ca
Add GetFlags endpoint and tool This adds an rpc endpoint that retrieves gflags from servers. It also includes a tool for retrieving flag values from servers. By default, it returns only flags with non-default values. It supports returning all flags, and also filtering flags by tags. Example output from the tool run against a local cluster's master: flag | value | default? | tags ------------------------+-----------------------------------------------+----------+----------------- log_dir | /tmp/kudu/logs/master/0 | false | stable heap_profile_path | /tmp/kudu-master.56285 | false | advanced,stable log_filename | kudu-master | false | stable webserver_interface | 127.0.0.1 | false | advanced master_addresses | 127.0.0.1:7053,127.0.0.1:7052,127.0.0.1:7051, | false | stable fs_data_dirs | /tmp/kudu/data/master/0/0 | false | stable rpc_bind_addresses | 127.0.0.1:7051 | false | stable fs_wal_dir | /tmp/kudu/wal/master/0 | false | stable evict_failed_followers | false | false | advanced webserver_port | 8051 | false | stable The rpc endpoint will also be used by ksck in a follow-up. Change-Id: Ia35b4261099c1a3c6e2ff68e907c84df9a7ff699 Reviewed-on: http://gerrit.cloudera.org:8080/9948 Tested-by: Kudu Jenkins Reviewed-by: Adar Dembo <a...@cloudera.com> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/21f651db Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/21f651db Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/21f651db Branch: refs/heads/master Commit: 21f651db1c51d80c9ce2761e3d07aa1129d1faca Parents: 337a731 Author: Will Berkeley <wdberke...@apache.org> Authored: Mon Apr 2 16:13:21 2018 -0700 Committer: Will Berkeley <wdberke...@gmail.com> Committed: Tue Apr 10 18:44:49 2018 +0000 ---------------------------------------------------------------------- src/kudu/server/generic_service.cc | 36 ++++++++++++++- src/kudu/server/generic_service.h | 6 +++ src/kudu/server/server_base.proto | 24 ++++++++++ src/kudu/tools/kudu-tool-test.cc | 48 ++++++++++++++++++++ src/kudu/tools/tool_action_common.cc | 44 +++++++++++++++++++ src/kudu/tools/tool_action_common.h | 5 +++ src/kudu/tools/tool_action_master.cc | 14 ++++++ src/kudu/tools/tool_action_tserver.cc | 14 ++++++ src/kudu/tserver/tablet_server-test.cc | 68 +++++++++++++++++++++++++++++ src/kudu/util/flags.cc | 26 +++++------ src/kudu/util/flags.h | 2 + 11 files changed, 273 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/server/generic_service.cc ---------------------------------------------------------------------- diff --git a/src/kudu/server/generic_service.cc b/src/kudu/server/generic_service.cc index e786c63..300e37f 100644 --- a/src/kudu/server/generic_service.cc +++ b/src/kudu/server/generic_service.cc @@ -17,9 +17,10 @@ #include "kudu/server/generic_service.h" -#include <string> #include <ostream> +#include <string> #include <unordered_set> +#include <utility> #include <gflags/gflags.h> #include <gflags/gflags_declare.h> @@ -39,6 +40,7 @@ #include "kudu/util/debug-util.h" #include "kudu/util/debug/leak_annotations.h" // IWYU pragma: keep #include "kudu/util/flag_tags.h" +#include "kudu/util/flags.h" #include "kudu/util/status.h" DECLARE_string(time_source); @@ -71,6 +73,38 @@ bool GenericServiceImpl::AuthorizeClient(const google::protobuf::Message* /*req* } +void GenericServiceImpl::GetFlags(const GetFlagsRequestPB* req, + GetFlagsResponsePB* resp, + rpc::RpcContext* rpc) { + // If no tags were specified, return all flags that have non-default values. + // If tags were specified, also filter flags that don't match any tag. + bool all_flags = req->all_flags(); + for (const auto& entry : GetFlagsMap()) { + if (entry.second.is_default && !all_flags) { + continue; + } + unordered_set<string> tags; + GetFlagTags(entry.first, &tags); + bool matches = req->tags().empty(); + for (const auto& tag : req->tags()) { + if (ContainsKey(tags, tag)) { + matches = true; + break; + } + } + if (!matches) continue; + + auto* flag = resp->add_flags(); + flag->set_name(entry.first); + flag->set_value(CheckFlagAndRedact(entry.second, EscapeMode::NONE)); + flag->set_is_default_value(entry.second.current_value == entry.second.default_value); + for (const auto& tag : tags) { + flag->add_tags(tag); + } + } + rpc->RespondSuccess(); +} + void GenericServiceImpl::SetFlag(const SetFlagRequestPB* req, SetFlagResponsePB* resp, rpc::RpcContext* rpc) { http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/server/generic_service.h ---------------------------------------------------------------------- diff --git a/src/kudu/server/generic_service.h b/src/kudu/server/generic_service.h index bfc8704..4cf0f79 100644 --- a/src/kudu/server/generic_service.h +++ b/src/kudu/server/generic_service.h @@ -39,6 +39,8 @@ class CheckLeaksRequestPB; class CheckLeaksResponsePB; class FlushCoverageRequestPB; class FlushCoverageResponsePB; +class GetFlagsRequestPB; +class GetFlagsResponsePB; class GetStatusRequestPB; class GetStatusResponsePB; class ServerBase; @@ -62,6 +64,10 @@ class GenericServiceImpl : public GenericServiceIf { google::protobuf::Message* resp, rpc::RpcContext* rpc) override; + virtual void GetFlags(const GetFlagsRequestPB* req, + GetFlagsResponsePB* resp, + rpc::RpcContext* rpc) OVERRIDE; + virtual void SetFlag(const SetFlagRequestPB* req, SetFlagResponsePB* resp, rpc::RpcContext* rpc) OVERRIDE; http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/server/server_base.proto ---------------------------------------------------------------------- diff --git a/src/kudu/server/server_base.proto b/src/kudu/server/server_base.proto index a80c962..cf680dd 100644 --- a/src/kudu/server/server_base.proto +++ b/src/kudu/server/server_base.proto @@ -39,6 +39,27 @@ message ServerStatusPB { // So, do not expose anything here which may be sensitive! } +// Retrieve the values of command line flags. +message GetFlagsRequestPB { + // Whether to return all flags, or only flags with non-default values. + optional bool all_flags = 1; + // A list of flag tags. Flags that match at least one tag are returned. If + // no tags are specified, all flags match. + repeated string tags = 2; +} + +message GetFlagsResponsePB { + message Flag { + optional string name = 1; + optional string value = 2; + repeated string tags = 3; + // true if the flag has its default value. + optional bool is_default_value = 4; + } + + repeated Flag flags = 1; +} + // Attempt to set a command line flag. // Note that many command line flags do not take effect if changed // at runtime. @@ -127,6 +148,9 @@ message SetServerWallClockForTestsResponsePB { service GenericService { option (kudu.rpc.default_authz_method) = "AuthorizeSuperUser"; + rpc GetFlags(GetFlagsRequestPB) + returns (GetFlagsResponsePB); + rpc SetFlag(SetFlagRequestPB) returns (SetFlagResponsePB); http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/tools/kudu-tool-test.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tools/kudu-tool-test.cc b/src/kudu/tools/kudu-tool-test.cc index 361b8be..d436f9e 100644 --- a/src/kudu/tools/kudu-tool-test.cc +++ b/src/kudu/tools/kudu-tool-test.cc @@ -477,6 +477,7 @@ TEST_F(ToolTest, TestModeHelp) { } { const vector<string> kMasterModeRegexes = { + "get_flags.*Get the gflags", "set_flag.*Change a gflag value", "status.*Get the status", "timestamp.*Get the current timestamp" @@ -537,6 +538,7 @@ TEST_F(ToolTest, TestModeHelp) { } { const vector<string> kTServerModeRegexes = { + "get_flags.*Get the gflags", "set_flag.*Change a gflag value", "status.*Get the status", "timestamp.*Get the current timestamp", @@ -2481,5 +2483,51 @@ TEST_F(ToolTest, TestReplaceTablet) { ASSERT_GE(workload.rows_inserted(), CountTableRows(workload_table.get())); } +TEST_F(ToolTest, TestGetFlags) { + ExternalMiniClusterOptions opts; + opts.num_tablet_servers = 1; + NO_FATALS(StartExternalMiniCluster(std::move(opts))); + + // Check that we get non-default flags. + // CSV formatting is easiest to match against. + // It seems safe to assume that -help and -logemaillevel will not be + // set, and that fs_wal_dir will be set to a non-default value. + for (const string& daemon_type : { "master", "tserver" }) { + const string& daemon_addr = daemon_type == "master" ? + cluster_->master()->bound_rpc_addr().ToString() : + cluster_->tablet_server(0)->bound_rpc_addr().ToString(); + const string& wal_dir = daemon_type == "master" ? + cluster_->master()->wal_dir() : + cluster_->tablet_server(0)->wal_dir(); + string out; + NO_FATALS(RunActionStdoutString( + Substitute("$0 get_flags $1 -format=csv", daemon_type, daemon_addr), + &out)); + ASSERT_STR_NOT_MATCHES(out, "help,*"); + ASSERT_STR_NOT_MATCHES(out, "logemaillevel,*"); + ASSERT_STR_CONTAINS(out, Substitute("fs_wal_dir,$0,false", wal_dir)); + + // Check that we get all flags with -all_flags. + out.clear(); + NO_FATALS(RunActionStdoutString( + Substitute("$0 get_flags $1 -format=csv -all_flags", daemon_type, daemon_addr), + &out)); + ASSERT_STR_CONTAINS(out, "help,false,true"); + ASSERT_STR_CONTAINS(out, "logemaillevel,999,true"); + ASSERT_STR_CONTAINS(out, Substitute("fs_wal_dir,$0,false", wal_dir)); + + // Check that -flag_tags filter to matching tags. + // -logemaillevel is an unsafe flag. + out.clear(); + NO_FATALS(RunActionStdoutString( + Substitute("$0 get_flags $1 -format=csv -all_flags -flag_tags=stable", + daemon_type, daemon_addr), + &out)); + ASSERT_STR_CONTAINS(out, "help,false,true"); + ASSERT_STR_NOT_MATCHES(out, "logemaillevel,*"); + ASSERT_STR_CONTAINS(out, Substitute("fs_wal_dir,$0,false", wal_dir)); + } +} + } // namespace tools } // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/tools/tool_action_common.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tools/tool_action_common.cc b/src/kudu/tools/tool_action_common.cc index df019d3..9edc548 100644 --- a/src/kudu/tools/tool_action_common.cc +++ b/src/kudu/tools/tool_action_common.cc @@ -24,6 +24,7 @@ #include <cstddef> #include <iomanip> #include <iostream> +#include <iterator> #include <memory> #include <numeric> #include <string> @@ -50,6 +51,7 @@ #include "kudu/gutil/endian.h" #include "kudu/gutil/map-util.h" #include "kudu/gutil/ref_counted.h" +#include "kudu/gutil/strings/join.h" #include "kudu/gutil/strings/numbers.h" #include "kudu/gutil/strings/split.h" #include "kudu/gutil/strings/substitute.h" @@ -94,6 +96,11 @@ DEFINE_string(format, "pretty", "Format to use for printing list output tables.\n" "Possible values: pretty, space, tsv, csv, and json"); +DEFINE_string(flag_tags, "", "Comma-separated list of tags used to restrict which " + "flags are returned. An empty value matches all tags"); +DEFINE_bool(all_flags, false, "Whether to return all flags, or only flags that " + "were explicitly set."); + namespace boost { template <typename Signature> class function; @@ -133,6 +140,8 @@ using rpc::MessengerBuilder; using rpc::RequestIdPB; using rpc::RpcController; using server::GenericServiceProxy; +using server::GetFlagsRequestPB; +using server::GetFlagsResponsePB; using server::GetStatusRequestPB; using server::GetStatusResponsePB; using server::ServerClockRequestPB; @@ -354,6 +363,41 @@ Status PrintSegment(const scoped_refptr<ReadableLogSegment>& segment) { return Status::OK(); } +Status PrintServerFlags(const string& address, uint16_t default_port) { + unique_ptr<GenericServiceProxy> proxy; + RETURN_NOT_OK(BuildProxy(address, default_port, &proxy)); + + GetFlagsRequestPB req; + GetFlagsResponsePB resp; + RpcController rpc; + rpc.set_timeout(MonoDelta::FromMilliseconds(FLAGS_timeout_ms)); + + req.set_all_flags(FLAGS_all_flags); + vector<string> tags = strings::Split(FLAGS_flag_tags, ",", strings::SkipEmpty()); + for (const auto& tag : tags) { + req.add_tags(tag); + } + RETURN_NOT_OK(proxy->GetFlags(req, &resp, &rpc)); + + vector<GetFlagsResponsePB::Flag> flags(resp.flags().begin(), resp.flags().end()); + std::sort(flags.begin(), flags.end(), + [](const GetFlagsResponsePB::Flag& left, + const GetFlagsResponsePB::Flag& right) -> bool { + return left.name() < right.name(); + }); + DataTable table({ "flag", "value", "default value?", "tags" }); + for (const auto& flag : flags) { + tags.clear(); + std::copy(flag.tags().begin(), flag.tags().end(), std::back_inserter(tags)); + std::sort(tags.begin(), tags.end()); + table.AddRow({ flag.name(), + flag.value(), + Substitute("$0", flag.is_default_value()), + JoinStrings(tags, ",") }); + } + return table.PrintTo(cout); +} + Status SetServerFlag(const string& address, uint16_t default_port, const string& flag, const string& value) { unique_ptr<GenericServiceProxy> proxy; http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/tools/tool_action_common.h ---------------------------------------------------------------------- diff --git a/src/kudu/tools/tool_action_common.h b/src/kudu/tools/tool_action_common.h index e7e46cd..3f4a179 100644 --- a/src/kudu/tools/tool_action_common.h +++ b/src/kudu/tools/tool_action_common.h @@ -105,6 +105,11 @@ Status PrintServerStatus(const std::string& address, uint16_t default_port); // If 'address' does not contain a port, 'default_port' is used instead. Status PrintServerTimestamp(const std::string& address, uint16_t default_port); +// Prints the values of the gflags set for the Kudu server running at 'address'. +// +// If 'address' does not contain a port, 'default_port' is used instead. +Status PrintServerFlags(const std::string& address, uint16_t default_port); + // Changes the value of the gflag given by 'flag' to the value in 'value' on // the Kudu server running at 'address'. // http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/tools/tool_action_master.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tools/tool_action_master.cc b/src/kudu/tools/tool_action_master.cc index 611b36a..ae07172 100644 --- a/src/kudu/tools/tool_action_master.cc +++ b/src/kudu/tools/tool_action_master.cc @@ -65,6 +65,11 @@ const char* const kMasterAddressDesc = "Address of a Kudu Master of form " const char* const kFlagArg = "flag"; const char* const kValueArg = "value"; +Status MasterGetFlags(const RunnerContext& context) { + const string& address = FindOrDie(context.required_args, kMasterAddressArg); + return PrintServerFlags(address, master::Master::kDefaultPort); +} + Status MasterSetFlag(const RunnerContext& context) { const string& address = FindOrDie(context.required_args, kMasterAddressArg); const string& flag = FindOrDie(context.required_args, kFlagArg); @@ -152,6 +157,14 @@ Status ListMasters(const RunnerContext& context) { } // anonymous namespace unique_ptr<Mode> BuildMasterMode() { + unique_ptr<Action> get_flags = + ActionBuilder("get_flags", &MasterGetFlags) + .Description("Get the gflags for a Kudu Master") + .AddRequiredParameter({ kMasterAddressArg, kMasterAddressDesc }) + .AddOptionalParameter("all_flags") + .AddOptionalParameter("flag_tags") + .Build(); + unique_ptr<Action> set_flag = ActionBuilder("set_flag", &MasterSetFlag) .Description("Change a gflag value on a Kudu Master") @@ -187,6 +200,7 @@ unique_ptr<Mode> BuildMasterMode() { return ModeBuilder("master") .Description("Operate on a Kudu Master") + .AddAction(std::move(get_flags)) .AddAction(std::move(set_flag)) .AddAction(std::move(status)) .AddAction(std::move(timestamp)) http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/tools/tool_action_tserver.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tools/tool_action_tserver.cc b/src/kudu/tools/tool_action_tserver.cc index 1a1dc85..03e007f 100644 --- a/src/kudu/tools/tool_action_tserver.cc +++ b/src/kudu/tools/tool_action_tserver.cc @@ -64,6 +64,11 @@ const char* const kTServerAddressDesc = "Address of a Kudu Tablet Server of " const char* const kFlagArg = "flag"; const char* const kValueArg = "value"; +Status TServerGetFlags(const RunnerContext& context) { + const string& address = FindOrDie(context.required_args, kTServerAddressArg); + return PrintServerFlags(address, tserver::TabletServer::kDefaultPort); +} + Status TServerSetFlag(const RunnerContext& context) { const string& address = FindOrDie(context.required_args, kTServerAddressArg); const string& flag = FindOrDie(context.required_args, kFlagArg); @@ -146,6 +151,14 @@ Status ListTServers(const RunnerContext& context) { } // anonymous namespace unique_ptr<Mode> BuildTServerMode() { + unique_ptr<Action> get_flags = + ActionBuilder("get_flags", &TServerGetFlags) + .Description("Get the gflags for a Kudu Tablet Server") + .AddRequiredParameter({ kTServerAddressArg, kTServerAddressDesc }) + .AddOptionalParameter("all_flags") + .AddOptionalParameter("flag_tags") + .Build(); + unique_ptr<Action> set_flag = ActionBuilder("set_flag", &TServerSetFlag) .Description("Change a gflag value on a Kudu Tablet Server") @@ -182,6 +195,7 @@ unique_ptr<Mode> BuildTServerMode() { return ModeBuilder("tserver") .Description("Operate on a Kudu Tablet Server") + .AddAction(std::move(get_flags)) .AddAction(std::move(set_flag)) .AddAction(std::move(status)) .AddAction(std::move(timestamp)) http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/tserver/tablet_server-test.cc ---------------------------------------------------------------------- diff --git a/src/kudu/tserver/tablet_server-test.cc b/src/kudu/tserver/tablet_server-test.cc index 63b2998..6dba667 100644 --- a/src/kudu/tserver/tablet_server-test.cc +++ b/src/kudu/tserver/tablet_server-test.cc @@ -256,6 +256,74 @@ TEST_F(TabletServerTest, TestServerClock) { ASSERT_GT(mini_server_->server()->clock()->Now().ToUint64(), resp.timestamp()); } +TEST_F(TabletServerTest, TestGetFlags) { + server::GenericServiceProxy proxy( + client_messenger_, mini_server_->bound_rpc_addr(), + mini_server_->bound_rpc_addr().host()); + + server::GetFlagsRequestPB req; + server::GetFlagsResponsePB resp; + + // Check that a default request returns flags set to a non-default value and + // does not return flags set to a default value. + // Throughout, we make the reasonable assumption that the -fs_wal_dir flag + // will have a non-default value, and the -help and unsafe -logemaillevel + // flags will have default values. + { + RpcController controller; + ASSERT_OK(proxy.GetFlags(req, &resp, &controller)); + SCOPED_TRACE(SecureDebugString(resp)); + EXPECT_TRUE(std::any_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "log_dir"; + })); + EXPECT_TRUE(std::none_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "help"; + })); + } + + // Check that specifying all flags returns even flags with default values. + { + RpcController controller; + req.set_all_flags(true); + ASSERT_OK(proxy.GetFlags(req, &resp, &controller)); + SCOPED_TRACE(SecureDebugString(resp)); + EXPECT_TRUE(std::any_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "log_dir"; + })); + EXPECT_TRUE(std::any_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "help"; + })); + EXPECT_TRUE(std::any_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "logemaillevel"; + })); + } + + // Check that filtering on tags excludes flags with no matching tag. + { + RpcController controller; + req.add_tags("stable"); + ASSERT_OK(proxy.GetFlags(req, &resp, &controller)); + SCOPED_TRACE(SecureDebugString(resp)); + EXPECT_TRUE(std::any_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "log_dir"; + })); + EXPECT_TRUE(std::any_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "help"; + })); + EXPECT_TRUE(std::none_of(resp.flags().begin(), resp.flags().end(), + [](const server::GetFlagsResponsePB::Flag& flag) -> bool { + return flag.name() == "logemaillevel"; + })); + } +} + TEST_F(TabletServerTest, TestSetFlags) { server::GenericServiceProxy proxy( client_messenger_, mini_server_->bound_rpc_addr(), http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/util/flags.cc ---------------------------------------------------------------------- diff --git a/src/kudu/util/flags.cc b/src/kudu/util/flags.cc index e091d3d..3520be5 100644 --- a/src/kudu/util/flags.cc +++ b/src/kudu/util/flags.cc @@ -450,6 +450,19 @@ void RunCustomValidators() { } } +void SetUmask() { + // We already validated with a nice error message using the ValidateUmask + // FlagValidator above. + CHECK(safe_strtou32_base(FLAGS_umask.c_str(), &g_parsed_umask, 8)); + uint32_t old_mask = umask(g_parsed_umask); + if (old_mask != g_parsed_umask) { + VLOG(2) << "Changed umask from " << StringPrintf("%03o", old_mask) << " to " + << StringPrintf("%03o", g_parsed_umask); + } +} + +} // anonymous namespace + // If --redact indicates, redact the flag tagged as 'sensitive'. // Otherwise, return its value as-is. If EscapeMode is set to HTML, // return HTML escaped string. @@ -469,19 +482,6 @@ string CheckFlagAndRedact(const CommandLineFlagInfo& flag, EscapeMode mode) { return ret_value; } -void SetUmask() { - // We already validated with a nice error message using the ValidateUmask - // FlagValidator above. - CHECK(safe_strtou32_base(FLAGS_umask.c_str(), &g_parsed_umask, 8)); - uint32_t old_mask = umask(g_parsed_umask); - if (old_mask != g_parsed_umask) { - VLOG(2) << "Changed umask from " << StringPrintf("%03o", old_mask) << " to " - << StringPrintf("%03o", g_parsed_umask); - } -} - -} // anonymous namespace - int ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) { // The logbufsecs default is 30 seconds which is a bit too long. google::SetCommandLineOptionWithMode("logbufsecs", "5", http://git-wip-us.apache.org/repos/asf/kudu/blob/21f651db/src/kudu/util/flags.h ---------------------------------------------------------------------- diff --git a/src/kudu/util/flags.h b/src/kudu/util/flags.h index 032c3e3..83cb152 100644 --- a/src/kudu/util/flags.h +++ b/src/kudu/util/flags.h @@ -83,5 +83,7 @@ enum class TriStateFlag { Status ParseTriState(const char* flag_name, const std::string& flag_value, TriStateFlag* tri_state); +std::string CheckFlagAndRedact(const google::CommandLineFlagInfo& flag, EscapeMode mode); + } // namespace kudu #endif /* KUDU_UTIL_FLAGS_H */