1#include <iostream>
2
3#include <boost/program_options.hpp>
4#include <Poco/Logger.h>
5#include <Poco/ConsoleChannel.h>
6#include <Poco/FormattingChannel.h>
7#include <Poco/PatternFormatter.h>
8#include <Poco/AutoPtr.h>
9#include <Poco/Util/XMLConfiguration.h>
10
11#include <Common/ZooKeeper/ZooKeeperNodeCache.h>
12#include <Common/Config/ConfigProcessor.h>
13#include <Common/Exception.h>
14
15
16static void setupLogging(const std::string & log_level)
17{
18 Poco::AutoPtr<Poco::ConsoleChannel> channel(new Poco::ConsoleChannel);
19 Poco::AutoPtr<Poco::PatternFormatter> formatter(new Poco::PatternFormatter);
20 formatter->setProperty("pattern", "%L%Y-%m-%d %H:%M:%S.%i <%p> %s: %t");
21 Poco::AutoPtr<Poco::FormattingChannel> formatting_channel(new Poco::FormattingChannel(formatter, channel));
22 Poco::Logger::root().setChannel(formatting_channel);
23 Poco::Logger::root().setLevel(log_level);
24}
25
26static std::string extractFromConfig(
27 const std::string & config_path, const std::string & key, bool process_zk_includes, bool try_get = false)
28{
29 DB::ConfigProcessor processor(config_path, /* throw_on_bad_incl = */ false, /* log_to_console = */ false);
30 bool has_zk_includes;
31 DB::XMLDocumentPtr config_xml = processor.processConfig(&has_zk_includes);
32 if (has_zk_includes && process_zk_includes)
33 {
34 DB::ConfigurationPtr bootstrap_configuration(new Poco::Util::XMLConfiguration(config_xml));
35 zkutil::ZooKeeperPtr zookeeper = std::make_shared<zkutil::ZooKeeper>(
36 *bootstrap_configuration, "zookeeper");
37 zkutil::ZooKeeperNodeCache zk_node_cache([&] { return zookeeper; });
38 config_xml = processor.processConfig(&has_zk_includes, &zk_node_cache);
39 }
40 DB::ConfigurationPtr configuration(new Poco::Util::XMLConfiguration(config_xml));
41 // do not throw exception if not found
42 if (try_get)
43 return configuration->getString(key, "");
44 return configuration->getString(key);
45}
46
47#pragma GCC diagnostic ignored "-Wunused-function"
48#pragma GCC diagnostic ignored "-Wmissing-declarations"
49
50int mainEntryClickHouseExtractFromConfig(int argc, char ** argv)
51{
52 bool print_stacktrace = false;
53 bool process_zk_includes = false;
54 bool try_get = false;
55 std::string log_level;
56 std::string config_path;
57 std::string key;
58
59 namespace po = boost::program_options;
60
61 po::options_description options_desc("Allowed options");
62 options_desc.add_options()
63 ("help", "produce this help message")
64 ("stacktrace", po::bool_switch(&print_stacktrace), "print stack traces of exceptions")
65 ("process-zk-includes", po::bool_switch(&process_zk_includes),
66 "if there are from_zk elements in config, connect to ZooKeeper and process them")
67 ("try", po::bool_switch(&try_get), "Do not warn about missing keys")
68 ("log-level", po::value<std::string>(&log_level)->default_value("error"), "log level")
69 ("config-file,c", po::value<std::string>(&config_path)->required(), "path to config file")
70 ("key,k", po::value<std::string>(&key)->required(), "key to get value for");
71
72 po::positional_options_description positional_desc;
73 positional_desc.add("config-file", 1);
74 positional_desc.add("key", 1);
75
76 try
77 {
78 po::variables_map options;
79 po::store(po::command_line_parser(argc, argv).options(options_desc).positional(positional_desc).run(), options);
80
81 if (options.count("help"))
82 {
83 std::cerr << "Preprocess config file and extract value of the given key." << std::endl
84 << std::endl;
85 std::cerr << "Usage: clickhouse extract-from-config [options]" << std::endl
86 << std::endl;
87 std::cerr << options_desc << std::endl;
88 return 0;
89 }
90
91 po::notify(options);
92
93 setupLogging(log_level);
94 std::cout << extractFromConfig(config_path, key, process_zk_includes, try_get) << std::endl;
95 }
96 catch (...)
97 {
98 std::cerr << DB::getCurrentExceptionMessage(print_stacktrace, true) << std::endl;
99 return DB::getCurrentExceptionCode();
100 }
101
102 return 0;
103}
104