|
20 | 20 | */ |
21 | 21 | #include <fstream> |
22 | 22 | #include <unordered_map> |
| 23 | +#include <chrono> |
| 24 | +#include <thread> |
23 | 25 |
|
24 | 26 | #include "CtrlCommands.h" |
25 | 27 | #include "jsonrpc/CtrlRPCRequests.h" |
@@ -241,6 +243,9 @@ MetricCommand::MetricCommand(ts::Arguments *args) : RecordCommand(args) |
241 | 243 | } else if (args->get(ZERO_STR)) { |
242 | 244 | _printer = std::make_unique<GenericPrinter>(printOpts); |
243 | 245 | _invoked_func = [&]() { metric_zero(); }; |
| 246 | + } else if (args->get(MONITOR_STR)) { |
| 247 | + _printer = std::make_unique<MetricRecordPrinter>(printOpts); |
| 248 | + _invoked_func = [&]() { metric_monitor(); }; |
244 | 249 | } |
245 | 250 | } |
246 | 251 |
|
@@ -277,6 +282,86 @@ MetricCommand::metric_zero() |
277 | 282 |
|
278 | 283 | [[maybe_unused]] auto const &response = invoke_rpc(request); |
279 | 284 | } |
| 285 | + |
| 286 | +void |
| 287 | +MetricCommand::metric_monitor() |
| 288 | +{ |
| 289 | + ts::ArgumentData const &arg = get_parsed_arguments()->get(MONITOR_STR); |
| 290 | + std::string err_text; |
| 291 | + |
| 292 | + // |
| 293 | + // Note: if any of the string->number fails, the exception will be caught by the invoke function from the ArgParser. |
| 294 | + // |
| 295 | + const int32_t count = std::stoi(get_parsed_arguments()->get("count").value()); |
| 296 | + const int32_t interval = std::stoi(get_parsed_arguments()->get("interval").value()); |
| 297 | + if (count <= 0 || interval <= 0) { |
| 298 | + throw std::runtime_error( |
| 299 | + ts::bwprint(err_text, "monitor: invalid input, count({}), interval({}) should be > than '0'", count, interval)); |
| 300 | + } |
| 301 | + |
| 302 | + // keep track of each metric |
| 303 | + struct ctx { |
| 304 | + float min{std::numeric_limits<float>::max()}; |
| 305 | + float max{std::numeric_limits<float>::lowest()}; |
| 306 | + float sum{0.0f}; |
| 307 | + float last{0.0f}; |
| 308 | + }; |
| 309 | + |
| 310 | + // Keep track of the requested metric(s), we support more than one at the same time. |
| 311 | + std::unordered_map<std::string, ctx> summary; |
| 312 | + |
| 313 | + for (int idx = 0;; idx++) { |
| 314 | + // Request will hold all metrics in a single message. |
| 315 | + shared::rpc::JSONRPCResponse const &resp = record_fetch(arg, shared::rpc::NOT_REGEX, RecordQueryType::METRIC); |
| 316 | + |
| 317 | + if (resp.is_error()) { // something went wrong in the server, report it. |
| 318 | + _printer->write_output(resp); |
| 319 | + return; |
| 320 | + } |
| 321 | + |
| 322 | + auto const &response = resp.result.as<shared::rpc::RecordLookUpResponse>(); |
| 323 | + if (response.errorList.size() && response.recordList.size() == 0) { |
| 324 | + // nothing to be done or report, use '-f rpc' for details. |
| 325 | + break; |
| 326 | + } |
| 327 | + |
| 328 | + for (auto &&rec : response.recordList) { // requested metric(s) |
| 329 | + auto &s = summary[rec.name]; // We will update it. |
| 330 | + // Note: To avoid |
| 331 | + const float val = std::stof(rec.currentValue); |
| 332 | + |
| 333 | + s.sum += val; |
| 334 | + s.max = std::max<float>(s.max, val); |
| 335 | + s.min = std::min<float>(s.min, val); |
| 336 | + std::string symbol; |
| 337 | + if (idx > 0) { |
| 338 | + if (val > s.last) { |
| 339 | + symbol = "+"; |
| 340 | + } else if (val < s.last) { |
| 341 | + symbol = "-"; |
| 342 | + } |
| 343 | + } |
| 344 | + s.last = val; |
| 345 | + _printer->write_output(ts::bwprint(err_text, "{}: {} {}", rec.name, rec.currentValue, symbol)); |
| 346 | + } |
| 347 | + if (idx == count - 1) { |
| 348 | + break; |
| 349 | + } |
| 350 | + std::this_thread::sleep_for(std::chrono::seconds(interval)); |
| 351 | + } |
| 352 | + if (summary.size() == 0) { |
| 353 | + // nothing to report. |
| 354 | + return; |
| 355 | + } |
| 356 | + |
| 357 | + _printer->write_output("--- metric monitor statistics ---"); |
| 358 | + |
| 359 | + for (auto &&item : summary) { |
| 360 | + ctx const &s = item.second; |
| 361 | + const int avg = s.sum / count; |
| 362 | + _printer->write_output(ts::bwprint(err_text, "┌ {}\n└─ min/avg/max = {:.5}/{}/{:.5}", item.first, s.min, avg, s.max)); |
| 363 | + } |
| 364 | +} |
280 | 365 | //------------------------------------------------------------------------------------------------------------------------------------ |
281 | 366 | // TODO, let call the super const |
282 | 367 | HostCommand::HostCommand(ts::Arguments *args) : CtrlCommand(args) |
|
0 commit comments