license changed to LGPL for libnxcl, libnxsnmp, libnxlp, libnxsl, and libnxmap
[public/netxms.git] / src / libnxlp / rule.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Log Parsing Library
4 ** Copyright (C) 2003-2010 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 defined(_WIN32)
27 #include <malloc.h>
28 #elif HAVE_ALLOCA_H
29 #include <alloca.h>
30 #endif
31
32
33 //
34 // Constructor
35 //
36
37 LogParserRule::LogParserRule(LogParser *parser,
38 const char *regexp, DWORD event, int numParams,
39 const TCHAR *source, DWORD level,
40 DWORD idStart, DWORD idEnd)
41 {
42 String expandedRegexp;
43
44 m_parser = parser;
45 expandMacros(regexp, expandedRegexp);
46 m_regexp = _tcsdup(expandedRegexp);
47 m_isValid = (regcomp(&m_preg, expandedRegexp, REG_EXTENDED | REG_ICASE) == 0);
48 m_event = event;
49 m_numParams = numParams;
50 m_pmatch = (numParams > 0) ? (regmatch_t *)malloc(sizeof(regmatch_t) * (numParams + 1)) : NULL;
51 m_source = (source != NULL) ? _tcsdup(source) : NULL;
52 m_level = level;
53 m_idStart = idStart;
54 m_idEnd = idEnd;
55 m_context = NULL;
56 m_contextAction = 0;
57 m_contextToChange = NULL;
58 m_isInverted = FALSE;
59 m_breakOnMatch = FALSE;
60 m_description = NULL;
61 }
62
63
64 //
65 // Destructor
66 //
67
68 LogParserRule::~LogParserRule()
69 {
70 if (m_isValid)
71 regfree(&m_preg);
72 safe_free(m_pmatch);
73 safe_free(m_description);
74 safe_free(m_source);
75 safe_free(m_regexp);
76 }
77
78
79 //
80 // Match line
81 //
82
83 bool LogParserRule::match(const char *line, LogParserCallback cb, DWORD objectId, void *userArg)
84 {
85 if (!m_isValid)
86 {
87 m_parser->trace(6, _T(" regexp is invalid: %s"), m_regexp);
88 return false;
89 }
90
91 if (m_isInverted)
92 {
93 m_parser->trace(6, _T(" negated matching against regexp %s"), m_regexp);
94 if (regexec(&m_preg, line, 0, NULL, 0) != 0)
95 {
96 m_parser->trace(6, _T(" matched"));
97 if ((cb != NULL) && (m_event != 0))
98 cb(m_event, line, 0, NULL, objectId, userArg);
99 return true;
100 }
101 }
102 else
103 {
104 m_parser->trace(6, _T(" matching against regexp %s"), m_regexp);
105 if (regexec(&m_preg, line, (m_numParams > 0) ? m_numParams + 1 : 0, m_pmatch, 0) == 0)
106 {
107 m_parser->trace(6, _T(" matched"));
108 if ((cb != NULL) && (m_event != 0))
109 {
110 char **params = NULL;
111 int i, len;
112
113 if (m_numParams > 0)
114 {
115 params = (char **)alloca(sizeof(char *) * m_numParams);
116 for(i = 0; i < m_numParams; i++)
117 {
118 if (m_pmatch[i + 1].rm_so != -1)
119 {
120 len = m_pmatch[i + 1].rm_eo - m_pmatch[i + 1].rm_so;
121 params[i] = (char *)malloc(len + 1);
122 memcpy(params[i], &line[m_pmatch[i + 1].rm_so], len);
123 params[i][len] = 0;
124 }
125 else
126 {
127 params[i] = strdup("");
128 }
129 }
130 }
131
132 cb(m_event, line, m_numParams, params, objectId, userArg);
133
134 for(i = 0; i < m_numParams; i++)
135 safe_free(params[i]);
136 }
137 return true;
138 }
139 }
140
141 m_parser->trace(6, _T(" no match"));
142 return false; // no match
143 }
144
145
146 //
147 // Match event
148 //
149
150 bool LogParserRule::matchEx(const TCHAR *source, DWORD eventId, DWORD level,
151 const char *line, LogParserCallback cb, DWORD objectId, void *userArg)
152 {
153 if (m_source != NULL)
154 {
155 m_parser->trace(6, _T(" matching source \"%s\" against pattern \"%s\""), source, m_source);
156 if (!MatchString(m_source, source, FALSE))
157 {
158 m_parser->trace(6, _T(" source: no match"));
159 return false;
160 }
161 }
162
163 if ((eventId < m_idStart) || (eventId > m_idEnd))
164 {
165 m_parser->trace(6, _T(" event id 0x%08x not in range 0x%08x - 0x%08x"), eventId, m_idStart, m_idEnd);
166 return false;
167 }
168
169 if (!(m_level & level))
170 {
171 m_parser->trace(6, _T(" severity level 0x%04x not match mask 0x%04x"), level, m_level);
172 return false;
173 }
174
175 return match(line, cb, objectId, userArg);
176 }
177
178
179 //
180 // Expand macros in regexp
181 //
182
183 void LogParserRule::expandMacros(const char *regexp, String &out)
184 {
185 const char *curr, *prev;
186 char name[256];
187
188 for(curr = prev = regexp; *curr != 0; curr++)
189 {
190 if (*curr == '@')
191 {
192 // Check for escape
193 if ((curr != regexp) && (*(curr - 1) == '\\'))
194 {
195 out.addString(prev, (DWORD)(curr - prev - 1));
196 out += _T("@");
197 }
198 else
199 {
200 // { should follow @
201 if (*(curr + 1) == '{')
202 {
203 int i;
204
205 out.addString(prev, (DWORD)(curr - prev));
206 curr += 2;
207 for(i = 0; (*curr != 0) && (*curr != '}'); i++)
208 name[i] = *curr++;
209 name[i] = 0;
210 out += m_parser->getMacro(name);
211 }
212 else
213 {
214 out.addString(prev, (DWORD)(curr - prev + 1));
215 }
216 }
217 prev = curr + 1;
218 }
219 }
220 out.addString(prev, (DWORD)(curr - prev));
221 }