/******************************************************************************
* Icinga 2 *
- * Copyright (C) 2012-2016 Icinga Development Team (https://www.icinga.org/) *
+ * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String& compat_log_path)
: m_KeepAlive(false), m_OutputFormat("csv"), m_ColumnHeaders(true), m_Limit(-1), m_ErrorCode(0),
- m_LogTimeFrom(0), m_LogTimeUntil(static_cast<long>(Utility::GetTime()))
+ m_LogTimeFrom(0), m_LogTimeUntil(static_cast<long>(Utility::GetTime()))
{
if (lines.size() == 0) {
m_Verb = "ERROR";
m_CompatLogPath = compat_log_path;
/* default separators */
- m_Separators.push_back("\n");
- m_Separators.push_back(";");
- m_Separators.push_back(",");
- m_Separators.push_back("|");
+ m_Separators.emplace_back("\n");
+ m_Separators.emplace_back(";");
+ m_Separators.emplace_back(",");
+ m_Separators.emplace_back("|");
String line = lines[0];
if (header == "Or" || header == "StatsOr") {
filter = new OrFilter();
Log(LogDebug, "LivestatusQuery")
- << "Add OR filter for " << params << " column(s). " << deq.size() << " filters available.";
+ << "Add OR filter for " << params << " column(s). " << deq.size() << " filters available.";
} else {
filter = new AndFilter();
Log(LogDebug, "LivestatusQuery")
- << "Add AND filter for " << params << " column(s). " << deq.size() << " filters available.";
+ << "Add AND filter for " << params << " column(s). " << deq.size() << " filters available.";
}
if (num > deq.size()) {
while (num > 0 && num--) {
filter->AddSubFilter(deq.back());
Log(LogDebug, "LivestatusQuery")
- << "Add " << num << " filter.";
+ << "Add " << num << " filter.";
deq.pop_back();
if (&deq == &stats)
aggregators.pop_back();
}
- deq.push_back(filter);
+ deq.emplace_back(filter);
if (&deq == &stats) {
Aggregator::Ptr aggregator = new CountAggregator();
aggregator->SetFilter(filter);
m_Aggregators.swap(aggregators);
}
-int LivestatusQuery::GetExternalCommands(void)
+int LivestatusQuery::GetExternalCommands()
{
boost::mutex::scoped_lock lock(l_QueryMutex);
break;
}
- tokens.push_back(temp_buffer.SubStr(0, sp_index));
+ tokens.emplace_back(temp_buffer.SubStr(0, sp_index));
temp_buffer = temp_buffer.SubStr(sp_index + 1);
}
/* add the rest as value */
- tokens.push_back(temp_buffer);
+ tokens.emplace_back(std::move(temp_buffer));
if (tokens.size() == 2)
- tokens.push_back("");
+ tokens.emplace_back("");
if (tokens.size() < 3)
- return Filter::Ptr();
+ return nullptr;
bool negate = false;
String attr = tokens[0];
}
Log(LogDebug, "LivestatusQuery")
- << "Parsed filter with attr: '" << attr << "' op: '" << op << "' val: '" << val << "'.";
+ << "Parsed filter with attr: '" << attr << "' op: '" << op << "' val: '" << val << "'.";
return filter;
}
void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
{
Log(LogNotice, "LivestatusQuery")
- << "Table: " << m_Table;
+ << "Table: " << m_Table;
Table::Ptr table = Table::GetByName(m_Table, m_CompatLogPath, m_LogTimeFrom, m_LogTimeUntil);
column_objs.reserve(columns.size());
for (const String& columnName : columns)
- column_objs.push_back(std::make_pair(columnName, table->GetColumn(columnName)));
+ column_objs.emplace_back(columnName, table->GetColumn(columnName));
for (const LivestatusRowValue& object : objects) {
Array::Ptr row = new Array();
AppendResultRow(result, row, first_row);
}
} else {
- std::vector<double> stats(m_Aggregators.size(), 0);
- int index = 0;
+ std::map<std::vector<Value>, std::vector<AggregatorState *> > allStats;
/* add aggregated stats */
- for (const Aggregator::Ptr aggregator : m_Aggregators) {
- for (const LivestatusRowValue& object : objects) {
- aggregator->Apply(table, object.Row);
+ for (const LivestatusRowValue& object : objects) {
+ std::vector<Value> statsKey;
+
+ for (const String& columnName : m_Columns) {
+ Column column = table->GetColumn(columnName);
+ statsKey.emplace_back(column.ExtractValue(object.Row, object.GroupByType, object.GroupByObject));
+ }
+
+ auto it = allStats.find(statsKey);
+
+ if (it == allStats.end()) {
+ std::vector<AggregatorState *> newStats(m_Aggregators.size(), nullptr);
+ it = allStats.insert(std::make_pair(statsKey, newStats)).first;
}
- stats[index] = aggregator->GetResult();
- index++;
+ auto& stats = it->second;
+
+ int index = 0;
+
+ for (const Aggregator::Ptr& aggregator : m_Aggregators) {
+ aggregator->Apply(table, object.Row, &stats[index]);
+ index++;
+ }
}
/* add column headers both for raw and aggregated data */
AppendResultRow(result, header, first_row);
}
- Array::Ptr row = new Array();
+ for (const auto& kv : allStats) {
+ Array::Ptr row = new Array();
- row->Reserve(m_Columns.size() + m_Aggregators.size());
+ row->Reserve(m_Columns.size() + m_Aggregators.size());
- /*
- * add selected columns next to stats
- * may not be accurate for grouping!
- */
- if (objects.size() > 0 && m_Columns.size() > 0) {
- for (const String& columnName : m_Columns) {
- Column column = table->GetColumn(columnName);
+ for (const Value& keyPart : kv.first) {
+ row->Add(keyPart);
+ }
- LivestatusRowValue object = objects[0]; //first object wins
+ auto& stats = kv.second;
- row->Add(column.ExtractValue(object.Row, object.GroupByType, object.GroupByObject));
- }
+ for (size_t i = 0; i < m_Aggregators.size(); i++)
+ row->Add(m_Aggregators[i]->GetResultAndFreeState(stats[i]));
+
+ AppendResultRow(result, row, first_row);
}
- for (size_t i = 0; i < m_Aggregators.size(); i++)
- row->Add(stats[i]);
+ /* add a bogus zero value if aggregated is empty*/
+ if (allStats.empty()) {
+ Array::Ptr row = new Array();
- AppendResultRow(result, row, first_row);
+ for (size_t i = 1; i <= m_Aggregators.size(); i++) {
+ row->Add(0);
+ }
+
+ AppendResultRow(result, row, first_row);
+ }
}
EndResultSet(result);
}
Log(LogNotice, "LivestatusQuery")
- << "Executing command: " << m_Command;
+ << "Executing command: " << m_Command;
ExternalCommandProcessor::Execute(m_Command);
SendResponse(stream, LivestatusErrorOK, "");
}
void LivestatusQuery::ExecuteErrorHelper(const Stream::Ptr& stream)
{
Log(LogDebug, "LivestatusQuery")
- << "ERROR: Code: '" << m_ErrorCode << "' Message: '" << m_ErrorMessage << "'.";
+ << "ERROR: Code: '" << m_ErrorCode << "' Message: '" << m_ErrorMessage << "'.";
SendResponse(stream, m_ErrorCode, m_ErrorMessage);
}
{
try {
Log(LogNotice, "LivestatusQuery")
- << "Executing livestatus query: " << m_Verb;
+ << "Executing livestatus query: " << m_Verb;
if (m_Verb == "GET")
ExecuteGetHelper(stream);