/Users/deen/code/yugabyte-db/src/yb/master/call_home.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | |
13 | | #include "yb/master/call_home.h" |
14 | | |
15 | | #include <sstream> |
16 | | #include <thread> |
17 | | |
18 | | #include <boost/algorithm/string.hpp> |
19 | | #include <boost/optional.hpp> |
20 | | #include <rapidjson/reader.h> |
21 | | #include <rapidjson/writer.h> |
22 | | |
23 | | #include "yb/master/catalog_entity_info.pb.h" |
24 | | #include "yb/master/catalog_manager_if.h" |
25 | | #include "yb/master/master.h" |
26 | | #include "yb/master/master_client.pb.h" |
27 | | #include "yb/master/master_ddl.pb.h" |
28 | | #include "yb/master/ts_manager.h" |
29 | | |
30 | | #include "yb/rpc/scheduler.h" |
31 | | |
32 | | #include "yb/tserver/ts_tablet_manager.h" |
33 | | |
34 | | #include "yb/util/flag_tags.h" |
35 | | #include "yb/util/jsonwriter.h" |
36 | | #include "yb/util/logging.h" |
37 | | #include "yb/util/metrics.h" |
38 | | #include "yb/util/result.h" |
39 | | #include "yb/util/user.h" |
40 | | #include "yb/util/version_info.h" |
41 | | |
42 | | static const char* kLowLevel = "low"; |
43 | | static const char* kMediumLevel = "medium"; |
44 | | static const char* kHighLevel = "high"; |
45 | | |
46 | | DEFINE_bool(callhome_enabled, true, |
47 | | "Enables callhome feature that sends analytics data to yugabyte"); |
48 | | TAG_FLAG(callhome_enabled, runtime); |
49 | | |
50 | | DEFINE_int32(callhome_interval_secs, 3600, "How often to run callhome"); |
51 | | TAG_FLAG(callhome_interval_secs, runtime); |
52 | | // TODO: We need to change this to https, it involves updating our libcurl |
53 | | // implementation to support SSL. |
54 | | DEFINE_string(callhome_url, "http://diagnostics.yugabyte.com", |
55 | | "URL of callhome server"); |
56 | | TAG_FLAG(callhome_url, runtime); |
57 | | DEFINE_string(callhome_collection_level, kMediumLevel, "Level of details sent by callhome"); |
58 | | TAG_FLAG(callhome_collection_level, runtime); |
59 | | |
60 | | DEFINE_string(callhome_tag, "", "Tag to be inserted in the json sent to FLAGS_callhome_url. " |
61 | | "This tag is used by itest to specify that the data generated by " |
62 | | "callhome should be discarded by the receiver."); |
63 | | TAG_FLAG(callhome_tag, runtime); |
64 | | |
65 | | using google::CommandlineFlagsIntoString; |
66 | | using strings::Substitute; |
67 | | using yb::master::Master; |
68 | | using yb::master::ListMastersResponsePB; |
69 | | using yb::master::ListTablesRequestPB; |
70 | | using yb::master::ListTablesResponsePB; |
71 | | using yb::master::ListTabletServersResponsePB; |
72 | | using yb::master::GetMasterClusterConfigResponsePB; |
73 | | using yb::master::TSDescriptor; |
74 | | using yb::server::RpcAndWebServerBase; |
75 | | using yb::tserver::TabletServer; |
76 | | |
77 | | namespace yb { |
78 | | |
79 | 32 | Collector::~Collector() {} |
80 | | |
81 | | class CollectorBase : public Collector { |
82 | | public: |
83 | | CollectorBase(server::RpcAndWebServerBase* server, ServerType server_type); |
84 | | |
85 | | virtual ~CollectorBase(); |
86 | | |
87 | | bool Run(CollectionLevel collection_level); |
88 | | virtual void Collect(CollectionLevel collection_level) = 0; |
89 | | |
90 | 52 | const std::string& as_json() { return json_; } |
91 | 0 | ServerType server_type() { return server_type_; } |
92 | | |
93 | | virtual std::string collector_name() = 0; |
94 | | |
95 | | virtual CollectionLevel collection_level() = 0; |
96 | | virtual ServerType collector_type() = 0; |
97 | | |
98 | | protected: |
99 | 23 | inline master::Master* master() { return down_cast<master::Master*>(server_); } |
100 | 0 | inline tserver::TabletServer* tserver() { return down_cast<tserver::TabletServer*>(server_); } |
101 | | |
102 | | server::RpcAndWebServerBase* server_; |
103 | | ServerType server_type_; |
104 | | std::string json_; |
105 | | }; |
106 | | |
107 | 32 | CollectorBase::~CollectorBase() {} |
108 | | |
109 | | CollectorBase::CollectorBase(RpcAndWebServerBase* server, ServerType server_type): |
110 | 82.6k | server_(server), server_type_(server_type) {} |
111 | | |
112 | 32 | bool CollectorBase::Run(CollectionLevel level) { |
113 | 32 | json_.clear(); |
114 | 32 | if (collector_type() == ServerType::ALL || collector_type() == server_type_) { |
115 | 32 | if (collection_level() <= level) { |
116 | 26 | Collect(level); |
117 | 26 | return true; |
118 | 6 | } else { |
119 | 6 | LOG(INFO) << "Skipping collector " << collector_name() |
120 | 6 | << " because it has a higher collection level than the requested one"; |
121 | 6 | } |
122 | 0 | } else { |
123 | 0 | LOG(INFO) << "Skipping collector " << collector_name() << " because of server type"; |
124 | 0 | } |
125 | 6 | return false; |
126 | 32 | } |
127 | | |
128 | | namespace { |
129 | | |
130 | | template<class Key, class Value> |
131 | 22 | void AppendPairToJson(const Key& key, const Value& value, std::string *out) { |
132 | 22 | if (!out->empty()) { |
133 | 18 | *out += ","; |
134 | 18 | } |
135 | 22 | *out += '\"'; |
136 | 22 | *out += key; |
137 | 22 | *out += "\":\""; |
138 | 22 | *out += value; |
139 | 22 | *out += '\"'; |
140 | 22 | } call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA13_cNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKT_RKT0_PS9_ Line | Count | Source | 131 | 7 | void AppendPairToJson(const Key& key, const Value& value, std::string *out) { | 132 | 7 | if (!out->empty()) { | 133 | 3 | *out += ","; | 134 | 3 | } | 135 | 7 | *out += '\"'; | 136 | 7 | *out += key; | 137 | 7 | *out += "\":\""; | 138 | 7 | *out += value; | 139 | 7 | *out += '\"'; | 140 | 7 | } |
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA10_cNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKT_RKT0_PS9_ Line | Count | Source | 131 | 8 | void AppendPairToJson(const Key& key, const Value& value, std::string *out) { | 132 | 8 | if (!out->empty()) { | 133 | 8 | *out += ","; | 134 | 8 | } | 135 | 8 | *out += '\"'; | 136 | 8 | *out += key; | 137 | 8 | *out += "\":\""; | 138 | 8 | *out += value; | 139 | 8 | *out += '\"'; | 140 | 8 | } |
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA12_cA7_cEEvRKT_RKT0_PNSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEE Line | Count | Source | 131 | 4 | void AppendPairToJson(const Key& key, const Value& value, std::string *out) { | 132 | 4 | if (!out->empty()) { | 133 | 4 | *out += ","; | 134 | 4 | } | 135 | 4 | *out += '\"'; | 136 | 4 | *out += key; | 137 | 4 | *out += "\":\""; | 138 | 4 | *out += value; | 139 | 4 | *out += '\"'; | 140 | 4 | } |
call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA9_cNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvRKT_RKT0_PS9_ Line | Count | Source | 131 | 3 | void AppendPairToJson(const Key& key, const Value& value, std::string *out) { | 132 | 3 | if (!out->empty()) { | 133 | 3 | *out += ","; | 134 | 3 | } | 135 | 3 | *out += '\"'; | 136 | 3 | *out += key; | 137 | 3 | *out += "\":\""; | 138 | 3 | *out += value; | 139 | 3 | *out += '\"'; | 140 | 3 | } |
Unexecuted instantiation: call_home.cc:_ZN2yb12_GLOBAL__N_116AppendPairToJsonIA12_cA8_cEEvRKT_RKT0_PNSt3__112basic_stringIcNSA_11char_traitsIcEENSA_9allocatorIcEEEE |
141 | | |
142 | 3 | std::string GetCurrentUser() { |
143 | 3 | auto user_name = GetLoggedInUser(); |
144 | 3 | if (user_name.ok()) { |
145 | 2 | YB_LOG_FIRST_N(INFO, 1) << "Logged in user: " << *user_name; |
146 | 3 | return *user_name; |
147 | 0 | } else { |
148 | 0 | YB_LOG_FIRST_N(WARNING, 1) << "Failed to get current user: " << user_name.status(); |
149 | 0 | return "unknown_user"; |
150 | 0 | } |
151 | 3 | } |
152 | | |
153 | | } // namespace |
154 | | |
155 | | class BasicCollector : public CollectorBase { |
156 | | public: |
157 | | using CollectorBase::CollectorBase; |
158 | | |
159 | 4 | void Collect(CollectionLevel collection_level) { |
160 | 4 | switch (server_type_) { |
161 | 0 | case ServerType::ALL: |
162 | 0 | LOG(FATAL) << "Invalid server type ALL"; |
163 | 4 | case ServerType::MASTER: { |
164 | 4 | master::SysClusterConfigEntryPB config; |
165 | 4 | auto status = master()->catalog_manager()->GetClusterConfig(&config); |
166 | 4 | if (status.ok()) { |
167 | 4 | AppendPairToJson("cluster_uuid", config.cluster_uuid(), &json_); |
168 | 4 | } |
169 | 4 | AppendPairToJson("node_uuid", master()->fs_manager()->uuid(), &json_); |
170 | 4 | AppendPairToJson("server_type", "master", &json_); |
171 | | |
172 | | // Only collect hostname and username if collection level is medium or high. |
173 | 4 | if (collection_level != CollectionLevel::LOW) { |
174 | 3 | AppendPairToJson("hostname", master()->get_hostname(), &json_); |
175 | 3 | AppendPairToJson("current_user", GetCurrentUser(), &json_); |
176 | 3 | } |
177 | 4 | json_ += ",\"version_info\":" + VersionInfo::GetAllVersionInfoJson(); |
178 | 4 | break; |
179 | 0 | } |
180 | 0 | case ServerType::TSERVER: { |
181 | 0 | AppendPairToJson("cluster_uuid", tserver()->cluster_uuid(), &json_); |
182 | 0 | AppendPairToJson("node_uuid", tserver()->permanent_uuid(), &json_); |
183 | 0 | AppendPairToJson("server_type", "tserver", &json_); |
184 | | |
185 | | // Only collect hostname and username if collection level is medium or high. |
186 | 0 | if (collection_level != CollectionLevel::LOW) { |
187 | 0 | AppendPairToJson("hostname", tserver()->get_hostname(), &json_); |
188 | 0 | AppendPairToJson("current_user", GetCurrentUser(), &json_); |
189 | 0 | } |
190 | 0 | break; |
191 | 4 | } |
192 | 4 | } |
193 | 4 | AppendPairToJson("timestamp", std::to_string(WallTime_Now()), &json_); |
194 | 4 | } |
195 | | |
196 | 4 | string collector_name() { return "BasicCollector"; } |
197 | | |
198 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::LOW; } |
199 | 4 | virtual ServerType collector_type() { return ServerType::ALL; } |
200 | | }; |
201 | | |
202 | | class MetricsCollector : public CollectorBase { |
203 | | public: |
204 | | using CollectorBase::CollectorBase; |
205 | | |
206 | 1 | void Collect(CollectionLevel collection_level) { |
207 | 1 | std::stringstream s; |
208 | 1 | JsonWriter w(&s, JsonWriter::COMPACT); |
209 | | |
210 | 1 | Status status = server_->metric_registry()->WriteAsJson(&w, {"*"}, MetricJsonOptions()); |
211 | 1 | if (!status.ok()) { |
212 | 0 | json_ = "\"metrics\":{}"; |
213 | 0 | return; |
214 | 0 | } |
215 | 1 | json_ = "\"metrics\":" + s.str(); |
216 | 1 | } |
217 | | |
218 | 4 | string collector_name() { return "MetricsCollector"; } |
219 | | |
220 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::HIGH; } |
221 | 4 | virtual ServerType collector_type() { return ServerType::ALL; } |
222 | | }; |
223 | | |
224 | | class RpcsCollector : public CollectorBase { |
225 | | public: |
226 | | using CollectorBase::CollectorBase; |
227 | | |
228 | 1 | void Collect(CollectionLevel collection_level) { |
229 | 1 | if (!UpdateAddr().ok()) { |
230 | 0 | json_ = "\"rpcs\":{}"; |
231 | 0 | return; |
232 | 0 | } |
233 | | |
234 | 1 | faststring buf; |
235 | 1 | auto url = Substitute("http://$0/rpcz", yb::ToString(*addr_)); |
236 | 1 | auto status = curl_.FetchURL(url, &buf); |
237 | 1 | if (!status.ok()) { |
238 | 0 | LOG(ERROR) << "Unable to read url " << url; |
239 | 0 | return; |
240 | 0 | } |
241 | | |
242 | 1 | if (buf.length() > 0) { |
243 | 1 | auto rpcs_json = buf.ToString(); |
244 | 1 | boost::replace_all(rpcs_json, "\n", ""); |
245 | 1 | json_ = "\"rpcs\":" + rpcs_json; |
246 | 0 | } else { |
247 | 0 | LOG(WARNING) << "Error getting rpcs"; |
248 | 0 | } |
249 | | |
250 | 1 | } |
251 | | |
252 | 4 | string collector_name() { return "RpcsCollector"; } |
253 | | |
254 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::HIGH; } |
255 | 4 | virtual ServerType collector_type() { return ServerType::ALL; } |
256 | | |
257 | | private: |
258 | 1 | CHECKED_STATUS UpdateAddr() { |
259 | 1 | if (addr_) { |
260 | 0 | return Status::OK(); |
261 | 0 | } |
262 | | |
263 | 1 | vector<Endpoint> addrs; |
264 | 1 | auto status = server_->web_server()->GetBoundAddresses(&addrs); |
265 | 1 | if (!status.ok()) { |
266 | 0 | LOG(WARNING) << "Unable to get webserver address: " << status.ToString(); |
267 | 0 | return STATUS(InternalError, "Unable to get webserver address"); |
268 | 0 | } |
269 | 1 | addr_.emplace(addrs[0]); |
270 | 1 | return Status::OK(); |
271 | 1 | } |
272 | | |
273 | | boost::optional<Endpoint> addr_; |
274 | | EasyCurl curl_; |
275 | | }; |
276 | | |
277 | | class TablesCollector : public CollectorBase { |
278 | | public: |
279 | | using CollectorBase::CollectorBase; |
280 | | |
281 | 4 | void Collect(CollectionLevel collection_level) { |
282 | 4 | ListTablesRequestPB req; |
283 | 4 | req.set_exclude_system_tables(true); |
284 | 4 | ListTablesResponsePB resp; |
285 | 4 | auto status = master()->catalog_manager()->ListTables(&req, &resp); |
286 | 4 | if (!status.ok()) { |
287 | 0 | LOG(INFO) << "Error getting number of tables"; |
288 | 0 | return; |
289 | 0 | } |
290 | 4 | if (collection_level == CollectionLevel::LOW) { |
291 | 1 | json_ = Substitute("\"tables\":$0", resp.tables_size()); |
292 | 3 | } else { |
293 | | // TODO(hector): Add more table details. |
294 | 3 | json_ = Substitute("\"tables\":$0", resp.tables_size()); |
295 | 3 | } |
296 | 4 | } |
297 | | |
298 | 4 | string collector_name() { return "TablesCollector"; } |
299 | | |
300 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::ALL; } |
301 | 8 | virtual ServerType collector_type() { return ServerType::MASTER; } |
302 | | }; |
303 | | |
304 | | class MasterInfoCollector : public CollectorBase { |
305 | | public: |
306 | | using CollectorBase::CollectorBase; |
307 | | |
308 | 4 | void Collect(CollectionLevel collection_level) { |
309 | 4 | vector<ServerEntryPB> masters; |
310 | 4 | Status s = master()->ListMasters(&masters); |
311 | 4 | if (s.ok()) { |
312 | 4 | if (collection_level == CollectionLevel::LOW) { |
313 | 1 | json_ = Substitute("\"masters\":$0", masters.size()); |
314 | 3 | } else { |
315 | | // TODO(hector): Add more details. |
316 | 3 | json_ = Substitute("\"masters\":$0", masters.size()); |
317 | 3 | } |
318 | 4 | } |
319 | 4 | } |
320 | | |
321 | 4 | string collector_name() { return "MasterInfoCollector"; } |
322 | | |
323 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::ALL; } |
324 | 8 | virtual ServerType collector_type() { return ServerType::MASTER; } |
325 | | }; |
326 | | |
327 | | class TServersInfoCollector : public CollectorBase { |
328 | | public: |
329 | | using CollectorBase::CollectorBase; |
330 | | |
331 | 4 | void Collect(CollectionLevel collection_level) { |
332 | 4 | vector<std::shared_ptr<TSDescriptor>> descs; |
333 | 4 | master()->ts_manager()->GetAllDescriptors(&descs); |
334 | 4 | if (collection_level == CollectionLevel::LOW) { |
335 | 1 | json_ = Substitute("\"tservers\":$0", descs.size()); |
336 | 3 | } else { |
337 | | // TODO(hector): Add more details. |
338 | 3 | json_ = Substitute("\"tservers\":$0", descs.size()); |
339 | 3 | } |
340 | 4 | } |
341 | | |
342 | 4 | string collector_name() { return "TServersInfoCollector"; } |
343 | | |
344 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::ALL; } |
345 | 8 | virtual ServerType collector_type() { return ServerType::MASTER; } |
346 | | }; |
347 | | |
348 | | class TabletsCollector : public CollectorBase { |
349 | | public: |
350 | | using CollectorBase::CollectorBase; |
351 | | |
352 | 4 | void Collect(CollectionLevel collection_level) { |
353 | 4 | int ntablets; |
354 | 4 | if (server_type_ == ServerType::MASTER) { |
355 | 4 | ntablets = 1; |
356 | 0 | } else { |
357 | 0 | ntablets = tserver()->tablet_manager()->GetNumLiveTablets(); |
358 | 0 | } |
359 | 4 | json_ = Substitute("\"tablets\":$0", ntablets); |
360 | 4 | } |
361 | | |
362 | 4 | string collector_name() { return "TabletsCollector"; } |
363 | | |
364 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::ALL; } |
365 | 4 | virtual ServerType collector_type() { return ServerType::ALL; } |
366 | | }; |
367 | | |
368 | | class GFlagsCollector : public CollectorBase { |
369 | | public: |
370 | | using CollectorBase::CollectorBase; |
371 | | |
372 | 4 | void Collect(CollectionLevel collection_level) { |
373 | 4 | auto gflags = CommandlineFlagsIntoString(); |
374 | 4 | boost::replace_all(gflags, "\n", " "); |
375 | 4 | json_ = Substitute("\"gflags\":\"$0\"", gflags); |
376 | 4 | } |
377 | | |
378 | 4 | string collector_name() { return "GFlagsCollector"; } |
379 | | |
380 | 4 | virtual CollectionLevel collection_level() { return CollectionLevel::LOW; } |
381 | 4 | virtual ServerType collector_type() { return ServerType::ALL; } |
382 | | }; |
383 | | |
384 | | CallHome::CallHome(server::RpcAndWebServerBase* server, ServerType server_type) : |
385 | 10.3k | server_(server), pool_("call_home", 1), server_type_(server_type) { |
386 | | |
387 | 10.3k | scheduler_ = std::make_unique<yb::rpc::Scheduler>(&pool_.io_service()); |
388 | | |
389 | 10.3k | AddCollector<BasicCollector>(); |
390 | 10.3k | AddCollector<MasterInfoCollector>(); |
391 | 10.3k | AddCollector<TServersInfoCollector>(); |
392 | 10.3k | AddCollector<TablesCollector>(); |
393 | 10.3k | AddCollector<TabletsCollector>(); |
394 | 10.3k | AddCollector<MetricsCollector>(); |
395 | 10.3k | AddCollector<RpcsCollector>(); |
396 | 10.3k | AddCollector<GFlagsCollector>(); |
397 | 10.3k | } |
398 | | |
399 | 4 | CallHome::~CallHome() { |
400 | 4 | scheduler_->Shutdown(); |
401 | 4 | pool_.Shutdown(); |
402 | 4 | pool_.Join(); |
403 | 4 | } |
404 | | |
405 | | template <typename T> |
406 | 82.6k | void CallHome::AddCollector() { |
407 | 82.6k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); |
408 | 82.6k | } _ZN2yb8CallHome12AddCollectorINS_14BasicCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_19MasterInfoCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_21TServersInfoCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_15TablesCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_16TabletsCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_16MetricsCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_13RpcsCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
_ZN2yb8CallHome12AddCollectorINS_15GFlagsCollectorEEEvv Line | Count | Source | 406 | 10.3k | void CallHome::AddCollector() { | 407 | 10.3k | collectors_.emplace_back(std::make_unique<T>(server_, server_type_)); | 408 | 10.3k | } |
|
409 | | |
410 | 4 | std::string CallHome::BuildJson() { |
411 | 4 | string str = "{"; |
412 | 4 | string comma = ""; |
413 | 4 | auto collection_level = GetCollectionLevel(); |
414 | 32 | for (const auto& collector : collectors_) { |
415 | 32 | if (collector->Run(collection_level) && !collector->as_json().empty()) { |
416 | 26 | str += comma; |
417 | 26 | str += collector->as_json(); |
418 | 26 | comma = ","; |
419 | 26 | LOG(INFO) << "Done with collector " << collector->collector_name(); |
420 | 26 | } |
421 | 32 | } |
422 | 4 | if (!FLAGS_callhome_tag.empty()) { |
423 | 4 | str += comma; |
424 | 4 | str += Substitute("\"tag\":\"$0\"", FLAGS_callhome_tag); |
425 | 4 | } |
426 | 4 | str += "}"; |
427 | | |
428 | 4 | rapidjson::StringBuffer buffer; |
429 | 4 | rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); |
430 | 4 | rapidjson::Reader reader; |
431 | 4 | rapidjson::StringStream ss(str.c_str()); |
432 | 4 | if (!reader.Parse<rapidjson::kParseDefaultFlags>(ss, writer)) { |
433 | 0 | LOG(ERROR) << "Unable to parse json. Error: " << reader.GetParseErrorCode() |
434 | 0 | << " at offset " << reader.GetErrorOffset() << " in string " << |
435 | 0 | str.substr(reader.GetErrorOffset(), 10); |
436 | 0 | return str; |
437 | 0 | } |
438 | | |
439 | 4 | return buffer.GetString(); |
440 | 4 | } |
441 | | |
442 | 1 | void CallHome::BuildJsonAndSend() { |
443 | 1 | auto json = BuildJson(); |
444 | 1 | SendData(json); |
445 | 1 | } |
446 | | |
447 | 1.11M | void CallHome::DoCallHome() { |
448 | 1.11M | if (FLAGS_callhome_enabled) { |
449 | 1 | if (server_type_ == ServerType::MASTER && |
450 | 1 | !master()->catalog_manager()->CheckIsLeaderAndReady().ok()) { |
451 | 0 | VLOG(3) << "This master instance is not a leader. Skipping call home"; |
452 | 1 | } else { |
453 | 1 | BuildJsonAndSend(); |
454 | 1 | } |
455 | 1 | } |
456 | | |
457 | 1.11M | ScheduleCallHome(FLAGS_callhome_interval_secs); |
458 | 1.11M | } |
459 | | |
460 | 4 | void CallHome::SendData(const string& payload) { |
461 | 4 | faststring reply; |
462 | | |
463 | 4 | auto status = curl_.PostToURL(FLAGS_callhome_url, payload, "application/json", &reply); |
464 | 4 | if (!status.ok()) { |
465 | 0 | LOG(INFO) << "Unable to send diagnostics data to " << FLAGS_callhome_url; |
466 | 0 | } |
467 | 0 | VLOG(1) << "Received reply: " << reply; |
468 | 4 | } |
469 | | |
470 | 1.12M | void CallHome::ScheduleCallHome(int delay_seconds) { |
471 | 1.11M | scheduler_->Schedule([this](const Status& status) { DoCallHome(); }, |
472 | 1.12M | std::chrono::seconds(delay_seconds)); |
473 | 1.12M | } |
474 | | |
475 | 4 | CollectionLevel CallHome::GetCollectionLevel() { |
476 | 4 | if (FLAGS_callhome_collection_level == kHighLevel) { |
477 | 1 | return CollectionLevel::HIGH; |
478 | 3 | } else if (FLAGS_callhome_collection_level == kMediumLevel) { |
479 | 2 | return CollectionLevel::MEDIUM; |
480 | 1 | } else if (FLAGS_callhome_collection_level == kLowLevel) { |
481 | 1 | return CollectionLevel::LOW; |
482 | 1 | } |
483 | 0 | return CollectionLevel::LOW; |
484 | 0 | } |
485 | | |
486 | 1 | master::Master* CallHome::master() { |
487 | 1 | return down_cast<master::Master*>(server_); |
488 | 1 | } |
489 | | |
490 | 0 | tserver::TabletServer* CallHome::tserver() { |
491 | 0 | return down_cast<tserver::TabletServer*>(server_); |
492 | 0 | } |
493 | | |
494 | | } // namespace yb |