]> granicus.if.org Git - icinga2/blob - plugins/thresholds.cpp
Merge pull request #6857 from Icinga/bugfix/check_nscp_api-query-sorted-6536
[icinga2] / plugins / thresholds.cpp
1 /******************************************************************************
2  * Icinga 2                                                                   *
3  * Copyright (C) 2012-2018 Icinga Development Team (https://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 "plugins/thresholds.hpp"
21 #include <boost/algorithm/string.hpp>
22 #include <boost/lexical_cast.hpp>
23 #include <iostream>
24
25 using namespace boost::algorithm;
26
27 threshold::threshold()
28         : set(false)
29 {}
30
31 threshold::threshold(const double v, const double c, bool l , bool p ) {
32         lower = v;
33         upper = c;
34         legal = l;
35         perc = p;
36 }
37
38 threshold::threshold(const std::wstring& stri)
39 {
40         if (stri.empty())
41                 throw std::invalid_argument("Threshold must not be empty");
42
43         std::wstring str = stri;
44
45         //kill whitespace
46         boost::algorithm::trim(str);
47
48         bool low = (str.at(0) == L'!');
49         if (low)
50                 str = std::wstring(str.begin() + 1, str.end());
51
52         bool pc = false;
53
54         if (str.at(0) == L'[' && str.at(str.length() - 1) == L']') {//is range
55                 str = std::wstring(str.begin() + 1, str.end() - 1);
56                 std::vector<std::wstring> svec;
57                 boost::split(svec, str, boost::is_any_of(L"-"));
58                 if (svec.size() != 2)
59                         throw std::invalid_argument("Threshold range requires two arguments");
60                 std::wstring str1 = svec.at(0), str2 = svec.at(1);
61
62                 if (str1.at(str1.length() - 1) == L'%' && str2.at(str2.length() - 1) == L'%') {
63                         pc = true;
64                         str1 = std::wstring(str1.begin(), str1.end() - 1);
65                         str2 = std::wstring(str2.begin(), str2.end() - 1);
66                 }
67
68                 try {
69                         boost::algorithm::trim(str1);
70                         lower = boost::lexical_cast<DOUBLE>(str1);
71                         boost::algorithm::trim(str2);
72                         upper = boost::lexical_cast<DOUBLE>(str2);
73                         legal = !low; perc = pc; set = true;
74                 } catch (const boost::bad_lexical_cast&) {
75                         throw std::invalid_argument("Unknown Threshold type");
76                 }
77         } else { //not range
78                 if (str.at(str.length() - 1) == L'%') {
79                         pc = true;
80                         str = std::wstring(str.begin(), str.end() - 1);
81                 }
82                 try {
83                         boost::algorithm::trim(str);
84                         lower = upper = boost::lexical_cast<DOUBLE>(str);
85                         legal = !low; perc = pc; set = true;
86                 } catch (const boost::bad_lexical_cast&) {
87                         throw std::invalid_argument("Unknown Threshold type");
88                 }
89         }
90 }
91
92 //return TRUE if the threshold is broken
93 bool threshold::rend(const double val, const double max)
94 {
95         double upperAbs = upper;
96         double lowerAbs = lower;
97
98         if (perc) {
99                 upperAbs = upper / 100.0 * max;
100                 lowerAbs = lower / 100.0 * max;
101         }
102
103         if (!set)
104                 return set;
105         if (lowerAbs == upperAbs)
106                 return val > upperAbs == legal;
107         else
108                 return (val < lowerAbs || upperAbs < val) != legal;
109 }
110
111 //returns a printable string of the threshold
112 std::wstring threshold::pString(const double max)
113 {
114         if (!set)
115                 return L"";
116         //transform percentages to abolute values
117         double lowerAbs = lower;
118         double upperAbs = upper;
119         if (perc) {
120                 lowerAbs = lower / 100.0 * max;
121                 upperAbs = upper / 100.0 * max;
122         }
123
124         std::wstring s, lowerStr = removeZero(lowerAbs),
125                                         upperStr = removeZero(upperAbs);
126
127         if (lower != upper) {
128                 s.append(L"[").append(lowerStr).append(L"-")
129                 .append(upperStr).append(L"]");
130         } else
131                 s.append(lowerStr);
132
133         return s;
134 }
135
136 threshold threshold::toSeconds(const Tunit& fromUnit) {
137         if (!set)
138                 return *this;
139
140         double lowerAbs = lower;
141         double upperAbs = upper;
142
143         switch (fromUnit) {
144         case TunitMS:
145                 lowerAbs = lowerAbs / 1000;
146                 upperAbs = upperAbs / 1000;
147                 break;
148         case TunitS:
149                 lowerAbs = lowerAbs ;
150                 upperAbs = upperAbs ;
151                 break;
152         case TunitM:
153                 lowerAbs = lowerAbs * 60;
154                 upperAbs = upperAbs * 60;
155                 break;
156         case TunitH:
157                 lowerAbs = lowerAbs * 60 * 60;
158                 upperAbs = upperAbs * 60 * 60;
159                 break;
160         }
161
162         return threshold(lowerAbs, upperAbs, legal, perc);
163 }
164
165 std::wstring removeZero(double val)
166 {
167         std::wstring ret = boost::lexical_cast<std::wstring>(val);
168         std::wstring::size_type pos = ret.length();
169         if (ret.find_first_of(L".") == std::string::npos)
170                 return ret;
171         for (std::wstring::reverse_iterator rit = ret.rbegin(); rit != ret.rend(); ++rit) {
172                 if (*rit == L'.') {
173                         return ret.substr(0, pos - 1);
174                 }
175                 if (*rit != L'0') {
176                         return ret.substr(0, pos);
177                 }
178                 pos--;
179         }
180         return L"0";
181 }
182
183 std::vector<std::wstring> splitMultiOptions(const std::wstring& str)
184 {
185         std::vector<std::wstring> sVec;
186         boost::split(sVec, str, boost::is_any_of(L","));
187         return sVec;
188 }
189
190 Bunit parseBUnit(const std::wstring& str)
191 {
192         std::wstring wstr = to_upper_copy(str);
193
194         if (wstr == L"B")
195                 return BunitB;
196         if (wstr == L"KB")
197                 return BunitkB;
198         if (wstr == L"MB")
199                 return BunitMB;
200         if (wstr == L"GB")
201                 return BunitGB;
202         if (wstr == L"TB")
203                 return BunitTB;
204
205         throw std::invalid_argument("Unknown unit type");
206 }
207
208 std::wstring BunitStr(const Bunit& unit)
209 {
210         switch (unit) {
211         case BunitB:
212                 return L"B";
213         case BunitkB:
214                 return L"kB";
215         case BunitMB:
216                 return L"MB";
217         case BunitGB:
218                 return L"GB";
219         case BunitTB:
220                 return L"TB";
221         }
222         return NULL;
223 }
224
225 Tunit parseTUnit(const std::wstring& str) {
226         std::wstring wstr = to_lower_copy(str);
227
228         if (wstr == L"ms")
229                 return TunitMS;
230         if (wstr == L"s")
231                 return TunitS;
232         if (wstr == L"m")
233                 return TunitM;
234         if (wstr == L"h")
235                 return TunitH;
236
237         throw std::invalid_argument("Unknown unit type");
238 }
239
240 std::wstring TunitStr(const Tunit& unit)
241 {
242         switch (unit) {
243         case TunitMS:
244                 return L"ms";
245         case TunitS:
246                 return L"s";
247         case TunitM:
248                 return L"m";
249         case TunitH:
250                 return L"h";
251         }
252         return NULL;
253 }
254
255 void printErrorInfo(unsigned long err)
256 {
257         if (!err)
258                 err = GetLastError();
259         LPWSTR mBuf = NULL;
260         if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
261                 NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&mBuf, 0, NULL))
262                 std::wcout << "Failed to format error message, last error was: " << err << '\n';
263         else {
264                 boost::trim_right(std::wstring(mBuf));
265                 std::wcout << mBuf << std::endl;
266         }
267 }
268
269 std::wstring formatErrorInfo(unsigned long err) {
270         std::wostringstream out;
271         if (!err)
272                 err = GetLastError();
273         LPWSTR mBuf = NULL;
274         if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
275                 NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&mBuf, 0, NULL))
276                 out << "Failed to format error message, last error was: " << err;
277         else {
278                 std::wstring tempOut = std::wstring(mBuf);
279                 boost::trim_right(tempOut);
280                 out << tempOut;
281         }
282
283         return out.str();
284 }
285
286 std::wstring stateToString(const state& state) {
287         switch (state) {
288                 case OK: return L"OK";
289                 case WARNING: return L"WARNING";
290                 case CRITICAL: return L"CRITICAL";
291                 default: return L"UNKNOWN";
292         }
293 }