]> granicus.if.org Git - icinga2/blobdiff - lib/livestatus/livestatusquery.cpp
Move CompatUtility::GetCheckableInCheckPeriod() into Livestatus feature
[icinga2] / lib / livestatus / livestatusquery.cpp
index 010a93367a9c4cafb9738ea32b3cfce34e45a982..a8e7577aa21813933d77ba4ca7656347d6c78030 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  * 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                *
@@ -53,7 +53,7 @@ static boost::mutex l_QueryMutex;
 
 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";
@@ -71,10 +71,10 @@ LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String&
        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];
 
@@ -210,11 +210,11 @@ LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String&
                        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()) {
@@ -227,13 +227,13 @@ LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String&
                        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);
@@ -279,7 +279,7 @@ LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String&
        m_Aggregators.swap(aggregators);
 }
 
-int LivestatusQuery::GetExternalCommands(void)
+int LivestatusQuery::GetExternalCommands()
 {
        boost::mutex::scoped_lock lock(l_QueryMutex);
 
@@ -309,18 +309,18 @@ Filter::Ptr LivestatusQuery::ParseFilter(const String& params, unsigned long& fr
                        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];
@@ -356,7 +356,7 @@ Filter::Ptr LivestatusQuery::ParseFilter(const String& params, unsigned long& fr
        }
 
        Log(LogDebug, "LivestatusQuery")
-           << "Parsed filter with attr: '" << attr << "' op: '" << op << "' val: '" << val << "'.";
+               << "Parsed filter with attr: '" << attr << "' op: '" << op << "' val: '" << val << "'.";
 
        return filter;
 }
@@ -459,7 +459,7 @@ String LivestatusQuery::QuoteStringPython(const String& str) {
 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);
 
@@ -490,7 +490,7 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                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();
@@ -512,17 +512,32 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                        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 */
@@ -540,28 +555,33 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                        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);
@@ -578,7 +598,7 @@ void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream)
        }
 
        Log(LogNotice, "LivestatusQuery")
-           << "Executing command: " << m_Command;
+               << "Executing command: " << m_Command;
        ExternalCommandProcessor::Execute(m_Command);
        SendResponse(stream, LivestatusErrorOK, "");
 }
@@ -586,7 +606,7 @@ void LivestatusQuery::ExecuteCommandHelper(const Stream::Ptr& stream)
 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);
 }
 
@@ -624,7 +644,7 @@ bool LivestatusQuery::Execute(const Stream::Ptr& stream)
 {
        try {
                Log(LogNotice, "LivestatusQuery")
-                   << "Executing livestatus query: " << m_Verb;
+                       << "Executing livestatus query: " << m_Verb;
 
                if (m_Verb == "GET")
                        ExecuteGetHelper(stream);