18 namespace SWC {
namespace Utils {
namespace shell {
22 "host",
"group",
"role",
"id",
"component",
"part",
"type"
27 :
Interface(
"\033[32mSWC-DB(\033[36mstatistics\033[32m)\033[33m> \033[00m",
28 "/tmp/.swc-cli-statistics-history",
30 with_broker(Env::Config::settings()->get_bool(
"with-broker")),
33 ? client::Clients::make(
34 *Env::Config::settings(),
35 Comm::IoContext::make(
"Statistics", 8),
38 : client::Clients::make(
39 *Env::Config::settings(),
40 Comm::IoContext::make(
"Statistics", 8),
48 m_read_groups(), m_definitions() {
52 {
"show last='DURATION' since='DATETIME' agg='DURATION'",
53 " host='STRING' group='STRING' role='STRING' id='STRING'",
54 " component='STRING' part='STRING' type='STRING' metric='STRING'",
56 " -> show last=30day group=swcdb role=rgr component=fs part=broker;",
57 " # show Fs-Broker stats on Ranger for the last 30 days",
58 " -> show since='2021/05/01 00:00:00' component='cpu';",
59 " # show CPU on all roles having CPU metrics since May of 2021",
60 "* STRING: string-type definition is optional",
61 "* DURATION: in Decimal[week|day|hour|minute] (4week)",
62 "* DATETIME: in format YYYY/MM/DD HH:mm:ss or seconds-timestamp",
63 "* 'last=': The Duration set or NONE default to 7day",
64 "* 'since=': The Datetime set or NONE for since (now-'last'|ever)",
65 "* 'agg=': The Duration for aggregations or NONE into-single entry",
66 "* AND: Another metrics group"
68 [
this](std::string& cmd) {
return read(cmd,
true); },
73 {
"list metrics host='STRING' group='STRING' role='STRING' id='STRING'",
74 " component='STRING' part='STRING' type='STRING' AND .. ;",
76 " # List all metrics definitions"
78 [
this](std::string& cmd) {
return read(cmd,
false); },
79 "(?i)^list metrics(.*|$)"
83 {
"truncate last='DURATION' since='DATETIME' agg='DURATION'",
84 " host='STRING' group='STRING' role='STRING' id='STRING'",
85 " component='STRING' part='STRING'",
86 " type='STRING' AND ..;",
88 " # Truncate all metrics"
90 [
this](std::string& cmd) {
return read(cmd,
true); },
95 {
"set stat-names F1,F2, .. or 'swcdb-default';",
96 "* swcdb-default: host,group,role,id,component,part,type"},
97 [
this](std::string& cmd) {
return read(cmd,
false); },
98 "(?i)^set stat-names(.*|$)"
102 {
"list stat-names;"},
103 [
this](std::string&) {
113 "(?i)^list stat-names(.*|$)"
126 out <<
"last=" <<
last <<
"s ";
128 out <<
"since=" <<
since <<
"s ";
130 out <<
"agg=" <<
agg <<
"s ";
131 for(
size_t i=0; i <
key.
size(); ++i) {
136 out <<
" metric=" <<
metric <<
' ';
173 parser.
read(buf,
",");
185 return error(
"Empty stat names list");
187 bool token_cmd =
false;
188 parser.
expect_token(
"list metrics|show|truncate", 1, token_cmd);
212 parser.
read(buf,
" ");
217 group->since /= 1000000000;
235 parser.
read(group->metric,
" ");
243 parser.
read(buf,
" =");
249 parser.
read(group->key[i],
" ");
277 auto it = g.key.begin();
278 auto it_set = g.key.cbegin();
279 for(; it != g.key.cend(); ++it) {
287 if(it == g.key.cbegin()) {
289 }
else if(it_set != g.key.cend() &&
290 ++it_set != g.key.cend() &&
291 ++it_set != g.key.cend()) {
292 g.key.erase(it_set, g.key.cend());
313 : property(), metrics() {
320 const uint8_t* ptr = v.
base;
321 size_t remain = v.
size;
335 else if(value.
fid == 3)
337 else if(value.
fid == 4)
345 else if(value.
fid == 2)
355 for(
size_t i =0; i < ids.
size(); ++i) {
357 metrics[i].relation = i < relations.
size() ? relations[i] : 0;
358 metrics[i].agg = i < aggregations.
size() ? aggregations[i] : 0;
360 metrics[i].name = std::move(names[i]);
363 if(i < labels.
size())
364 metrics[i].label = std::move(labels[i]);
380 for(i=0; i < metrics.size(); ++i) {
381 if(metrics[i].
id == fid) {
382 if(!name.empty() && (metrics[i].name.empty() ||
393 bool only_property)
const {
394 out <<
"# property:";
395 for(
size_t i = 1; i <
property.size(); ++i) {
401 out <<
'=' <<
property[i];
406 size_t len_relation = 8;
409 size_t len_label = 5;
410 for(
auto& metric : metrics) {
411 if(len_name < metric.name.length())
412 len_name = metric.name.length();
413 if(len_label < metric.label.length())
414 len_label = metric.label.length();
419 if(len_relation < tmp)
428 out << std::left << std::setw(3) <<
" "
429 << std::left << std::setw(len_name) <<
"Metric"
430 << std::left << std::setw(len_id) <<
"ID"
431 << std::left << std::setw(len_label) <<
"Label"
432 << std::left << std::setw(len_relation) <<
"Relation"
433 << std::left <<
"Aggregation";
435 for(
auto& metric : metrics) {
436 out << std::left << std::setw(3) <<
" "
437 << std::left << std::setw(len_name) << metric.name
438 << std::left << std::setw(len_id) << metric.id
439 << std::left << std::setw(len_label) << metric.label
440 << std::left << std::setw(len_relation) << metric.relation
457 auto& key_intval = col.add(
460 key_intval.start.copy(g.key);
461 key_intval.start.insert(
475 for(
cid_t cid : _hdlr->get_cids()) {
476 _hdlr->get_cells(cid, cells);
477 m_definitions.reserve(cells.size());
478 for(auto cell : cells) {
480 m_definitions.emplace_back(*cell);
482 SWC_LOG_CURRENT_EXCEPTION(
"");
484 cell->print(SWC_LOG_OSTREAM, DB::Types::Column::SERIAL);
485 SWC_LOG_OSTREAM << SWC_PRINT_CLOSE;
498 hdlr->scan(
err, specs);
534 size_t len_value = 5;
539 if(len_name < m.name.length())
540 len_name = m.name.length();
554 std::strftime(res, 20,
"%Y/%m/%d %H:%M:%S", std::gmtime(&
ts));
555 out <<
" since " << res;
557 time_t tmp =
ts + group.
agg-1;
558 std::strftime(res, 20,
"%Y/%m/%d %H:%M:%S", std::gmtime(&tmp));
559 out <<
" to " << res;
563 out << std::left << std::setw(3) <<
" "
564 << std::left << std::setw(len_name) <<
"Metric"
565 << std::left << std::setw(len_value) <<
"Value"
566 << std::left <<
"Label";
576 value.append(
"(!prop)");
577 out << std::left << std::setw(3) <<
" "
578 << std::left << std::setw(len_name) << m.name
579 << std::left << std::setw(len_value) << value
580 << std::left << m.label;
588 size_t metric_idx,
uint24_t field_id,
589 int64_t value) noexcept {
592 for(;idx < values.size(); ++idx) {
593 if((found = values[idx].
id == field_id))
598 values.emplace_back(field_id);
600 auto&
data = values[idx];
602 auto& m = defined->metrics[metric_idx];
605 if(!found || value >
data.total)
610 if(!found || value <
data.total)
617 for(
auto& stat : *datasp) {
618 if(defined != stat.defined || ts != stat.ts)
620 for(
auto& other_m : defined->metrics) {
623 m.relation != other_m.relation)
625 for(
auto& other_v : stat.values) {
626 if(other_v.id == other_m.id) {
627 data.count += other_v.last;
628 data.total += value * other_v.last;
664 bool empty = g.key.empty();
670 key_intval.finish.add(
675 int64_t secs = ::time(
nullptr);
676 key_intval.start.insert(
681 if(empty && !key_intval.start.empty())
693 [
this, &g, datasp=&stats_datas]
696 if(!
err && !(
err = _hdlr->state_error)) {
697 auto col = _hdlr->get_columnn(DB::Types::SystemColumn::SYS_CID_STATS);
698 if(!(err = col->error()) && !col->empty())
699 col->get_cells(cells);
702 _hdlr->valid_state.store(false);
706 for(
auto cell : cells) {
707 for(auto& defined : m_definitions) {
708 if(defined.property.is_matching_lexic(cell->key)) {
710 time_t ts = (cell->get_timestamp()/1000000000);
716 cell->get_value(v, false);
717 const uint8_t* ptr = v.base;
718 size_t remain = v.size;
721 SWC::DB::Cell::Serial::Value::read_type(&ptr, &remain);
725 DB::Cell::Serial::Value::Field_INT64 field(&ptr, &remain);
726 if(!defined.has_metric(g.metric, field.fid, metric_idx))
729 Stats* statsp = nullptr;
730 for(auto& stats : *datasp) {
731 if(stats.defined == &defined &&
732 (!g.agg || (stats.ts + g.agg > ts && stats.ts <= ts))) {
737 (statsp ? statsp : &datasp->emplace_back(&defined, ts))
738 ->add(datasp, metric_idx, field.fid, field.value);
759 DB::Types::KeySeq::LEXIC,
764 if(
err || (
err = hdlr->state_error))
768 for(
auto&
data : stats_datas)
791 [countp=&deleted_count]
793 if(_hdlr->state_error) {
794 _hdlr->valid_state.store(false);
796 auto col = _hdlr->get_columnn(DB::Types::SystemColumn::SYS_CID_STATS);
798 _hdlr->valid_state.store(false);
799 }
else if(!col->empty()) {
800 DB::Cells::Result cells;
801 col->get_cells(cells);
802 countp->fetch_add(cells.size());
816 for(
auto& g : m_read_groups) {
818 intval->set_opt__deleting();
819 intval->flags.set_only_keys();
820 auto& key_intval = intval->key_intervals.add();
822 bool empty = g.key.empty();
824 key_intval.start.copy(g.key);
828 key_intval.finish.add(
833 int64_t secs = ::time(
nullptr);
834 key_intval.start.insert(
839 if(empty && !key_intval.start.empty())
847 for(
auto& g : m_read_groups)
851 hdlr->scan(err, std::move(specs));
854 err = hdlr->state_error.load();
857 return err ? error(m_message) : true;