diff --git a/doc/05-service-monitoring.md b/doc/05-service-monitoring.md index 68180c32a..f37630913 100644 --- a/doc/05-service-monitoring.md +++ b/doc/05-service-monitoring.md @@ -651,7 +651,7 @@ Icinga sets `LC_NUMERIC=C` to enforce this locale on plugin execution. ``` The UoMs are written as-is into the [core backends](14-features.md#core-backends) -(Icinga DB, IDO, API). I.e. 12.445000ms remain 12.445000ms. +(IDO, API). I.e. 12.445000ms remain 12.445000ms. In contrast, the [metric backends](14-features.md#metrics) (Graphite, InfluxDB, etc.) get perfdata (including warn, crit, min, max) @@ -660,6 +660,8 @@ normalized by Icinga. E.g. 12.445000ms become 0.012445 seconds. Some plugins change the UoM for different sizing, e.g. returning the disk usage in MB and later GB for the same performance data label. This is to ensure that graphs always look the same. +[Icinga DB](14-features.md#core-backends-icingadb) gets both the as-is and the normalized perfdata. + What metric backends get... | ... from which perfdata UoMs (case-insensitive if possible) ----------------------------|--------------------------------------- bytes (B) | B, KB, MB, ..., YB, KiB, MiB, ..., YiB diff --git a/lib/icinga/pluginutility.cpp b/lib/icinga/pluginutility.cpp index 5c7f4b924..2197d1693 100644 --- a/lib/icinga/pluginutility.cpp +++ b/lib/icinga/pluginutility.cpp @@ -176,7 +176,7 @@ Array::Ptr PluginUtility::SplitPerfdata(const String& perfdata) return new Array(std::move(result)); } -String PluginUtility::FormatPerfdata(const Array::Ptr& perfdata) +String PluginUtility::FormatPerfdata(const Array::Ptr& perfdata, bool normalize) { if (!perfdata) return ""; @@ -192,10 +192,25 @@ String PluginUtility::FormatPerfdata(const Array::Ptr& perfdata) else first = false; - if (pdv.IsObjectType()) + if (pdv.IsObjectType()) { result << static_cast(pdv)->Format(); - else + } else if (normalize) { + PerfdataValue::Ptr normalized; + + try { + normalized = PerfdataValue::Parse(pdv); + } catch (const std::invalid_argument& ex) { + Log(LogDebug, "PerfdataValue") << ex.what(); + } + + if (normalized) { + result << normalized->Format(); + } else { + result << pdv; + } + } else { result << pdv; + } } return result.str(); diff --git a/lib/icinga/pluginutility.hpp b/lib/icinga/pluginutility.hpp index 0ea56e2c5..3f6a8444a 100644 --- a/lib/icinga/pluginutility.hpp +++ b/lib/icinga/pluginutility.hpp @@ -31,7 +31,7 @@ public: static std::pair ParseCheckOutput(const String& output); static Array::Ptr SplitPerfdata(const String& perfdata); - static String FormatPerfdata(const Array::Ptr& perfdata); + static String FormatPerfdata(const Array::Ptr& perfdata, bool normalize = false); private: PluginUtility(); diff --git a/lib/icingadb/icingadb-objects.cpp b/lib/icingadb/icingadb-objects.cpp index 8d519d0ca..9d1405ff8 100644 --- a/lib/icingadb/icingadb-objects.cpp +++ b/lib/icingadb/icingadb-objects.cpp @@ -2193,6 +2193,10 @@ Dictionary::Ptr IcingaDB::SerializeState(const Checkable::Ptr& checkable) if (!perfData.IsEmpty()) attrs->Set("performance_data", perfData); + String normedPerfData = PluginUtility::FormatPerfdata(cr->GetPerformanceData(), true); + if (!normedPerfData.IsEmpty()) + attrs->Set("normalized_performance_data", normedPerfData); + if (!cr->GetCommand().IsEmpty()) attrs->Set("commandline", FormatCommandLine(cr->GetCommand())); attrs->Set("execution_time", TimestampToMilliseconds(fmax(0.0, cr->CalculateExecutionTime()))); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6a5a4bb27..3d19eb83d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -143,6 +143,7 @@ add_boost_test(base icinga_perfdata/simple icinga_perfdata/quotes icinga_perfdata/multiple + icinga_perfdata/normalize icinga_perfdata/uom icinga_perfdata/warncritminmax icinga_perfdata/ignore_invalid_warn_crit_min_max diff --git a/test/icinga-perfdata.cpp b/test/icinga-perfdata.cpp index 288161486..f763ac043 100644 --- a/test/icinga-perfdata.cpp +++ b/test/icinga-perfdata.cpp @@ -43,6 +43,15 @@ BOOST_AUTO_TEST_CASE(multiple) BOOST_CHECK(str == "testA=123456 testB=123456"); } +BOOST_AUTO_TEST_CASE(normalize) +{ + Array::Ptr pd = PluginUtility::SplitPerfdata("testA=2m;3;4;1;5 testB=2foobar"); + BOOST_CHECK(pd->GetLength() == 2); + + String str = PluginUtility::FormatPerfdata(pd, true); + BOOST_CHECK(str == "testA=120s;180;240;60;300 testB=2"); +} + BOOST_AUTO_TEST_CASE(uom) { PerfdataValue::Ptr pv = PerfdataValue::Parse("test=123456B");