]> granicus.if.org Git - icinga2/blobdiff - lib/livestatus/livestatusquery.cpp
Move CompatUtility::GetCheckableInCheckPeriod() into Livestatus feature
[icinga2] / lib / livestatus / livestatusquery.cpp
index 0e048d7151b9f5e46d0359f48629f05d89793d26..a8e7577aa21813933d77ba4ca7656347d6c78030 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  * Icinga 2                                                                   *
- * Copyright (C) 2012-2015 Icinga Development Team (http://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                *
@@ -42,7 +42,6 @@
 #include "base/timer.hpp"
 #include "base/initialize.hpp"
 #include <boost/algorithm/string/classification.hpp>
-#include <boost/foreach.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <boost/algorithm/string/join.hpp>
@@ -54,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";
@@ -64,7 +63,7 @@ LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String&
        }
 
        String msg;
-       BOOST_FOREACH(const String& line, lines) {
+       for (const String& line : lines) {
                msg += line + "\n";
        }
        Log(LogDebug, "LivestatusQuery", msg);
@@ -72,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];
 
@@ -211,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()) {
@@ -228,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);
@@ -272,7 +271,7 @@ LivestatusQuery::LivestatusQuery(const std::vector<String>& lines, const String&
        /* Combine all top-level filters into a single filter. */
        AndFilter::Ptr top_filter = new AndFilter();
 
-       BOOST_FOREACH(const Filter::Ptr& filter, filters) {
+       for (const Filter::Ptr& filter : filters) {
                top_filter->AddSubFilter(filter);
        }
 
@@ -280,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);
 
@@ -310,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];
@@ -357,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;
 }
@@ -380,7 +379,7 @@ void LivestatusQuery::AppendResultRow(std::ostream& fp, const Array::Ptr& row, b
                bool first = true;
 
                ObjectLock rlock(row);
-               BOOST_FOREACH(const Value& value, row) {
+               for (const Value& value : row) {
                        if (first)
                                first = false;
                        else
@@ -413,7 +412,7 @@ void LivestatusQuery::PrintCsvArray(std::ostream& fp, const Array::Ptr& array, i
        bool first = true;
 
        ObjectLock olock(array);
-       BOOST_FOREACH(const Value& value, array) {
+       for (const Value& value : array) {
                if (first)
                        first = false;
                else
@@ -434,7 +433,7 @@ void LivestatusQuery::PrintPythonArray(std::ostream& fp, const Array::Ptr& rs) c
 
        bool first = true;
 
-       BOOST_FOREACH(const Value& value, rs) {
+       for (const Value& value : rs) {
                if (first)
                        first = false;
                else
@@ -460,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,15 +489,15 @@ void LivestatusQuery::ExecuteGetHelper(const Stream::Ptr& stream)
                std::vector<ColumnPair> column_objs;
                column_objs.reserve(columns.size());
 
-               BOOST_FOREACH(const String& columnName, columns)
-                       column_objs.push_back(std::make_pair(columnName, table->GetColumn(columnName)));
+               for (const String& columnName : columns)
+                       column_objs.emplace_back(columnName, table->GetColumn(columnName));
 
-               BOOST_FOREACH(const LivestatusRowValue& object, objects) {
+               for (const LivestatusRowValue& object : objects) {
                        Array::Ptr row = new Array();
 
                        row->Reserve(column_objs.size());
 
-                       BOOST_FOREACH(const ColumnPair& cv, column_objs) {
+                       for (const ColumnPair& cv : column_objs) {
                                if (m_ColumnHeaders)
                                        header->Add(cv.first);
 
@@ -513,24 +512,39 @@ 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 */
-               BOOST_FOREACH(const Aggregator::Ptr aggregator, m_Aggregators) {
-                       BOOST_FOREACH(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 */
                if (m_ColumnHeaders) {
                        Array::Ptr header = new Array();
 
-                       BOOST_FOREACH(const String& columnName, m_Columns) {
+                       for (const String& columnName : m_Columns) {
                                header->Add(columnName);
                        }
 
@@ -541,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) {
-                       BOOST_FOREACH(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();
+
+                       for (size_t i = 1; i <= m_Aggregators.size(); i++) {
+                               row->Add(0);
+                       }
 
-               AppendResultRow(result, row, first_row);
+                       AppendResultRow(result, row, first_row);
+               }
        }
 
        EndResultSet(result);
@@ -579,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, "");
 }
@@ -587,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);
 }
 
@@ -625,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);