fixed bug in script threshold update from template
[public/netxms.git] / src / server / core / dcithreshold.cpp
CommitLineData
4016c0df 1/*
5039dede 2** NetXMS - Network Management System
6b29839d 3** Copyright (C) 2003-2014 Victor Kirhenshtein
5039dede
AK
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (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
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: dcithreshold.cpp
20**
21**/
22
23#include "nxcore.h"
24
85ae39bc
VK
25/**
26 * Create new threshold for given DCI
27 */
5039dede
AK
28Threshold::Threshold(DCItem *pRelatedItem)
29{
d9ae1904 30 m_id = 0;
fb05c05b 31 m_itemId = pRelatedItem->getId();
4804be4e 32 m_targetId = pRelatedItem->getOwnerId();
d9ae1904
VK
33 m_eventCode = EVENT_THRESHOLD_REACHED;
34 m_rearmEventCode = EVENT_THRESHOLD_REARMED;
35 m_function = F_LAST;
36 m_operation = OP_EQ;
fb05c05b 37 m_dataType = pRelatedItem->getDataType();
1d34c533
VK
38 m_sampleCount = 1;
39 m_scriptSource = NULL;
40 m_script = NULL;
d9ae1904 41 m_isReached = FALSE;
711e5e9a 42 m_currentSeverity = SEVERITY_NORMAL;
d9ae1904
VK
43 m_repeatInterval = -1;
44 m_lastEventTimestamp = 0;
45 m_numMatches = 0;
5039dede
AK
46}
47
85ae39bc
VK
48/**
49 * Constructor for NXMP parser
50 */
5039dede
AK
51Threshold::Threshold()
52{
d9ae1904
VK
53 m_id = 0;
54 m_itemId = 0;
1d34c533 55 m_targetId = 0;
d9ae1904
VK
56 m_eventCode = EVENT_THRESHOLD_REACHED;
57 m_rearmEventCode = EVENT_THRESHOLD_REARMED;
58 m_function = F_LAST;
59 m_operation = OP_EQ;
60 m_dataType = 0;
1d34c533
VK
61 m_sampleCount = 1;
62 m_scriptSource = NULL;
63 m_script = NULL;
d9ae1904 64 m_isReached = FALSE;
711e5e9a 65 m_currentSeverity = SEVERITY_NORMAL;
d9ae1904
VK
66 m_repeatInterval = -1;
67 m_lastEventTimestamp = 0;
68 m_numMatches = 0;
5039dede
AK
69}
70
85ae39bc
VK
71/**
72 * Create from another threshold object
73 */
d9ae1904 74Threshold::Threshold(Threshold *src)
5039dede 75{
d9ae1904
VK
76 m_id = src->m_id;
77 m_itemId = src->m_itemId;
1d34c533 78 m_targetId = src->m_targetId;
d9ae1904
VK
79 m_eventCode = src->m_eventCode;
80 m_rearmEventCode = src->m_rearmEventCode;
81 m_value = src->m_value;
82 m_function = src->m_function;
83 m_operation = src->m_operation;
84 m_dataType = src->m_dataType;
1d34c533
VK
85 m_sampleCount = src->m_sampleCount;
86 m_scriptSource = NULL;
87 m_script = NULL;
88 setScript((src->m_scriptSource != NULL) ? _tcsdup(src->m_scriptSource) : NULL);
d9ae1904 89 m_isReached = FALSE;
711e5e9a 90 m_currentSeverity = SEVERITY_NORMAL;
d9ae1904
VK
91 m_repeatInterval = src->m_repeatInterval;
92 m_lastEventTimestamp = 0;
93 m_numMatches = 0;
5039dede
AK
94}
95
1d34c533
VK
96/**
97 * Constructor for creating object from database
98 * This constructor assumes that SELECT query look as following:
99 * SELECT threshold_id,fire_value,rearm_value,check_function,check_operation,
100 * sample_count,script,event_code,current_state,rearm_event_code,
b2042b58 101 * repeat_interval,current_severity,last_event_timestamp,match_count FROM thresholds
1d34c533 102 */
5039dede
AK
103Threshold::Threshold(DB_RESULT hResult, int iRow, DCItem *pRelatedItem)
104{
105 TCHAR szBuffer[MAX_DB_STRING];
106
d9ae1904 107 m_id = DBGetFieldULong(hResult, iRow, 0);
fb05c05b 108 m_itemId = pRelatedItem->getId();
4804be4e 109 m_targetId = pRelatedItem->getOwnerId();
d9ae1904
VK
110 m_eventCode = DBGetFieldULong(hResult, iRow, 7);
111 m_rearmEventCode = DBGetFieldULong(hResult, iRow, 9);
5039dede 112 DBGetField(hResult, iRow, 1, szBuffer, MAX_DB_STRING);
5039dede 113 m_value = szBuffer;
d9ae1904
VK
114 m_function = (BYTE)DBGetFieldLong(hResult, iRow, 3);
115 m_operation = (BYTE)DBGetFieldLong(hResult, iRow, 4);
fb05c05b 116 m_dataType = pRelatedItem->getDataType();
1d34c533
VK
117 m_sampleCount = DBGetFieldLong(hResult, iRow, 5);
118 if ((m_function == F_LAST) && (m_sampleCount < 1))
119 m_sampleCount = 1;
120 m_scriptSource = NULL;
121 m_script = NULL;
122 setScript(DBGetField(hResult, iRow, 6, NULL, 0));
d9ae1904
VK
123 m_isReached = DBGetFieldLong(hResult, iRow, 8);
124 m_repeatInterval = DBGetFieldLong(hResult, iRow, 10);
711e5e9a
VK
125 m_currentSeverity = (BYTE)DBGetFieldLong(hResult, iRow, 11);
126 m_lastEventTimestamp = (time_t)DBGetFieldULong(hResult, iRow, 12);
b2042b58 127 m_numMatches = DBGetFieldLong(hResult, iRow, 13);
5039dede
AK
128}
129
9387bc59
VK
130/**
131 * Create threshold from import file
132 */
a65c1819
VK
133Threshold::Threshold(ConfigEntry *config, DCItem *parentItem)
134{
135 createId();
136 m_itemId = parentItem->getId();
4804be4e 137 m_targetId = parentItem->getOwnerId();
a65c1819
VK
138 m_eventCode = EventCodeFromName(config->getSubEntryValue(_T("activationEvent"), 0, _T("SYS_THRESHOLD_REACHED")));
139 m_rearmEventCode = EventCodeFromName(config->getSubEntryValue(_T("deactivationEvent"), 0, _T("SYS_THRESHOLD_REARMED")));
31b0f68b
VK
140 m_function = (BYTE)config->getSubEntryValueAsInt(_T("function"), 0, F_LAST);
141 m_operation = (BYTE)config->getSubEntryValueAsInt(_T("condition"), 0, OP_EQ);
a65c1819
VK
142 m_dataType = parentItem->getDataType();
143 m_value = config->getSubEntryValue(_T("value"), 0, _T(""));
31b0f68b 144 m_sampleCount = (config->getSubEntryValue(_T("sampleCount")) != NULL) ? config->getSubEntryValueAsInt(_T("sampleCount"), 0, 1) : config->getSubEntryValueAsInt(_T("param1"), 0, 1);
1d34c533
VK
145 m_scriptSource = NULL;
146 m_script = NULL;
147 const TCHAR *script = config->getSubEntryValue(_T("script"));
53a9a341 148 setScript(_tcsdup_ex(script));
a65c1819 149 m_isReached = FALSE;
711e5e9a 150 m_currentSeverity = SEVERITY_NORMAL;
31b0f68b 151 m_repeatInterval = config->getSubEntryValueAsInt(_T("repeatInterval"), 0, -1);
a65c1819
VK
152 m_lastEventTimestamp = 0;
153 m_numMatches = 0;
154}
155
1d34c533
VK
156/**
157 * Destructor
158 */
5039dede
AK
159Threshold::~Threshold()
160{
1d34c533
VK
161 safe_free(m_scriptSource);
162 delete m_script;
5039dede
AK
163}
164
1d34c533
VK
165/**
166 * Create new unique id for object
167 */
711e5e9a 168void Threshold::createId()
5039dede 169{
4016c0df 170 m_id = CreateUniqueId(IDG_THRESHOLD);
5039dede
AK
171}
172
9098ad59
VK
173/**
174 * Save threshold to database
175 */
967893bb 176BOOL Threshold::saveToDB(DB_HANDLE hdb, UINT32 dwIndex)
5039dede 177{
5039dede 178 // Prepare and execute query
711e5e9a 179 DB_STATEMENT hStmt;
eaf7440b 180 if (!IsDatabaseRecordExist(hdb, _T("thresholds"), _T("threshold_id"), m_id))
711e5e9a 181 {
4016c0df 182 hStmt = DBPrepare(hdb,
711e5e9a 183 _T("INSERT INTO thresholds (item_id,fire_value,rearm_value,")
1d34c533 184 _T("check_function,check_operation,sample_count,script,event_code,")
711e5e9a 185 _T("sequence_number,current_state,rearm_event_code,repeat_interval,")
b2042b58
VK
186 _T("current_severity,last_event_timestamp,match_count,threshold_id) ")
187 _T("VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"));
711e5e9a
VK
188 }
189 else
190 {
4016c0df 191 hStmt = DBPrepare(hdb,
711e5e9a 192 _T("UPDATE thresholds SET item_id=?,fire_value=?,rearm_value=?,check_function=?,")
1d34c533 193 _T("check_operation=?,sample_count=?,script=?,event_code=?,")
711e5e9a 194 _T("sequence_number=?,current_state=?,rearm_event_code=?,")
b2042b58
VK
195 _T("repeat_interval=?,current_severity=?,last_event_timestamp=?,")
196 _T("match_count=? WHERE threshold_id=?"));
711e5e9a
VK
197 }
198 if (hStmt == NULL)
199 return FALSE;
200
201 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_itemId);
202 DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, m_value.getString(), DB_BIND_STATIC);
203 DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, NULL, DB_BIND_STATIC);
967893bb
VK
204 DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (INT32)m_function);
205 DBBind(hStmt, 5, DB_SQLTYPE_INTEGER, (INT32)m_operation);
1d34c533
VK
206 DBBind(hStmt, 6, DB_SQLTYPE_INTEGER, (INT32)m_sampleCount);
207 DBBind(hStmt, 7, DB_SQLTYPE_VARCHAR, m_scriptSource, DB_BIND_STATIC);
711e5e9a
VK
208 DBBind(hStmt, 8, DB_SQLTYPE_INTEGER, m_eventCode);
209 DBBind(hStmt, 9, DB_SQLTYPE_INTEGER, dwIndex);
967893bb 210 DBBind(hStmt, 10, DB_SQLTYPE_INTEGER, (INT32)(m_isReached ? 1 : 0));
711e5e9a 211 DBBind(hStmt, 11, DB_SQLTYPE_INTEGER, m_rearmEventCode);
967893bb
VK
212 DBBind(hStmt, 12, DB_SQLTYPE_INTEGER, (INT32)m_repeatInterval);
213 DBBind(hStmt, 13, DB_SQLTYPE_INTEGER, (INT32)m_currentSeverity);
214 DBBind(hStmt, 14, DB_SQLTYPE_INTEGER, (INT32)m_lastEventTimestamp);
b2042b58
VK
215 DBBind(hStmt, 15, DB_SQLTYPE_INTEGER, (INT32)m_numMatches);
216 DBBind(hStmt, 16, DB_SQLTYPE_INTEGER, (INT32)m_id);
711e5e9a
VK
217
218 BOOL success = DBExecute(hStmt);
219 DBFreeStatement(hStmt);
220 return success;
5039dede
AK
221}
222
6b8e9f96
VK
223/**
224 * Check threshold
225 * Method will return the following codes:
226 * THRESHOLD_REACHED - when item's value match the threshold condition while previous check doesn't
227 * THRESHOLD_REARMED - when item's value doesn't match the threshold condition while previous check do
228 * NO_ACTION - when there are no changes in item's value match to threshold's condition
229 */
1d34c533 230ThresholdCheckResult Threshold::check(ItemValue &value, ItemValue **ppPrevValues, ItemValue &fvalue, NetObj *target, DCItem *dci)
5039dede 231{
0f2eaffc
VK
232 // check if there is enough cached data
233 switch(m_function)
234 {
235 case F_DIFF:
236 if (ppPrevValues[0]->getTimeStamp() == 1) // Timestamp 1 means placeholder value inserted by cache loader
237 return m_isReached ? ALREADY_ACTIVE : ALREADY_INACTIVE;
238 break;
239 case F_AVERAGE:
240 case F_SUM:
241 case F_DEVIATION:
242 for(int i = 0; i < m_sampleCount - 1; i++)
243 if (ppPrevValues[i]->getTimeStamp() == 1) // Timestamp 1 means placeholder value inserted by cache loader
244 return m_isReached ? ALREADY_ACTIVE : ALREADY_INACTIVE;
245 break;
246 default:
247 break;
248 }
249
5039dede 250 BOOL bMatch = FALSE;
a0dc14f9 251 int iDataType = m_dataType;
5039dede
AK
252
253 // Execute function on value
d9ae1904 254 switch(m_function)
5039dede
AK
255 {
256 case F_LAST: // Check last value only
1d34c533 257 case F_SCRIPT:
5039dede
AK
258 fvalue = value;
259 break;
260 case F_AVERAGE: // Check average value for last n polls
d9ae1904 261 calculateAverageValue(&fvalue, value, ppPrevValues);
5039dede 262 break;
007a87e7
VK
263 case F_SUM:
264 calculateSumValue(&fvalue, value, ppPrevValues);
265 break;
5039dede 266 case F_DEVIATION: // Check mean absolute deviation
d9ae1904 267 calculateMDValue(&fvalue, value, ppPrevValues);
5039dede
AK
268 break;
269 case F_DIFF:
d9ae1904
VK
270 calculateDiff(&fvalue, value, ppPrevValues);
271 if (m_dataType == DCI_DT_STRING)
5039dede
AK
272 iDataType = DCI_DT_INT; // diff() for strings is an integer
273 break;
274 case F_ERROR: // Check for collection error
967893bb 275 fvalue = (UINT32)0;
5039dede
AK
276 break;
277 default:
278 break;
279 }
280
281 // Run comparision operation on function result and threshold value
d9ae1904 282 if (m_function == F_ERROR)
5039dede
AK
283 {
284 // Threshold::Check() can be called only for valid values, which
285 // means that error thresholds cannot be active
286 bMatch = FALSE;
287 }
1d34c533
VK
288 else if (m_function == F_SCRIPT)
289 {
290 if (m_script != NULL)
291 {
615621a4
VK
292 NXSL_VM *vm = new NXSL_VM(new NXSL_ServerEnv());
293 if (vm->load(m_script))
1d34c533 294 {
615621a4
VK
295 NXSL_Value *parameters[2];
296 parameters[0] = new NXSL_Value(value.getString());
297 parameters[1] = new NXSL_Value(m_value.getString());
298 vm->setGlobalVariable(_T("$object"), target->createNXSLObject());
299 if (target->getObjectClass() == OBJECT_NODE)
300 {
301 vm->setGlobalVariable(_T("$node"), new NXSL_Value(new NXSL_Object(&g_nxslNodeClass, target)));
302 }
303 vm->setGlobalVariable(_T("$dci"), dci->createNXSLObject());
304 vm->setGlobalVariable(_T("$isCluster"), new NXSL_Value((target->getObjectClass() == OBJECT_CLUSTER) ? 1 : 0));
305 if (vm->run(2, parameters))
1d34c533 306 {
615621a4
VK
307 NXSL_Value *result = vm->getResult();
308 if (result != NULL)
309 {
310 bMatch = (result->getValueAsInt32() != 0);
311 }
312 }
313 else
314 {
315 TCHAR buffer[1024];
316 _sntprintf(buffer, 1024, _T("DCI::%s::%d::%d::ThresholdScript"), target->getName(), dci->getId(), m_id);
317 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, dci->getId(), "ssd", buffer, vm->getErrorText(), dci->getId());
318 nxlog_write(MSG_THRESHOLD_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "sdds", target->getName(), dci->getId(), m_id, vm->getErrorText());
1d34c533
VK
319 }
320 }
321 else
322 {
323 TCHAR buffer[1024];
c42b4551 324 _sntprintf(buffer, 1024, _T("DCI::%s::%d::%d::ThresholdScript"), target->getName(), dci->getId(), m_id);
615621a4
VK
325 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, dci->getId(), "ssd", buffer, vm->getErrorText(), dci->getId());
326 nxlog_write(MSG_THRESHOLD_SCRIPT_EXECUTION_ERROR, NXLOG_WARNING, "sdds", target->getName(), dci->getId(), m_id, vm->getErrorText());
1d34c533 327 }
615621a4 328 delete vm;
1d34c533
VK
329 }
330 else
331 {
332 DbgPrintf(7, _T("Script not compiled for threshold %d of DCI %d of data collection target %s [%d]"),
c42b4551 333 m_id, dci->getId(), target->getName(), target->getId());
1d34c533
VK
334 }
335 }
5039dede
AK
336 else
337 {
d9ae1904 338 switch(m_operation)
5039dede
AK
339 {
340 case OP_LE: // Less
341 switch(iDataType)
342 {
343 case DCI_DT_INT:
967893bb 344 bMatch = ((INT32)fvalue < (INT32)m_value);
5039dede
AK
345 break;
346 case DCI_DT_UINT:
967893bb 347 bMatch = ((UINT32)fvalue < (UINT32)m_value);
5039dede
AK
348 break;
349 case DCI_DT_INT64:
350 bMatch = ((INT64)fvalue < (INT64)m_value);
351 break;
352 case DCI_DT_UINT64:
967893bb 353 bMatch = ((UINT64)fvalue < (UINT64)m_value);
5039dede
AK
354 break;
355 case DCI_DT_FLOAT:
356 bMatch = ((double)fvalue < (double)m_value);
357 break;
358 }
359 break;
360 case OP_LE_EQ: // Less or equal
361 switch(iDataType)
362 {
363 case DCI_DT_INT:
967893bb 364 bMatch = ((INT32)fvalue <= (INT32)m_value);
5039dede
AK
365 break;
366 case DCI_DT_UINT:
967893bb 367 bMatch = ((UINT32)fvalue <= (UINT32)m_value);
5039dede
AK
368 break;
369 case DCI_DT_INT64:
370 bMatch = ((INT64)fvalue <= (INT64)m_value);
371 break;
372 case DCI_DT_UINT64:
967893bb 373 bMatch = ((UINT64)fvalue <= (UINT64)m_value);
5039dede
AK
374 break;
375 case DCI_DT_FLOAT:
376 bMatch = ((double)fvalue <= (double)m_value);
377 break;
378 }
379 break;
380 case OP_EQ: // Equal
381 switch(iDataType)
382 {
383 case DCI_DT_INT:
967893bb 384 bMatch = ((INT32)fvalue == (INT32)m_value);
5039dede
AK
385 break;
386 case DCI_DT_UINT:
967893bb 387 bMatch = ((UINT32)fvalue == (UINT32)m_value);
5039dede
AK
388 break;
389 case DCI_DT_INT64:
390 bMatch = ((INT64)fvalue == (INT64)m_value);
391 break;
392 case DCI_DT_UINT64:
967893bb 393 bMatch = ((UINT64)fvalue == (UINT64)m_value);
5039dede
AK
394 break;
395 case DCI_DT_FLOAT:
396 bMatch = ((double)fvalue == (double)m_value);
397 break;
398 case DCI_DT_STRING:
df94e0ce 399 bMatch = !_tcscmp(fvalue.getString(), m_value.getString());
5039dede
AK
400 break;
401 }
402 break;
403 case OP_GT_EQ: // Greater or equal
404 switch(iDataType)
405 {
406 case DCI_DT_INT:
967893bb 407 bMatch = ((INT32)fvalue >= (INT32)m_value);
5039dede
AK
408 break;
409 case DCI_DT_UINT:
967893bb 410 bMatch = ((UINT32)fvalue >= (UINT32)m_value);
5039dede
AK
411 break;
412 case DCI_DT_INT64:
413 bMatch = ((INT64)fvalue >= (INT64)m_value);
414 break;
415 case DCI_DT_UINT64:
967893bb 416 bMatch = ((UINT64)fvalue >= (UINT64)m_value);
5039dede
AK
417 break;
418 case DCI_DT_FLOAT:
419 bMatch = ((double)fvalue >= (double)m_value);
420 break;
421 }
422 break;
423 case OP_GT: // Greater
424 switch(iDataType)
425 {
426 case DCI_DT_INT:
967893bb 427 bMatch = ((INT32)fvalue > (INT32)m_value);
5039dede
AK
428 break;
429 case DCI_DT_UINT:
967893bb 430 bMatch = ((UINT32)fvalue > (UINT32)m_value);
5039dede
AK
431 break;
432 case DCI_DT_INT64:
433 bMatch = ((INT64)fvalue > (INT64)m_value);
434 break;
435 case DCI_DT_UINT64:
967893bb 436 bMatch = ((UINT64)fvalue > (UINT64)m_value);
5039dede
AK
437 break;
438 case DCI_DT_FLOAT:
439 bMatch = ((double)fvalue > (double)m_value);
440 break;
441 }
442 break;
443 case OP_NE: // Not equal
444 switch(iDataType)
445 {
446 case DCI_DT_INT:
967893bb 447 bMatch = ((INT32)fvalue != (INT32)m_value);
5039dede
AK
448 break;
449 case DCI_DT_UINT:
967893bb 450 bMatch = ((UINT32)fvalue != (UINT32)m_value);
5039dede
AK
451 break;
452 case DCI_DT_INT64:
453 bMatch = ((INT64)fvalue != (INT64)m_value);
454 break;
455 case DCI_DT_UINT64:
967893bb 456 bMatch = ((UINT64)fvalue != (UINT64)m_value);
5039dede
AK
457 break;
458 case DCI_DT_FLOAT:
459 bMatch = ((double)fvalue != (double)m_value);
460 break;
461 case DCI_DT_STRING:
df94e0ce 462 bMatch = _tcscmp(fvalue.getString(), m_value.getString());
5039dede
AK
463 break;
464 }
465 break;
466 case OP_LIKE:
467 // This operation can be performed only on strings
d9ae1904 468 if (m_dataType == DCI_DT_STRING)
9098ad59 469 bMatch = MatchString(m_value.getString(), fvalue.getString(), true);
5039dede
AK
470 break;
471 case OP_NOTLIKE:
472 // This operation can be performed only on strings
d9ae1904 473 if (m_dataType == DCI_DT_STRING)
9098ad59 474 bMatch = !MatchString(m_value.getString(), fvalue.getString(), true);
5039dede
AK
475 break;
476 default:
477 break;
478 }
479 }
480
481 // Check for number of consecutive matches
1d34c533 482 if ((m_function == F_LAST) || (m_function == F_SCRIPT))
5039dede
AK
483 {
484 if (bMatch)
485 {
d9ae1904 486 m_numMatches++;
1d34c533 487 if (m_numMatches < m_sampleCount)
5039dede
AK
488 bMatch = FALSE;
489 }
490 else
491 {
d9ae1904 492 m_numMatches = 0;
5039dede
AK
493 }
494 }
495
a0dc14f9 496 ThresholdCheckResult result = (bMatch & !m_isReached) ? ACTIVATED : ((!bMatch & m_isReached) ? DEACTIVATED : (m_isReached ? ALREADY_ACTIVE : ALREADY_INACTIVE));
d9ae1904 497 m_isReached = bMatch;
a0dc14f9 498 if (result == ACTIVATED || result == DEACTIVATED)
5039dede 499 {
5039dede 500 // Update threshold status in database
a0dc14f9
VK
501 TCHAR szQuery[256];
502 _sntprintf(szQuery, 256, _T("UPDATE thresholds SET current_state=%d WHERE threshold_id=%d"), (int)m_isReached, (int)m_id);
5039dede
AK
503 QueueSQLRequest(szQuery);
504 }
a0dc14f9 505 return result;
5039dede
AK
506}
507
85ae39bc
VK
508/**
509 * Mark last activation event
510 */
711e5e9a
VK
511void Threshold::markLastEvent(int severity)
512{
513 m_lastEventTimestamp = time(NULL);
514 m_currentSeverity = (BYTE)severity;
515
516 // Update threshold in database
517 TCHAR query[256];
518 _sntprintf(query, 256,
519 _T("UPDATE thresholds SET current_severity=%d,last_event_timestamp=%d WHERE threshold_id=%d"),
520 (int)m_currentSeverity, (int)m_lastEventTimestamp, (int)m_id);
521 QueueSQLRequest(query);
522}
523
85ae39bc
VK
524/**
525 * Check for collection error thresholds
526 * Return same values as Check()
527 */
a0dc14f9 528ThresholdCheckResult Threshold::checkError(UINT32 dwErrorCount)
5039dede 529{
d9ae1904 530 if (m_function != F_ERROR)
a0dc14f9 531 return m_isReached ? ALREADY_ACTIVE : ALREADY_INACTIVE;
5039dede 532
1d34c533 533 BOOL bMatch = ((UINT32)m_sampleCount <= dwErrorCount);
a0dc14f9 534 ThresholdCheckResult result = (bMatch & !m_isReached) ? ACTIVATED : ((!bMatch & m_isReached) ? DEACTIVATED : (m_isReached ? ALREADY_ACTIVE : ALREADY_INACTIVE));
d9ae1904 535 m_isReached = bMatch;
a0dc14f9 536 if (result == ACTIVATED || result == DEACTIVATED)
5039dede 537 {
5039dede 538 // Update threshold status in database
a0dc14f9
VK
539 TCHAR szQuery[256];
540 _sntprintf(szQuery, 256, _T("UPDATE thresholds SET current_state=%d WHERE threshold_id=%d"), m_isReached, m_id);
5039dede
AK
541 QueueSQLRequest(szQuery);
542 }
a0dc14f9 543 return result;
5039dede
AK
544}
545
a0dc14f9
VK
546/**
547 * Fill DCI_THRESHOLD with object's data ready to send over the network
548 */
b368969c 549void Threshold::createMessage(NXCPMessage *msg, UINT32 baseId)
5039dede 550{
967893bb 551 UINT32 varId = baseId;
d9ae1904 552
b368969c
VK
553 msg->setField(varId++, m_id);
554 msg->setField(varId++, m_eventCode);
555 msg->setField(varId++, m_rearmEventCode);
556 msg->setField(varId++, (WORD)m_function);
557 msg->setField(varId++, (WORD)m_operation);
558 msg->setField(varId++, (UINT32)m_sampleCount);
559 msg->setField(varId++, CHECK_NULL_EX(m_scriptSource));
560 msg->setField(varId++, (UINT32)m_repeatInterval);
561 msg->setField(varId++, m_value.getString());
562 msg->setField(varId++, (WORD)m_isReached);
563 msg->setField(varId++, (WORD)m_currentSeverity);
564 msg->setField(varId++, (UINT32)m_lastEventTimestamp);
5039dede
AK
565}
566
85ae39bc
VK
567/**
568 * Update threshold object from NXCP message
569 */
b368969c 570void Threshold::updateFromMessage(NXCPMessage *msg, UINT32 baseId)
5039dede 571{
d9ae1904 572 TCHAR buffer[MAX_DCI_STRING_VALUE];
967893bb 573 UINT32 varId = baseId + 1; // Skip ID field
d9ae1904 574
b368969c
VK
575 m_eventCode = msg->getFieldAsUInt32(varId++);
576 m_rearmEventCode = msg->getFieldAsUInt32(varId++);
577 m_function = (BYTE)msg->getFieldAsUInt16(varId++);
578 m_operation = (BYTE)msg->getFieldAsUInt16(varId++);
579 m_sampleCount = (int)msg->getFieldAsUInt32(varId++);
580 setScript(msg->getFieldAsString(varId++));
581 m_repeatInterval = (int)msg->getFieldAsUInt32(varId++);
582 m_value = msg->getFieldAsString(varId++, buffer, MAX_DCI_STRING_VALUE);
5039dede
AK
583}
584
1d34c533
VK
585/**
586 * Calculate average value for parameter
587 */
5039dede
AK
588#define CALC_AVG_VALUE(vtype) \
589{ \
590 vtype var; \
591 var = (vtype)lastValue; \
0f2eaffc 592 for(int i = 1; i < m_sampleCount; i++) \
5039dede 593 { \
0f2eaffc 594 var += (vtype)(*ppPrevValues[i - 1]); \
5039dede 595 } \
0f2eaffc 596 *pResult = var / (vtype)m_sampleCount; \
5039dede
AK
597}
598
d9ae1904 599void Threshold::calculateAverageValue(ItemValue *pResult, ItemValue &lastValue, ItemValue **ppPrevValues)
5039dede 600{
d9ae1904 601 switch(m_dataType)
5039dede
AK
602 {
603 case DCI_DT_INT:
967893bb 604 CALC_AVG_VALUE(INT32);
5039dede
AK
605 break;
606 case DCI_DT_UINT:
967893bb 607 CALC_AVG_VALUE(UINT32);
5039dede
AK
608 break;
609 case DCI_DT_INT64:
610 CALC_AVG_VALUE(INT64);
611 break;
612 case DCI_DT_UINT64:
967893bb 613 CALC_AVG_VALUE(UINT64);
5039dede
AK
614 break;
615 case DCI_DT_FLOAT:
616 CALC_AVG_VALUE(double);
617 break;
618 case DCI_DT_STRING:
619 *pResult = _T(""); // Average value for string is meaningless
620 break;
621 default:
622 break;
623 }
624}
625
85ae39bc 626/**
0f2eaffc 627 * Calculate sum value for values of given type
85ae39bc 628 */
007a87e7
VK
629#define CALC_SUM_VALUE(vtype) \
630{ \
631 vtype var; \
632 var = (vtype)lastValue; \
0f2eaffc 633 for(int i = 1; i < m_sampleCount; i++) \
007a87e7 634 { \
0f2eaffc 635 var += (vtype)(*ppPrevValues[i - 1]); \
007a87e7
VK
636 } \
637 *pResult = var; \
638}
639
0f2eaffc
VK
640/**
641 * Calculate sum value for parameter
642 */
643void Threshold::calculateSumValue(ItemValue *pResult, ItemValue &lastValue, ItemValue **ppPrevValues)
644{
007a87e7
VK
645 switch(m_dataType)
646 {
647 case DCI_DT_INT:
967893bb 648 CALC_SUM_VALUE(INT32);
007a87e7
VK
649 break;
650 case DCI_DT_UINT:
967893bb 651 CALC_SUM_VALUE(UINT32);
007a87e7
VK
652 break;
653 case DCI_DT_INT64:
654 CALC_SUM_VALUE(INT64);
655 break;
656 case DCI_DT_UINT64:
967893bb 657 CALC_SUM_VALUE(UINT64);
007a87e7
VK
658 break;
659 case DCI_DT_FLOAT:
660 CALC_SUM_VALUE(double);
661 break;
662 case DCI_DT_STRING:
663 *pResult = _T(""); // Sum value for string is meaningless
664 break;
665 default:
666 break;
667 }
668}
669
0f2eaffc
VK
670/**
671 * Calculate mean absolute deviation for values of given type
672 */
5039dede
AK
673#define CALC_MD_VALUE(vtype) \
674{ \
675 vtype mean, dev; \
676 mean = (vtype)lastValue; \
0f2eaffc 677 for(i = 1; i < m_sampleCount; i++) \
5039dede 678 { \
0f2eaffc 679 mean += (vtype)(*ppPrevValues[i - 1]); \
5039dede 680 } \
0f2eaffc 681 mean /= (vtype)m_sampleCount; \
5039dede 682 dev = ABS((vtype)lastValue - mean); \
0f2eaffc 683 for(i = 1; i < m_sampleCount; i++) \
5039dede 684 { \
0f2eaffc 685 dev += ABS((vtype)(*ppPrevValues[i - 1]) - mean); \
5039dede 686 } \
0f2eaffc 687 *pResult = dev / (vtype)m_sampleCount; \
5039dede
AK
688}
689
0f2eaffc
VK
690/**
691 * Calculate mean absolute deviation for parameter
692 */
d9ae1904 693void Threshold::calculateMDValue(ItemValue *pResult, ItemValue &lastValue, ItemValue **ppPrevValues)
5039dede 694{
0f2eaffc 695 int i;
5039dede 696
d9ae1904 697 switch(m_dataType)
5039dede
AK
698 {
699 case DCI_DT_INT:
700#define ABS(x) ((x) < 0 ? -(x) : (x))
967893bb 701 CALC_MD_VALUE(INT32);
5039dede
AK
702 break;
703 case DCI_DT_INT64:
704 CALC_MD_VALUE(INT64);
705 break;
706 case DCI_DT_FLOAT:
707 CALC_MD_VALUE(double);
708 break;
709 case DCI_DT_UINT:
710#undef ABS
711#define ABS(x) (x)
967893bb 712 CALC_MD_VALUE(UINT32);
5039dede
AK
713 break;
714 case DCI_DT_UINT64:
967893bb 715 CALC_MD_VALUE(UINT64);
5039dede
AK
716 break;
717 case DCI_DT_STRING:
718 *pResult = _T(""); // Mean deviation for string is meaningless
719 break;
720 default:
721 break;
722 }
723}
724
725#undef ABS
726
85ae39bc
VK
727/**
728 * Calculate difference between last and previous value
729 */
d9ae1904 730void Threshold::calculateDiff(ItemValue *pResult, ItemValue &lastValue, ItemValue **ppPrevValues)
5039dede 731{
d9ae1904 732 CalculateItemValueDiff(*pResult, m_dataType, lastValue, *ppPrevValues[0]);
5039dede
AK
733}
734
85ae39bc
VK
735/**
736 * Compare to another threshold
737 */
d9ae1904 738BOOL Threshold::compare(Threshold *pThr)
5039dede
AK
739{
740 BOOL bMatch;
741
03de1819 742 if (m_function == F_SCRIPT)
5039dede 743 {
03de1819
VK
744 // Threat value field as string for script thresholds
745 bMatch = !_tcscmp(pThr->m_value.getString(), m_value.getString());
746 }
747 else
748 {
749 switch(m_dataType)
750 {
751 case DCI_DT_INT:
752 bMatch = ((INT32)pThr->m_value == (INT32)m_value);
753 break;
754 case DCI_DT_UINT:
755 bMatch = ((UINT32)pThr->m_value == (UINT32)m_value);
756 break;
757 case DCI_DT_INT64:
758 bMatch = ((INT64)pThr->m_value == (INT64)m_value);
759 break;
760 case DCI_DT_UINT64:
761 bMatch = ((UINT64)pThr->m_value == (UINT64)m_value);
762 break;
763 case DCI_DT_FLOAT:
764 bMatch = ((double)pThr->m_value == (double)m_value);
765 break;
766 case DCI_DT_STRING:
767 bMatch = !_tcscmp(pThr->m_value.getString(), m_value.getString());
768 break;
769 default:
770 bMatch = TRUE;
771 break;
772 }
5039dede
AK
773 }
774 return bMatch &&
d9ae1904
VK
775 (pThr->m_eventCode == m_eventCode) &&
776 (pThr->m_rearmEventCode == m_rearmEventCode) &&
777 (pThr->m_dataType == m_dataType) &&
778 (pThr->m_function == m_function) &&
779 (pThr->m_operation == m_operation) &&
1d34c533
VK
780 (pThr->m_sampleCount == m_sampleCount) &&
781 !_tcscmp(CHECK_NULL_EX(pThr->m_scriptSource), CHECK_NULL_EX(m_scriptSource)) &&
d9ae1904 782 (pThr->m_repeatInterval == m_repeatInterval);
5039dede
AK
783}
784
85ae39bc
VK
785/**
786 * Create management pack record
787 */
a65c1819 788void Threshold::createNXMPRecord(String &str, int index)
5039dede 789{
6e102d6e 790 TCHAR activationEvent[MAX_EVENT_NAME], deactivationEvent[MAX_EVENT_NAME];
5039dede 791
6e102d6e
VK
792 EventNameFromCode(m_eventCode, activationEvent);
793 EventNameFromCode(m_rearmEventCode, deactivationEvent);
4e0e77e6 794 str.appendFormattedString(_T("\t\t\t\t\t\t<threshold id=\"%d\">\n")
a7ff20a5
VK
795 _T("\t\t\t\t\t\t\t<function>%d</function>\n")
796 _T("\t\t\t\t\t\t\t<condition>%d</condition>\n")
797 _T("\t\t\t\t\t\t\t<value>%s</value>\n")
798 _T("\t\t\t\t\t\t\t<activationEvent>%s</activationEvent>\n")
799 _T("\t\t\t\t\t\t\t<deactivationEvent>%s</deactivationEvent>\n")
1d34c533
VK
800 _T("\t\t\t\t\t\t\t<sampleCount>%d</sampleCount>\n")
801 _T("\t\t\t\t\t\t\t<repeatInterval>%d</repeatInterval>\n"),
a65c1819 802 index, m_function, m_operation,
df94e0ce 803 (const TCHAR *)EscapeStringForXML2(m_value.getString()),
6e102d6e
VK
804 (const TCHAR *)EscapeStringForXML2(activationEvent),
805 (const TCHAR *)EscapeStringForXML2(deactivationEvent),
1d34c533
VK
806 m_sampleCount, m_repeatInterval);
807 if (m_scriptSource != NULL)
808 {
53a9a341
VK
809 str.append(_T("\t\t\t\t\t\t\t<script>"));
810 str.append(EscapeStringForXML2(m_scriptSource));
811 str.append(_T("</script>\n"));
1d34c533 812 }
53a9a341 813 str.append(_T("\t\t\t\t\t\t</threshold>\n"));
5039dede
AK
814}
815
85ae39bc
VK
816/**
817 * Make an association with DCI (used by management pack parser)
818 */
d9ae1904 819void Threshold::associate(DCItem *pItem)
5039dede 820{
fb05c05b 821 m_itemId = pItem->getId();
4804be4e 822 m_targetId = pItem->getOwnerId();
fb05c05b 823 m_dataType = pItem->getDataType();
5039dede 824}
1d34c533
VK
825
826/**
827 * Set new script. Script source must be dynamically allocated
828 * and will be deallocated by threshold object
829 */
830void Threshold::setScript(TCHAR *script)
831{
832 safe_free(m_scriptSource);
833 delete m_script;
834 if (script != NULL)
835 {
836 m_scriptSource = script;
837 StrStrip(m_scriptSource);
838 if (m_scriptSource[0] != 0)
839 {
615621a4
VK
840 TCHAR errorText[1024];
841 m_script = NXSLCompile(m_scriptSource, errorText, 1024, NULL);
842 if (m_script == NULL)
843 {
844 TCHAR buffer[1024], defaultName[32];
845 _sntprintf(defaultName, 32, _T("[%d]"), m_targetId);
846 _sntprintf(buffer, 1024, _T("DCI::%s::%d::%d::ThresholdScript"), GetObjectName(m_targetId, defaultName), m_itemId, m_id);
847 PostDciEvent(EVENT_SCRIPT_ERROR, g_dwMgmtNode, m_itemId, "ssd", buffer, errorText, m_itemId);
848 nxlog_write(MSG_THRESHOLD_SCRIPT_COMPILATION_ERROR, NXLOG_WARNING, "sdds", GetObjectName(m_targetId, defaultName), m_itemId, m_id, errorText);
849 }
1d34c533
VK
850 }
851 else
852 {
853 m_script = NULL;
854 }
855 }
856 else
857 {
858 m_scriptSource = NULL;
859 m_script = NULL;
860 }
861}