From: Michael Friedrich Date: Thu, 11 Jul 2013 13:52:01 +0000 (+0200) Subject: livestatus: add basic aggregator support X-Git-Tag: v0.0.3~857 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4f75ba03ff0a16515d6a034284ba91a278377721;p=icinga2 livestatus: add basic aggregator support refs #4398 --- diff --git a/components/livestatus/Makefile.am b/components/livestatus/Makefile.am index 67c1ed41d..3699921c6 100644 --- a/components/livestatus/Makefile.am +++ b/components/livestatus/Makefile.am @@ -10,6 +10,8 @@ EXTRA_DIST = \ $(top_builddir)/tools/mkembedconfig/mkembedconfig $< $@ liblivestatus_la_SOURCES = \ + aggregator.cpp \ + aggregator.h \ attributefilter.cpp \ attributefilter.h \ andfilter.cpp \ @@ -28,6 +30,8 @@ liblivestatus_la_SOURCES = \ contactgroupstable.h \ contactstable.cpp \ contactstable.h \ + countaggregator.cpp \ + countaggregator.h \ downtimestable.cpp \ downtimestable.h \ filter.cpp \ diff --git a/components/livestatus/aggregator.cpp b/components/livestatus/aggregator.cpp new file mode 100644 index 000000000..06c286fd8 --- /dev/null +++ b/components/livestatus/aggregator.cpp @@ -0,0 +1,35 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "livestatus/aggregator.h" + +using namespace livestatus; + +Aggregator::Aggregator(void) +{ } + +void Aggregator::SetFilter(const Filter::Ptr& filter) +{ + m_Filter = filter; +} + +Filter::Ptr Aggregator::GetFilter(void) const +{ + return m_Filter; +} diff --git a/components/livestatus/aggregator.h b/components/livestatus/aggregator.h new file mode 100644 index 000000000..803134a95 --- /dev/null +++ b/components/livestatus/aggregator.h @@ -0,0 +1,52 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef AGGREGATOR_H +#define AGGREGATOR_H + +#include "livestatus/table.h" +#include "livestatus/filter.h" + +namespace livestatus +{ + +/** + * @ingroup livestatus + */ +class Aggregator : public Object +{ +public: + DECLARE_PTR_TYPEDEFS(Aggregator); + + virtual void Apply(const Table::Ptr& table, const Value& row) = 0; + virtual double GetResult(void) const = 0; + void SetFilter(const Filter::Ptr& filter); + +protected: + Aggregator(void); + + Filter::Ptr GetFilter(void) const; + +private: + Filter::Ptr m_Filter; +}; + +} + +#endif /* AGGREGATOR_H */ diff --git a/components/livestatus/countaggregator.cpp b/components/livestatus/countaggregator.cpp new file mode 100644 index 000000000..54df56774 --- /dev/null +++ b/components/livestatus/countaggregator.cpp @@ -0,0 +1,37 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "livestatus/countaggregator.h" + +using namespace livestatus; + +CountAggregator::CountAggregator(void) + : m_Count(0) +{ } + +void CountAggregator::Apply(const Table::Ptr& table, const Value& row) +{ + if (GetFilter()->Apply(table, row)) + m_Count++; +} + +double CountAggregator::GetResult(void) const +{ + return m_Count; +} diff --git a/components/livestatus/countaggregator.h b/components/livestatus/countaggregator.h new file mode 100644 index 000000000..aea0858ba --- /dev/null +++ b/components/livestatus/countaggregator.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012 Icinga Development Team (http://www.icinga.org/) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef COUNTAGGREGATOR_H +#define COUNTAGGREGATOR_H + +#include "livestatus/table.h" +#include "livestatus/aggregator.h" + +namespace livestatus +{ + +/** + * @ingroup livestatus + */ +class CountAggregator : public Aggregator +{ +public: + DECLARE_PTR_TYPEDEFS(CountAggregator); + + CountAggregator(void); + + virtual void Apply(const Table::Ptr& table, const Value& row); + virtual double GetResult(void) const; + +private: + int m_Count; +}; + +} + +#endif /* COUNTAGGREGATOR_H */ diff --git a/components/livestatus/query.cpp b/components/livestatus/query.cpp index 879360158..02ce92f4e 100644 --- a/components/livestatus/query.cpp +++ b/components/livestatus/query.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "livestatus/query.h" +#include "livestatus/countaggregator.h" #include "livestatus/attributefilter.h" #include "livestatus/negatefilter.h" #include "livestatus/orfilter.h" @@ -63,6 +64,7 @@ Query::Query(const std::vector& lines) } std::deque filters, stats; + std::deque aggregators; for (unsigned int i = 1; i < lines.size(); i++) { line = lines[i]; @@ -80,43 +82,24 @@ Query::Query(const std::vector& lines) else if (header == "ColumnHeaders") m_ColumnHeaders = (params == "on"); else if (header == "Filter" || header == "Stats") { - std::vector tokens; - boost::algorithm::split(tokens, params, boost::is_any_of(" ")); - if (tokens.size() == 2) - tokens.push_back(""); - - if (tokens.size() < 3) { + Filter::Ptr filter = ParseFilter(params); + + if (!filter) { m_Verb = "ERROR"; m_ErrorCode = 452; - m_ErrorMessage = "Expected 3 parameters in the filter specification."; + m_ErrorMessage = "Invalid filter specification."; return; } - String op = tokens[1]; - bool negate = false; - - if (op == "!=") { - op = "="; - negate = true; - } else if (op == "!~") { - op = "~"; - negate = true; - } else if (op == "!=~") { - op = "=~"; - negate = true; - } else if (op == "!~~") { - op = "~~"; - negate = true; - } - - Filter::Ptr filter = boost::make_shared(tokens[0], op, tokens[2]); - - if (negate) - filter = boost::make_shared(filter); - std::deque& deq = (header == "Filter") ? filters : stats; deq.push_back(filter); + + if (deq == stats) { + Aggregator::Ptr aggregator = boost::make_shared(); + aggregator->SetFilter(filter); + aggregators.push_back(aggregator); + } } else if (header == "Or" || header == "And") { std::deque& deq = (header == "Or" || header == "And") ? filters : stats; @@ -155,6 +138,11 @@ Query::Query(const std::vector& lines) filters.pop_back(); deq.push_back(boost::make_shared(filter)); + + if (deq == stats) { + Aggregator::Ptr aggregator = aggregators.back(); + aggregator->SetFilter(filter); + } } } @@ -166,7 +154,43 @@ Query::Query(const std::vector& lines) } m_Filter = top_filter; - m_Stats.swap(stats); + m_Aggregators.swap(aggregators); +} + +Filter::Ptr Query::ParseFilter(const String& params) +{ + std::vector tokens; + boost::algorithm::split(tokens, params, boost::is_any_of(" ")); + + if (tokens.size() == 2) + tokens.push_back(""); + + if (tokens.size() < 3) + return Filter::Ptr(); + + String op = tokens[1]; + bool negate = false; + + if (op == "!=") { + op = "="; + negate = true; + } else if (op == "!~") { + op = "~"; + negate = true; + } else if (op == "!=~") { + op = "=~"; + negate = true; + } else if (op == "!~~") { + op = "~~"; + negate = true; + } + + Filter::Ptr filter = boost::make_shared(tokens[0], op, tokens[2]); + + if (negate) + filter = boost::make_shared(filter); + + return filter; } void Query::PrintResultSet(std::ostream& fp, const std::vector& columns, const Array::Ptr& rs) @@ -231,7 +255,7 @@ void Query::ExecuteGetHelper(const Stream::Ptr& stream) Array::Ptr rs = boost::make_shared(); - if (m_Stats.empty()) { + if (m_Aggregators.empty()) { BOOST_FOREACH(const Value& object, objects) { Array::Ptr row = boost::make_shared(); @@ -244,20 +268,20 @@ void Query::ExecuteGetHelper(const Stream::Ptr& stream) rs->Add(row); } } else { - std::vector stats(m_Stats.size(), 0); - - BOOST_FOREACH(const Value& object, objects) { - int index = 0; - BOOST_FOREACH(const Filter::Ptr filter, m_Stats) { - if (filter->Apply(table, object)) - stats[index]++; + std::vector stats(m_Aggregators.size(), 0); - index++; + int index = 0; + BOOST_FOREACH(const Aggregator::Ptr aggregator, m_Aggregators) { + BOOST_FOREACH(const Value& object, objects) { + aggregator->Apply(table, object); } + + stats[index] = aggregator->GetResult(); + index++; } Array::Ptr row = boost::make_shared(); - for (int i = 0; i < m_Stats.size(); i++) + for (int i = 0; i < m_Aggregators.size(); i++) row->Add(stats[i]); rs->Add(row); diff --git a/components/livestatus/query.h b/components/livestatus/query.h index 270aa6abe..16ce7efe7 100644 --- a/components/livestatus/query.h +++ b/components/livestatus/query.h @@ -21,6 +21,7 @@ #define QUERY_H #include "livestatus/filter.h" +#include "livestatus/aggregator.h" #include "base/object.h" #include "base/array.h" #include "base/stream.h" @@ -53,7 +54,7 @@ private: std::vector m_Columns; Filter::Ptr m_Filter; - std::deque m_Stats; + std::deque m_Aggregators; String m_OutputFormat; bool m_ColumnHeaders; @@ -76,6 +77,8 @@ private: void SendResponse(const Stream::Ptr& stream, int code, const String& data); void PrintFixed16(const Stream::Ptr& stream, int code, const String& data); + + static Filter::Ptr ParseFilter(const String& params); }; }