changed log file format
[public/netxms.git] / src / server / core / hk.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 Victor Kirhenshtein
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: hk.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 #define DEBUG_TAG _T("housekeeper")
26
27 /**
28 * Delete empty subnets from given list
29 */
30 static void DeleteEmptySubnetsFromList(ObjectArray<NetObj> *subnets)
31 {
32 for(int i = 0; i < subnets->size(); i++)
33 {
34 NetObj *object = subnets->get(i);
35 nxlog_debug_tag(DEBUG_TAG, 7, _T("DeleteEmptySubnets: checking subnet %s [%d] (refs: %d refs, children: %d, parents: %d)"),
36 object->getName(), object->getId(), object->getRefCount(), object->getChildCount(), object->getParentCount());
37 if (object->isEmpty())
38 {
39 nxlog_debug_tag(DEBUG_TAG, 5, _T("DeleteEmptySubnets: delete subnet %s [%d] (refs: %d, children: %d, parents: %d)"),
40 object->getName(), object->getId(), object->getRefCount(), object->getChildCount(), object->getParentCount());
41 object->deleteObject();
42 }
43 object->decRefCount();
44 }
45 }
46
47 /**
48 * Delete empty subnets
49 */
50 static void DeleteEmptySubnets()
51 {
52 if (IsZoningEnabled())
53 {
54 ObjectArray<NetObj> *zones = g_idxZoneByUIN.getObjects(true);
55 for(int i = 0; i < zones->size(); i++)
56 {
57 Zone *zone = (Zone *)zones->get(i);
58 ObjectArray<NetObj> *subnets = zone->getSubnets(true);
59 DeleteEmptySubnetsFromList(subnets);
60 delete subnets;
61 zone->decRefCount();
62 }
63 delete zones;
64 }
65 else
66 {
67 ObjectArray<NetObj> *subnets = g_idxSubnetByAddr.getObjects(true);
68 DeleteEmptySubnetsFromList(subnets);
69 delete subnets;
70 }
71 }
72
73 /**
74 * Delete notes for alarm
75 */
76 void DeleteAlarmNotes(DB_HANDLE hdb, UINT32 alarmId)
77 {
78 DB_STATEMENT hStmt = DBPrepare(hdb, _T("DELETE FROM alarm_notes WHERE alarm_id=?"));
79 if (hStmt == NULL)
80 return;
81
82 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, alarmId);
83 DBExecute(hStmt);
84 DBFreeStatement(hStmt);
85 }
86
87 /**
88 * Delete realted events for alarm
89 */
90 void DeleteAlarmEvents(DB_HANDLE hdb, UINT32 alarmId)
91 {
92 DB_STATEMENT hStmt = DBPrepare(hdb, _T("DELETE FROM alarm_events WHERE alarm_id=?"));
93 if (hStmt == NULL)
94 return;
95
96 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, alarmId);
97 DBExecute(hStmt);
98 DBFreeStatement(hStmt);
99 }
100
101 /**
102 * Remove outdated alarm records
103 */
104 static void CleanAlarmHistory(DB_HANDLE hdb)
105 {
106 UINT32 retentionTime = ConfigReadULong(_T("AlarmHistoryRetentionTime"), 180);
107 if (retentionTime == 0)
108 return;
109
110 nxlog_debug_tag(DEBUG_TAG, 2, _T("Clearing alarm log (retention time %d days)"), retentionTime);
111 retentionTime *= 86400; // Convert days to seconds
112 time_t ts = time(NULL) - (time_t)retentionTime;
113
114 DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT alarm_id FROM alarms WHERE alarm_state=3 AND last_change_time<?"));
115 if (hStmt != NULL)
116 {
117 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (UINT32)ts);
118 DB_RESULT hResult = DBSelectPrepared(hStmt);
119 if (hResult != NULL)
120 {
121 int count = DBGetNumRows(hResult);
122 for(int i = 0; i < count; i++)
123 {
124 UINT32 alarmId = DBGetFieldULong(hResult, i, 0);
125 DeleteAlarmNotes(hdb, alarmId);
126 DeleteAlarmEvents(hdb, alarmId);
127 }
128 DBFreeResult(hResult);
129 }
130 DBFreeStatement(hStmt);
131 }
132
133 hStmt = DBPrepare(hdb, _T("DELETE FROM alarms WHERE alarm_state=3 AND last_change_time<?"));
134 if (hStmt != NULL)
135 {
136 DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, (UINT32)ts);
137 DBExecute(hStmt);
138 DBFreeStatement(hStmt);
139 }
140 }
141
142 /**
143 * Callback for cleaning expired DCI data on node
144 */
145 static void CleanDciData(NetObj *object, void *data)
146 {
147 ((DataCollectionTarget *)object)->cleanDCIData((DB_HANDLE)data);
148 }
149
150 /**
151 * Housekeeper wakeup condition
152 */
153 static CONDITION s_wakeupCondition = INVALID_CONDITION_HANDLE;
154
155 /**
156 * Housekeeper shutdown flag
157 */
158 static bool s_shutdown = false;
159
160 /**
161 * Housekeeper thread
162 */
163 static THREAD_RESULT THREAD_CALL HouseKeeper(void *pArg)
164 {
165 ThreadSetName("Housekeeper");
166
167 // Read housekeeping configuration
168 int hour;
169 int minute;
170
171 TCHAR buffer[64];
172 ConfigReadStr(_T("HousekeeperStartTime"), buffer, 64, _T("02:00"));
173 TCHAR *p = _tcschr(buffer, _T(':'));
174 if (p != NULL)
175 {
176 *p = 0;
177 p++;
178 minute = _tcstol(p, NULL, 10);
179 if ((minute < 0) || (minute > 59))
180 {
181 nxlog_debug_tag(DEBUG_TAG, 2, _T("Invalid minute value %s"), p);
182 minute = 0;
183 }
184 }
185 else
186 {
187 minute = 0;
188 }
189 hour = _tcstol(buffer, NULL, 10);
190 if ((hour < 0) || (hour > 23))
191 {
192 nxlog_debug_tag(DEBUG_TAG, 2, _T("Invalid hour value %s"), buffer);
193 hour = 0;
194 }
195 nxlog_debug_tag(DEBUG_TAG, 2, _T("Wakeup time is %02d:%02d"), hour, minute);
196
197 int sleepTime = GetSleepTime(hour, minute, 0);
198 nxlog_debug_tag(DEBUG_TAG, 2, _T("Sleeping for %d seconds"), sleepTime);
199
200 while(!s_shutdown)
201 {
202 ConditionWait(s_wakeupCondition, sleepTime * 1000);
203 if (s_shutdown)
204 break;
205
206 nxlog_debug_tag(DEBUG_TAG, 2, _T("Wakeup"));
207
208 DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
209 CleanAlarmHistory(hdb);
210
211 time_t currTime = time(NULL);
212
213 // Remove outdated event log records
214 UINT32 dwRetentionTime = ConfigReadULong(_T("EventLogRetentionTime"), 90);
215 if (dwRetentionTime > 0)
216 {
217 nxlog_debug_tag(DEBUG_TAG, 2, _T("Clearing event log (retention time %d days)"), dwRetentionTime);
218 dwRetentionTime *= 86400; // Convert days to seconds
219 TCHAR query[256];
220 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM event_log WHERE event_timestamp<%ld"), (long)(currTime - dwRetentionTime));
221 DBQuery(hdb, query);
222 }
223
224 // Remove outdated syslog records
225 dwRetentionTime = ConfigReadULong(_T("SyslogRetentionTime"), 90);
226 if (dwRetentionTime > 0)
227 {
228 nxlog_debug_tag(DEBUG_TAG, 2, _T("Clearing syslog (retention time %d days)"), dwRetentionTime);
229 dwRetentionTime *= 86400; // Convert days to seconds
230 TCHAR query[256];
231 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM syslog WHERE msg_timestamp<%ld"), (long)(currTime - dwRetentionTime));
232 DBQuery(hdb, query);
233 }
234
235 // Remove outdated audit log records
236 dwRetentionTime = ConfigReadULong(_T("AuditLogRetentionTime"), 90);
237 if (dwRetentionTime > 0)
238 {
239 nxlog_debug_tag(DEBUG_TAG, 2, _T("Clearing audit log (retention time %d days)"), dwRetentionTime);
240 dwRetentionTime *= 86400; // Convert days to seconds
241 TCHAR query[256];
242 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM audit_log WHERE timestamp<%ld"), (long)(currTime - dwRetentionTime));
243 DBQuery(hdb, query);
244 }
245
246 // Remove outdated SNMP trap log records
247 dwRetentionTime = ConfigReadULong(_T("SNMPTrapLogRetentionTime"), 90);
248 if (dwRetentionTime > 0)
249 {
250 nxlog_debug_tag(DEBUG_TAG, 2, _T("Clearing SNMP trap log (retention time %d days)"), dwRetentionTime);
251 dwRetentionTime *= 86400; // Convert days to seconds
252 TCHAR query[256];
253 _sntprintf(query, sizeof(query) / sizeof(TCHAR), _T("DELETE FROM snmp_trap_log WHERE trap_timestamp<%ld"), (long)(currTime - dwRetentionTime));
254 DBQuery(hdb, query);
255 }
256
257 // Delete empty subnets if needed
258 if (g_flags & AF_DELETE_EMPTY_SUBNETS)
259 DeleteEmptySubnets();
260
261 // Remove expired DCI data
262 nxlog_debug_tag(DEBUG_TAG, 2, _T("Clearing collected DCI data"));
263 g_idxNodeById.forEach(CleanDciData, hdb);
264 g_idxClusterById.forEach(CleanDciData, hdb);
265 g_idxMobileDeviceById.forEach(CleanDciData, hdb);
266 g_idxSensorById.forEach(CleanDciData, hdb);
267
268 DBConnectionPoolReleaseConnection(hdb);
269
270 // Call hooks in loaded modules
271 for(UINT32 i = 0; i < g_dwNumModules; i++)
272 {
273 if (g_pModuleList[i].pfHousekeeperHook != NULL)
274 {
275 nxlog_debug_tag(DEBUG_TAG, 3, _T("Housekeeper: calling hook in module %s"), g_pModuleList[i].szName);
276 g_pModuleList[i].pfHousekeeperHook();
277 }
278 }
279
280 SaveCurrentFreeId();
281
282 ThreadSleep(1); // to prevent multiple executions if processing took less then 1 second
283 sleepTime = GetSleepTime(hour, minute, 0);
284 nxlog_debug_tag(DEBUG_TAG, 2, _T("Sleeping for %d seconds"), sleepTime);
285 }
286
287 nxlog_debug_tag(DEBUG_TAG, 1, _T("Housekeeper thread terminated"));
288 return THREAD_OK;
289 }
290
291 /**
292 * Housekeeper thread handle
293 */
294 static THREAD s_thread = INVALID_THREAD_HANDLE;
295
296 /**
297 * Start housekeeper
298 */
299 void StartHouseKeeper()
300 {
301 s_wakeupCondition = ConditionCreate(FALSE);
302 s_thread = ThreadCreateEx(HouseKeeper, 0, NULL);
303 }
304
305 /**
306 * Stop housekeeper
307 */
308 void StopHouseKeeper()
309 {
310 s_shutdown = true;
311 ConditionSet(s_wakeupCondition);
312 ThreadJoin(s_thread);
313 ConditionDestroy(s_wakeupCondition);
314 }
315
316 /**
317 * Run housekeeper
318 */
319 void RunHouseKeeper()
320 {
321 ConditionSet(s_wakeupCondition);
322 }