String class refactored; background log writer option implemented; fixed incorrect...
[public/netxms.git] / src / libnxlp / rule.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Log Parsing Library
4 ** Copyright (C) 2003-2013 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: rule.cpp
21 **
22 **/
23
24 #include "libnxlp.h"
25
26 #if HAVE_ALLOCA_H
27 #include <alloca.h>
28 #endif
29
30 /**
31 * Constructor
32 */
33 LogParserRule::LogParserRule(LogParser *parser, const TCHAR *regexp, UINT32 eventCode, const TCHAR *eventName,
34 int numParams, const TCHAR *source, UINT32 level, UINT32 idStart, UINT32 idEnd)
35 {
36 String expandedRegexp;
37
38 m_parser = parser;
39 expandMacros(regexp, expandedRegexp);
40 m_regexp = _tcsdup(expandedRegexp);
41 m_isValid = (_tregcomp(&m_preg, expandedRegexp, REG_EXTENDED | REG_ICASE) == 0);
42 m_eventCode = eventCode;
43 m_eventName = (eventName != NULL) ? _tcsdup(eventName) : NULL;
44 m_numParams = numParams;
45 m_pmatch = (numParams > 0) ? (regmatch_t *)malloc(sizeof(regmatch_t) * (numParams + 1)) : NULL;
46 m_source = (source != NULL) ? _tcsdup(source) : NULL;
47 m_level = level;
48 m_idStart = idStart;
49 m_idEnd = idEnd;
50 m_context = NULL;
51 m_contextAction = 0;
52 m_contextToChange = NULL;
53 m_isInverted = FALSE;
54 m_breakOnMatch = FALSE;
55 m_description = NULL;
56 }
57
58 /**
59 * Copy constructor
60 */
61 LogParserRule::LogParserRule(LogParserRule *src, LogParser *parser)
62 {
63 m_parser = parser;
64 m_regexp = _tcsdup(src->m_regexp);
65 m_isValid = (_tregcomp(&m_preg, m_regexp, REG_EXTENDED | REG_ICASE) == 0);
66 m_eventCode = src->m_eventCode;
67 m_eventName = (src->m_eventName != NULL) ? _tcsdup(src->m_eventName) : NULL;
68 m_numParams = src->m_numParams;
69 m_pmatch = (m_numParams > 0) ? (regmatch_t *)malloc(sizeof(regmatch_t) * (m_numParams + 1)) : NULL;
70 m_source = (src->m_source != NULL) ? _tcsdup(src->m_source) : NULL;
71 m_level = src->m_level;
72 m_idStart = src->m_idStart;
73 m_idEnd = src->m_idEnd;
74 m_context = (src->m_context != NULL) ? _tcsdup(src->m_context) : NULL;
75 m_contextAction = src->m_contextAction;
76 m_contextToChange = (src->m_contextToChange != NULL) ? _tcsdup(src->m_contextToChange) : NULL;;
77 m_isInverted = src->m_isInverted;
78 m_breakOnMatch = src->m_breakOnMatch;
79 m_description = (src->m_description != NULL) ? _tcsdup(src->m_description) : NULL;;
80 }
81
82 /**
83 * Destructor
84 */
85 LogParserRule::~LogParserRule()
86 {
87 if (m_isValid)
88 regfree(&m_preg);
89 safe_free(m_pmatch);
90 safe_free(m_description);
91 safe_free(m_source);
92 safe_free(m_regexp);
93 safe_free(m_eventName);
94 safe_free(m_context);
95 safe_free(m_contextToChange);
96 }
97
98 /**
99 * Match line
100 */
101 bool LogParserRule::matchInternal(bool extMode, const TCHAR *source, UINT32 eventId, UINT32 level,
102 const TCHAR *line, LogParserCallback cb, UINT32 objectId, void *userArg)
103 {
104 if (extMode)
105 {
106 if (m_source != NULL)
107 {
108 m_parser->trace(6, _T(" matching source \"%s\" against pattern \"%s\""), source, m_source);
109 if (!MatchString(m_source, source, FALSE))
110 {
111 m_parser->trace(6, _T(" source: no match"));
112 return false;
113 }
114 }
115
116 if ((eventId < m_idStart) || (eventId > m_idEnd))
117 {
118 m_parser->trace(6, _T(" event id 0x%08x not in range 0x%08x - 0x%08x"), eventId, m_idStart, m_idEnd);
119 return false;
120 }
121
122 if (!(m_level & level))
123 {
124 m_parser->trace(6, _T(" severity level 0x%04x not match mask 0x%04x"), level, m_level);
125 return false;
126 }
127 }
128
129 if (!m_isValid)
130 {
131 m_parser->trace(6, _T(" regexp is invalid: %s"), m_regexp);
132 return false;
133 }
134
135 if (m_isInverted)
136 {
137 m_parser->trace(6, _T(" negated matching against regexp %s"), m_regexp);
138 if (_tregexec(&m_preg, line, 0, NULL, 0) != 0)
139 {
140 m_parser->trace(6, _T(" matched"));
141 if ((cb != NULL) && ((m_eventCode != 0) || (m_eventName != NULL)))
142 cb(m_eventCode, m_eventName, line, source, eventId, level, 0, NULL, objectId, userArg);
143 return true;
144 }
145 }
146 else
147 {
148 m_parser->trace(6, _T(" matching against regexp %s"), m_regexp);
149 if (_tregexec(&m_preg, line, (m_numParams > 0) ? m_numParams + 1 : 0, m_pmatch, 0) == 0)
150 {
151 m_parser->trace(6, _T(" matched"));
152 if ((cb != NULL) && ((m_eventCode != 0) || (m_eventName != NULL)))
153 {
154 TCHAR **params = NULL;
155 int i, len;
156
157 if (m_numParams > 0)
158 {
159 params = (TCHAR **)alloca(sizeof(TCHAR *) * m_numParams);
160 for(i = 0; i < m_numParams; i++)
161 {
162 if (m_pmatch[i + 1].rm_so != -1)
163 {
164 len = m_pmatch[i + 1].rm_eo - m_pmatch[i + 1].rm_so;
165 params[i] = (TCHAR *)malloc((len + 1) * sizeof(TCHAR));
166 memcpy(params[i], &line[m_pmatch[i + 1].rm_so], len * sizeof(TCHAR));
167 params[i][len] = 0;
168 }
169 else
170 {
171 params[i] = _tcsdup(_T(""));
172 }
173 }
174 }
175
176 cb(m_eventCode, m_eventName, line, source, eventId, level, m_numParams, params, objectId, userArg);
177
178 for(i = 0; i < m_numParams; i++)
179 safe_free(params[i]);
180 }
181 return true;
182 }
183 }
184
185 m_parser->trace(6, _T(" no match"));
186 return false; // no match
187 }
188
189 /**
190 * Match line
191 */
192 bool LogParserRule::match(const TCHAR *line, LogParserCallback cb, UINT32 objectId, void *userArg)
193 {
194 return matchInternal(false, NULL, 0, 0, line, cb, objectId, userArg);
195 }
196
197 /**
198 * Match event
199 */
200 bool LogParserRule::matchEx(const TCHAR *source, UINT32 eventId, UINT32 level,
201 const TCHAR *line, LogParserCallback cb, UINT32 objectId, void *userArg)
202 {
203 return matchInternal(true, source, eventId, level, line, cb, objectId, userArg);
204 }
205
206 /**
207 * Expand macros in regexp
208 */
209 void LogParserRule::expandMacros(const TCHAR *regexp, String &out)
210 {
211 const TCHAR *curr, *prev;
212 TCHAR name[256];
213
214 for(curr = prev = regexp; *curr != 0; curr++)
215 {
216 if (*curr == _T('@'))
217 {
218 // Check for escape
219 if ((curr != regexp) && (*(curr - 1) == _T('\\')))
220 {
221 out.append(prev, (size_t)(curr - prev - 1));
222 out += _T("@");
223 }
224 else
225 {
226 // { should follow @
227 if (*(curr + 1) == _T('{'))
228 {
229 int i;
230
231 out.append(prev, (size_t)(curr - prev));
232 curr += 2;
233 for(i = 0; (*curr != 0) && (*curr != '}'); i++)
234 name[i] = *curr++;
235 name[i] = 0;
236 out += m_parser->getMacro(name);
237 }
238 else
239 {
240 out.append(prev, (size_t)(curr - prev + 1));
241 }
242 }
243 prev = curr + 1;
244 }
245 }
246 out.append(prev, (size_t)(curr - prev));
247 }