]> granicus.if.org Git - icinga2/blob - lib/base/perfdatavalue.cpp
Merge pull request #5262 from Icinga/fix/graylog-perfdata
[icinga2] / lib / base / perfdatavalue.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/)  *
4  *                                                                            *
5  * This program is free software; you can redistribute it and/or              *
6  * modify it under the terms of the GNU General Public License                *
7  * as published by the Free Software Foundation; either version 2             *
8  * of the License, or (at your option) any later version.                     *
9  *                                                                            *
10  * This program is distributed in the hope that it will be useful,            *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
13  * GNU General Public License for more details.                               *
14  *                                                                            *
15  * You should have received a copy of the GNU General Public License          *
16  * along with this program; if not, write to the Free Software Foundation     *
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.             *
18  ******************************************************************************/
19
20 #include "base/perfdatavalue.hpp"
21 #include "base/perfdatavalue.tcpp"
22 #include "base/convert.hpp"
23 #include "base/exception.hpp"
24 #include "base/logger.hpp"
25 #include "base/function.hpp"
26 #include <boost/algorithm/string/case_conv.hpp>
27 #include <boost/algorithm/string/split.hpp>
28 #include <boost/algorithm/string/classification.hpp>
29
30 using namespace icinga;
31
32 REGISTER_TYPE(PerfdataValue);
33 REGISTER_SCRIPTFUNCTION_NS(System, parse_performance_data, PerfdataValue::Parse, "perfdata");
34
35 PerfdataValue::PerfdataValue(void)
36 { }
37
38 PerfdataValue::PerfdataValue(String label, double value, bool counter,
39     const String& unit, const Value& warn, const Value& crit, const Value& min,
40     const Value& max)
41 {
42         SetLabel(label, true);
43         SetValue(value, true);
44         SetCounter(counter, true);
45         SetUnit(unit, true);
46         SetWarn(warn, true);
47         SetCrit(crit, true);
48         SetMin(min, true);
49         SetMax(max, true);
50 }
51
52 PerfdataValue::Ptr PerfdataValue::Parse(const String& perfdata)
53 {
54         size_t eqp = perfdata.FindLastOf('=');
55
56         if (eqp == String::NPos)
57                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid performance data value: " + perfdata));
58
59         String label = perfdata.SubStr(0, eqp);
60
61         if (label.GetLength() > 2 && label[0] == '\'' && label[label.GetLength() - 1] == '\'')
62                 label = label.SubStr(1, label.GetLength() - 2);
63
64         size_t spq = perfdata.FindFirstOf(' ', eqp);
65
66         if (spq == String::NPos)
67                 spq = perfdata.GetLength();
68
69         String valueStr = perfdata.SubStr(eqp + 1, spq - eqp - 1);
70
71         size_t pos = valueStr.FindFirstNotOf("+-0123456789.e");
72
73         double value = Convert::ToDouble(valueStr.SubStr(0, pos));
74
75         std::vector<String> tokens;
76         boost::algorithm::split(tokens, valueStr, boost::is_any_of(";"));
77
78         bool counter = false;
79         String unit;
80         Value warn, crit, min, max;
81
82         if (pos != String::NPos)
83                 unit = valueStr.SubStr(pos, tokens[0].GetLength() - pos);
84
85         boost::algorithm::to_lower(unit);
86
87         double base = 1.0;
88
89         if (unit == "us") {
90                 base /= 1000.0 * 1000.0;
91                 unit = "seconds";
92         } else if (unit == "ms") {
93                 base /= 1000.0;
94                 unit = "seconds";
95         } else if (unit == "s") {
96                 unit = "seconds";
97         } else if (unit == "tb") {
98                 base *= 1024.0 * 1024.0 * 1024.0 * 1024.0;
99                 unit = "bytes";
100         } else if (unit == "gb") {
101                 base *= 1024.0 * 1024.0 * 1024.0;
102                 unit = "bytes";
103         } else if (unit == "mb") {
104                 base *= 1024.0 * 1024.0;
105                 unit = "bytes";
106         } else if (unit == "kb") {
107                 base *= 1024.0;
108                 unit = "bytes";
109         } else if (unit == "b") {
110                 unit = "bytes";
111         } else if (unit == "%") {
112                 unit = "percent";
113         } else if (unit == "c") {
114                 counter = true;
115                 unit = "";
116         } else if (unit != "") {
117                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid performance data unit: " + unit));
118         }
119
120         warn = ParseWarnCritMinMaxToken(tokens, 1, "warning");
121         crit = ParseWarnCritMinMaxToken(tokens, 2, "critical");
122         min = ParseWarnCritMinMaxToken(tokens, 3, "minimum");
123         max = ParseWarnCritMinMaxToken(tokens, 4, "maximum");
124
125         value = value * base;
126
127         if (!warn.IsEmpty())
128                 warn = warn * base;
129
130         if (!crit.IsEmpty())
131                 crit = crit * base;
132
133         if (!min.IsEmpty())
134                 min = min * base;
135
136         if (!max.IsEmpty())
137                 max = max * base;
138
139         return new PerfdataValue(label, value, counter, unit, warn, crit, min, max);
140 }
141
142 String PerfdataValue::Format(void) const
143 {
144         std::ostringstream result;
145
146         if (GetLabel().FindFirstOf(" ") != String::NPos)
147                 result << "'" << GetLabel() << "'";
148         else
149                 result << GetLabel();
150
151         result << "=" << Convert::ToString(GetValue());
152
153         String unit;
154
155         if (GetCounter())
156                 unit = "c";
157         else if (GetUnit() == "seconds")
158                 unit = "s";
159         else if (GetUnit() == "percent")
160                 unit = "%";
161         else if (GetUnit() == "bytes")
162                 unit = "B";
163
164         result << unit;
165
166         if (!GetWarn().IsEmpty()) {
167                 result << ";" << Convert::ToString(GetWarn());
168
169                 if (!GetCrit().IsEmpty()) {
170                         result << ";" << Convert::ToString(GetCrit());
171
172                         if (!GetMin().IsEmpty()) {
173                                 result << ";" << Convert::ToString(GetMin());
174
175                                 if (!GetMax().IsEmpty()) {
176                                         result << ";" << Convert::ToString(GetMax());
177                                 }
178                         }
179                 }
180         }
181
182         return result.str();
183 }
184
185 Value PerfdataValue::ParseWarnCritMinMaxToken(const std::vector<String>& tokens, std::vector<String>::size_type index, const String& description)
186 {
187         if (tokens.size() > index && tokens[index] != "U" && tokens[index] != "" && tokens[index].FindFirstNotOf("+-0123456789.e") == String::NPos)
188                 return Convert::ToDouble(tokens[index]);
189         else {
190                 if (tokens.size() > index && tokens[index] != "")
191                         Log(LogDebug, "PerfdataValue")
192                             << "Ignoring unsupported perfdata " << description << " range, value: '" << tokens[index] << "'.";
193                 return Empty;
194         }
195 }