From 5aba175e18e0f836238e2932eeaf29db827fe607 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 7 Nov 2013 14:38:37 +0100 Subject: [PATCH] Use PluginUtility::{Parse,Format}Perfdata for check results. Refs #2710 --- components/perfdata/graphitewriter.cpp | 167 ++++++------------------- components/perfdata/graphitewriter.h | 5 +- lib/icinga/compatutility.cpp | 11 +- lib/icinga/host.cpp | 3 +- lib/icinga/pluginutility.cpp | 2 +- lib/icinga/service.cpp | 3 +- lib/methods/nullchecktask.cpp | 6 +- lib/methods/randomchecktask.cpp | 6 +- 8 files changed, 55 insertions(+), 148 deletions(-) diff --git a/components/perfdata/graphitewriter.cpp b/components/perfdata/graphitewriter.cpp index f5284888d..4a101223f 100644 --- a/components/perfdata/graphitewriter.cpp +++ b/components/perfdata/graphitewriter.cpp @@ -22,6 +22,7 @@ #include "icinga/macroprocessor.h" #include "icinga/icingaapplication.h" #include "icinga/compatutility.h" +#include "icinga/perfdatavalue.h" #include "base/tcpsocket.h" #include "base/dynamictype.h" #include "base/objectlock.h" @@ -82,122 +83,36 @@ void GraphiteWriter::CheckResultHandler(const Service::Ptr& service, const Dicti if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !service->GetEnablePerfdata()) return; - Host::Ptr host = service->GetHost(); + /* basic metrics */ + SendMetric(service, "current_attempt", service->GetCheckAttempt()); + SendMetric(service, "max_check_attempts", service->GetMaxCheckAttempts()); + SendMetric(service, "state_type", service->GetStateType()); + SendMetric(service, "state", service->GetState()); + SendMetric(service, "latency", Service::CalculateLatency(cr)); + SendMetric(service, "execution_time", Service::CalculateExecutionTime(cr)); + + Value pdv = cr->Get("performance_data"); - if (!host) + if (!pdv.IsObjectType()) return; - /* service metrics */ - std::vector metrics; - String metricName; - Value metricValue; + Dictionary::Ptr perfdata = pdv; - /* basic metrics */ - AddServiceMetric(metrics, service, "current_attempt", service->GetCheckAttempt()); - AddServiceMetric(metrics, service, "max_check_attempts", service->GetMaxCheckAttempts()); - AddServiceMetric(metrics, service, "state_type", service->GetStateType()); - AddServiceMetric(metrics, service, "state", service->GetState()); - AddServiceMetric(metrics, service, "latency", Service::CalculateLatency(cr)); - AddServiceMetric(metrics, service, "execution_time", Service::CalculateExecutionTime(cr)); - - /* performance data metrics */ - String perfdata = CompatUtility::GetCheckResultPerfdata(cr); - - if (!perfdata.IsEmpty()) { - perfdata.Trim(); - - Log(LogDebug, "perfdata", "GraphiteWriter: Processing perfdata: '" + perfdata + "'."); - - /* - * 'foo bar'=0;;; baz=0.0;;; - * 'label'=value[UOM];[warn];[crit];[min];[max] - */ - std::vector tokens; - boost::algorithm::split(tokens, perfdata, boost::is_any_of(" ")); - - /* TODO deal with white spaces in single quoted labels: 'foo bar'=0;;; 'baz'=1.0;;; - * 1. find first ', find second ' -> if no '=' in between, this is a label - * 2. two single quotes define an escaped single quite - * 3. warn/crit/min/max may be null and semicolon delimiter omitted - * https://www.nagios-plugins.org/doc/guidelines.html#AEN200 - */ - BOOST_FOREACH(const String& token, tokens) { - String metricKeyVal = token; - metricKeyVal.Trim(); - - std::vector key_val; - boost::algorithm::split(key_val, metricKeyVal, boost::is_any_of("=")); - - if (key_val.size() == 0) { - Log(LogWarning, "perfdata", "GraphiteWriter: Invalid performance data. No assignment operator found in :'" + metricKeyVal + "'."); - return; - } - - String metricName = key_val[0]; - metricName.Trim(); - - if (key_val.size() == 1) { - Log(LogWarning, "perfdata", "GraphiteWriter: Invalid performance data: '" + metricKeyVal + "' with key: '" + metricName + "'."); - return; - } - - String metricValues = key_val[1]; - metricValues.Trim(); - - std::vector perfdata_values; - boost::algorithm::split(perfdata_values, metricValues, boost::is_any_of(";")); - - if (perfdata_values.size() == 0) { - Log(LogWarning, "perfdata", "GraphiteWriter: Invalid performance data: '" + metricKeyVal + - "' with key: '" + metricName + "' and values: '" + metricValues + "'."); - return; - } - - String metricValue = perfdata_values[0]; - - metricValue.Trim(); - Log(LogDebug, "perfdata", "GraphiteWriter: Trimmed metric value: '" + metricValue + "'."); - - /* extract raw value (digit number digit as double) and uom - * http://en.highscore.de/cpp/boost/stringhandling.html - */ - String metricValueRaw = boost::algorithm::trim_right_copy_if(metricValue, (!boost::algorithm::is_digit() && !boost::algorithm::is_any_of(".,"))); - String metricValueUom = boost::algorithm::trim_left_copy_if(metricValue, (boost::algorithm::is_digit() || boost::algorithm::is_any_of(".,"))); - - Log(LogDebug, "perfdata", "GraphiteWriter: Raw metric value: '" + metricValueRaw + "' with UOM: '" + metricValueUom + "'."); - - /* TODO: Normalize raw value based on UOM - * a. empty - assume a number - * b. 's' - seconds (us, ms) - * c. '%' - percentage - * d. 'B' - bytes (KB, MB, GB, TB) - * e. 'c' - continous counter (snmp) - */ - - /* //TODO: Figure out how graphite handles warn/crit/min/max - String metricValueWarn, metricValueCrit, metricValueMin, metricValueMax; - - if (perfdata_values.size() > 1) - metricValueWarn = perfdata_values[1]; - if (perfdata_values.size() > 2) - metricValueCrit = perfdata_values[2]; - if (perfdata_values.size() > 3) - metricValueMin = perfdata_values[3]; - if (perfdata_values.size() > 4) - metricValueMax = perfdata_values[4]; - */ - - /* sanitize invalid metric characters */ - SanitizeMetric(metricName); - - AddServiceMetric(metrics, service, metricName, metricValueRaw); - } - } + String key; + Value value; + BOOST_FOREACH(boost::tie(key, value), perfdata) { + double valueNum; - SendMetrics(metrics); + if (!value.IsObjectType()) + valueNum = value; + else + valueNum = static_cast(value)->GetValue(); + + SendMetric(service, key, valueNum); + } } -void GraphiteWriter::AddServiceMetric(std::vector& metrics, const Service::Ptr& service, const String& name, const Value& value) +void GraphiteWriter::SendMetric(const Service::Ptr& service, const String& name, double value) { /* TODO: sanitize host and service names */ String hostName = service->GetHost()->GetName(); @@ -211,33 +126,22 @@ void GraphiteWriter::AddServiceMetric(std::vector& metrics, const Servic String metric = graphitePrefix + "." + metricPrefix + "." + name + " " + Convert::ToString(value) + " " + Convert::ToString(static_cast(Utility::GetTime())) + "\n"; Log(LogDebug, "perfdata", "GraphiteWriter: Add to metric list:'" + metric + "'."); - metrics.push_back(metric); -} -void GraphiteWriter::SendMetrics(const std::vector& metrics) -{ - BOOST_FOREACH(const String& metric, metrics) { - if (metric.IsEmpty()) - continue; + ObjectLock olock(this); - Log(LogDebug, "perfdata", "GraphiteWriter: Sending metric '" + metric + "'."); - - ObjectLock olock(this); - - if (!m_Stream) - return; + if (!m_Stream) + return; - try { - m_Stream->Write(metric.CStr(), metric.GetLength()); - } catch (const std::exception& ex) { - std::ostringstream msgbuf; - msgbuf << "Exception thrown while writing to the Graphite socket: " << std::endl - << boost::diagnostic_information(ex); + try { + m_Stream->Write(metric.CStr(), metric.GetLength()); + } catch (const std::exception& ex) { + std::ostringstream msgbuf; + msgbuf << "Exception thrown while writing to the Graphite socket: " << std::endl + << boost::diagnostic_information(ex); - Log(LogCritical, "base", msgbuf.str()); + Log(LogCritical, "base", msgbuf.str()); - m_Stream.reset(); - } + m_Stream.reset(); } } @@ -249,4 +153,3 @@ void GraphiteWriter::SanitizeMetric(String& str) boost::replace_all(str, "\\", "_"); boost::replace_all(str, "/", "_"); } - diff --git a/components/perfdata/graphitewriter.h b/components/perfdata/graphitewriter.h index b99736338..133790fd1 100644 --- a/components/perfdata/graphitewriter.h +++ b/components/perfdata/graphitewriter.h @@ -50,10 +50,9 @@ private: Timer::Ptr m_ReconnectTimer; void CheckResultHandler(const Service::Ptr& service, const Dictionary::Ptr& cr); - static void AddServiceMetric(std::vector& metrics, const Service::Ptr& service, const String& name, const Value& value); - void SendMetrics(const std::vector& metrics); + void SendMetric(const Service::Ptr& service, const String& name, double value); static void SanitizeMetric(String& str); - + void ReconnectTimerHandler(void); }; diff --git a/lib/icinga/compatutility.cpp b/lib/icinga/compatutility.cpp index 511701756..de26f8c91 100644 --- a/lib/icinga/compatutility.cpp +++ b/lib/icinga/compatutility.cpp @@ -17,13 +17,14 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -#include "base/convert.h" #include "icinga/compatutility.h" #include "icinga/checkcommand.h" #include "icinga/eventcommand.h" +#include "icinga/pluginutility.h" #include "base/dynamictype.h" #include "base/objectlock.h" #include "base/debug.h" +#include "base/convert.h" #include #include #include @@ -556,12 +557,10 @@ Dictionary::Ptr CompatUtility::GetCheckResultOutput(const Dictionary::Ptr& cr) String CompatUtility::GetCheckResultPerfdata(const Dictionary::Ptr& cr) { if (!cr) - return Empty; - - String perfdata = EscapeString(cr->Get("performance_data_raw")); - perfdata.Trim(); + return String(); - return perfdata; + Dictionary::Ptr perfdata = cr->Get("performance_data"); + return PluginUtility::FormatPerfdata(perfdata); } String CompatUtility::EscapeString(const String& str) diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 13e6d82cf..7dbc04cfe 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -21,6 +21,7 @@ #include "icinga/service.h" #include "icinga/hostgroup.h" #include "icinga/icingaapplication.h" +#include "icinga/pluginutility.h" #include "base/dynamictype.h" #include "base/objectlock.h" #include "base/logger_fwd.h" @@ -619,7 +620,7 @@ bool Host::ResolveMacro(const String& macro, const Dictionary::Ptr&, String *res *result = hccr->Get("output"); return true; } else if (macro == "HOSTPERFDATA") { - *result = hccr->Get("performance_data_raw"); + *result = PluginUtility::FormatPerfdata(hccr->Get("performance_data")); return true; } else if (macro == "LASTHOSTCHECK") { *result = Convert::ToString((long)hccr->Get("schedule_start")); diff --git a/lib/icinga/pluginutility.cpp b/lib/icinga/pluginutility.cpp index 5589870e5..4e9af85e9 100644 --- a/lib/icinga/pluginutility.cpp +++ b/lib/icinga/pluginutility.cpp @@ -76,7 +76,7 @@ Dictionary::Ptr PluginUtility::ParseCheckOutput(const String& output) } result->Set("output", text); - result->Set("performance_data_raw", perfdata); + result->Set("performance_data", ParsePerfdata(perfdata)); return result; } diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index 38d9848f9..484c9abda 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -22,6 +22,7 @@ #include "icinga/checkcommand.h" #include "icinga/icingaapplication.h" #include "icinga/macroprocessor.h" +#include "icinga/pluginutility.h" #include "config/configitembuilder.h" #include "base/dynamictype.h" #include "base/objectlock.h" @@ -393,7 +394,7 @@ bool Service::ResolveMacro(const String& macro, const Dictionary::Ptr& cr, Strin *result = cr->Get("output"); return true; } else if (macro == "SERVICEPERFDATA") { - *result = cr->Get("performance_data_raw"); + *result = PluginUtility::FormatPerfdata(cr->Get("performance_data")); return true; } else if (macro == "LASTSERVICECHECK") { *result = Convert::ToString((long)cr->Get("execution_end")); diff --git a/lib/methods/nullchecktask.cpp b/lib/methods/nullchecktask.cpp index 42368c572..01e80fdca 100644 --- a/lib/methods/nullchecktask.cpp +++ b/lib/methods/nullchecktask.cpp @@ -39,11 +39,13 @@ Dictionary::Ptr NullCheckTask::ScriptFunc(const Service::Ptr&) String output = "Hello from "; output += name; - String perfdata = "time=" + Convert::ToString(static_cast(Utility::GetTime())); + + Dictionary::Ptr perfdata = make_shared(); + perfdata->Set("time", Utility::GetTime()); Dictionary::Ptr cr = make_shared(); cr->Set("output", output); - cr->Set("performance_data_raw", perfdata); + cr->Set("performance_data", perfdata); cr->Set("state", StateOK); return cr; diff --git a/lib/methods/randomchecktask.cpp b/lib/methods/randomchecktask.cpp index 9c6f9b8fe..2ca8c4b70 100644 --- a/lib/methods/randomchecktask.cpp +++ b/lib/methods/randomchecktask.cpp @@ -39,11 +39,13 @@ Dictionary::Ptr RandomCheckTask::ScriptFunc(const Service::Ptr&) String output = "Hello from "; output += name; - String perfdata = "time=" + Convert::ToString(static_cast(Utility::GetTime())); + + Dictionary::Ptr perfdata = make_shared(); + perfdata->Set("time", Utility::GetTime()); Dictionary::Ptr cr = make_shared(); cr->Set("output", output); - cr->Set("performance_data_raw", perfdata); + cr->Set("performance_data", perfdata); cr->Set("state", static_cast(Utility::Random() % 4)); return cr; -- 2.40.0