Remove --ignore-process-events
[nagios-reports-module.git] / showlog.c
blob220a599b249306ebed946d130c2630644e7487a3
1 #define _GNU_SOURCE 1
2 #include <sys/types.h>
3 #include <signal.h>
5 #include "logging.h"
6 #include "hash.h"
7 #include "lparse.h"
8 #include "logutils.h"
10 #define MAX_NVECS 16
11 #define HASH_TABLE_SIZE 128
13 static time_t first_time, last_time; /* first and last timestamp to show */
14 static time_t ltime; /* the timestamp from the current log-line */
16 #define EVT_PROCESS (1 << 0)
17 #define EVT_NOTIFY (1 << 1)
18 #define EVT_ALERT (1 << 2)
19 #define EVT_COMMAND (1 << 3)
20 #define EVT_STATE (1 << 4)
21 #define EVT_FLAPPING (1 << 5)
22 #define EVT_DOWNTIME (1 << 6)
23 #define EVT_HOST (1 << 20)
24 #define EVT_SERVICE (1 << 21)
25 #define EVENT_MASK (EVT_PROCESS | EVT_NOTIFY | EVT_ALERT | EVT_COMMAND | \
26 EVT_STATE | EVT_FLAPPING | EVT_DOWNTIME)
28 static int event_filter = EVT_ALERT | EVT_STATE | EVT_FLAPPING | EVT_DOWNTIME | EVT_PROCESS;
29 static int host_state_filter = -1;
30 static int service_state_filter = -1;
31 static int statetype_filter = (1 << HARD_STATE) | (1 << SOFT_STATE);
33 #define add_event(string, eventcode) add_code(0, string, eventcode)
34 static struct string_code event_codes[] = {
35 add_event("Error", EVT_PROCESS),
36 add_event("Warning", EVT_PROCESS),
37 add_event("HOST NOTIFICATION", EVT_NOTIFY | EVT_SERVICE),
38 add_event("HOST FLAPPING ALERT", EVT_FLAPPING | EVT_HOST),
39 add_event("SERVICE NOTIFICATION", EVT_NOTIFY | EVT_SERVICE),
40 add_event("SERVICE FLAPPING ALERT", EVT_FLAPPING | EVT_SERVICE),
41 add_ignored("LOG ROTATION"),
42 add_ignored("SERVICE EVENT HANDLER"),
43 add_ignored("HOST EVENT HANDLER"),
44 add_ignored("LOG VERSION"),
45 add_ignored("EXTERNAL COMMAND"),
47 add_code(5, "HOST ALERT", EVT_ALERT | EVT_HOST),
48 add_code(5, "INITIAL HOST STATE", EVT_STATE | EVT_HOST),
49 add_code(5, "CURRENT HOST STATE", EVT_STATE | EVT_HOST),
50 add_code(6, "SERVICE ALERT", EVT_ALERT | EVT_SERVICE),
51 add_code(6, "INITIAL SERVICE STATE", EVT_STATE | EVT_SERVICE),
52 add_code(6, "CURRENT SERVICE STATE", EVT_STATE | EVT_SERVICE),
53 add_code(3, "HOST DOWNTIME ALERT", EVT_DOWNTIME | EVT_HOST),
54 add_code(4, "SERVICE DOWNTIME ALERT", EVT_DOWNTIME | EVT_SERVICE),
55 { 0, NULL, 0, 0 },
58 static void print_line(char *line, uint len)
60 struct tm *t;
61 uint i;
63 for (i = 0; i < len; i++) {
64 if (!line[i])
65 line[i] = ';';
68 t = gmtime(&ltime);
69 if (t->tm_isdst)
70 t->tm_hour++;
71 printf("[%d-%02d-%02d %02d:%02d:%02d] %s\n",
72 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
73 t->tm_hour, t->tm_min, t->tm_sec,
74 line);
77 static int parse_line(char *orig_line, uint len)
79 char *ptr, *colon, *line;
80 int nvecs = 0;
81 struct string_code *sc;
83 line_no++;
85 /* ignore empty lines */
86 if (!len)
87 return 0;
89 /* skip obviously bogus lines */
90 if (len < 12 || *orig_line != '[') {
91 warn("line %d; len too short, or line doesn't start with '[' (%s)",
92 line_no, orig_line);
93 return -1;
96 ltime = strtoul(orig_line + 1, &ptr, 10);
97 if (orig_line + 1 == ptr) {
98 crash("Failed to parse log timestamp from '%s'. I can't handle malformed logdata",
99 orig_line);
100 return -1;
103 /* only print lines in the interesting interval */
104 if ((first_time && ltime < first_time) || (last_time && ltime > last_time))
105 return 0;
107 while (*ptr == ']' || *ptr == ' ')
108 ptr++;
110 line = ptr;
111 len -= line - orig_line;
113 if (!is_interesting(ptr))
114 return 0;
116 if (!(colon = strchr(ptr, ':'))) {
117 /* stupid heuristic, but might be good for something,
118 * somewhere, sometime. if nothing else, it should suppress
119 * annoying output */
120 if (is_start_event(ptr) || is_stop_event(ptr)) {
121 if (event_filter & EVT_PROCESS)
122 print_line(line, len);
123 return 0;
126 handle_unknown_event(line);
127 return -1;
130 if (!(sc = get_event_type(ptr, colon - ptr))) {
131 handle_unknown_event(line);
132 return -1;
135 if (sc->code == IGNORE_LINE)
136 return 0;
137 if ((sc->code & event_filter) != sc->code)
138 return 0;
140 ptr = colon + 1;
141 while (*ptr == ' ')
142 ptr++;
144 if (sc->nvecs) {
145 int i;
147 nvecs = vectorize_string(ptr, sc->nvecs);
149 if (nvecs != sc->nvecs) {
150 /* broken line */
151 warn("Line %d in %s seems to not have all the fields it should",
152 line_no, cur_file->path);
153 return -1;
156 for (i = 0; i < sc->nvecs; i++) {
157 if (!strv[i]) {
158 /* this should never happen */
159 warn("Line %d in %s seems to be broken, or we failed to parse it into a vector",
160 line_no, cur_file->path);
161 return -1;
166 switch (sc->code) {
167 case EVT_ALERT | EVT_HOST:
168 case EVT_STATE | EVT_HOST:
169 if (!(statetype_filter & (1 << soft_hard(strv[2]))))
170 return 0;
171 if (!(host_state_filter & (1 << parse_host_state(strv[1]))))
172 return 0;
173 if (!is_interesting_host(strv[0]))
174 return 0;
175 print_line(line, len);
176 break;
178 case EVT_ALERT | EVT_SERVICE:
179 case EVT_STATE | EVT_SERVICE:
180 if (!(statetype_filter & (1 << soft_hard(strv[3]))))
181 return 0;
182 if (!(service_state_filter & (1 << parse_service_state(strv[2]))))
183 return 0;
184 if (!is_interesting_service(strv[0], strv[1]))
185 return 0;
187 print_line(line, len);
188 break;
190 case EVT_FLAPPING | EVT_HOST:
191 case EVT_DOWNTIME | EVT_HOST:
192 if (!is_interesting_host(strv[0]))
193 return 0;
194 print_line(line, len);
195 break;
197 case EVT_FLAPPING | EVT_SERVICE:
198 case EVT_DOWNTIME | EVT_SERVICE:
199 if (!is_interesting_service(strv[0], strv[1]))
200 return 0;
201 print_line(line, len);
202 break;
204 case IGNORE_LINE:
205 return 0;
208 return 0;
212 * hashes one line from an "interesting"-file. We use (void *)1
213 * to mark this as "present in hash-table" as we have no real
214 * data to lookup but still want hash_find{,2} to return non-NULL
215 * when it finds a match
217 static int hash_one_line(char *line, uint len)
219 return add_interesting_object(line);
222 static int hash_interesting(const char *path)
224 struct stat st;
226 if (stat(path, &st) < 0)
227 crash("failed to stat %s: %s", path, strerror(errno));
229 lparse_path(path, st.st_size, hash_one_line);
231 return 0;
234 static void parse_host_state_filter(char *p)
236 host_state_filter = 0;
237 for (; *p; p++) {
238 switch (*p) {
239 case 'a': case '*':
240 host_state_filter = -1;
241 break;
242 case 'u':
243 host_state_filter |= 1 << HOST_UNREACHABLE;
244 break;
245 case 'd':
246 host_state_filter |= 1 << HOST_DOWN;
247 break;
248 case 'r':
249 host_state_filter |= 1 << HOST_UP;
250 break;
255 static void parse_service_state_filter(char *p)
257 service_state_filter = 0;
258 for (; *p; p++) {
259 switch (*p) {
260 case 'a': case '*':
261 service_state_filter = -1;
262 break;
263 case 'r':
264 service_state_filter |= 1 << SERVICE_OK;
265 break;
266 case 'w':
267 service_state_filter |= 1 << SERVICE_WARNING;
268 break;
269 case 'c':
270 service_state_filter |= 1 << SERVICE_CRITICAL;
271 break;
272 case 'u':
273 service_state_filter |= 1 << SERVICE_UNKNOWN;
278 extern const char *__progname;
279 int main(int argc, char **argv)
281 int i, reverse = 0;
282 struct naglog_file *nfile;
284 strv = calloc(sizeof(char *), MAX_NVECS);
285 nfile = calloc(sizeof(*nfile), argc - 1);
286 if (!strv || !nfile)
287 crash("Failed to alloc initial structs");
289 for (num_nfile = 0,i = 1; i < argc; i++) {
290 char *opt, *arg = argv[i];
291 struct naglog_file *nf;
292 int eq_opt = 0;
294 if ((opt = strchr(arg, '='))) {
295 *opt++ = '\0';
296 eq_opt = 1;
298 else if (i < argc - 1) {
299 opt = argv[i + 1];
302 if (!strcmp(arg, "--reverse")) {
303 reverse = 1;
304 continue;
306 if (!strcmp(arg, "--debug") || !strcmp(arg, "-d")) {
307 debug_level++;
308 continue;
310 if (!prefixcmp(arg, "--hide-flapping")) {
311 event_filter &= ~EVT_FLAPPING;
312 continue;
314 if (!prefixcmp(arg, "--hide-downtime")) {
315 event_filter &= ~EVT_DOWNTIME;
317 if (!prefixcmp(arg, "--hide-process")) {
318 event_filter &= ~EVT_PROCESS;
319 continue;
322 if (!prefixcmp(arg, "--")) {
323 if (!opt)
324 crash("Option '%s' requires an argument\n", arg);
325 if (!eq_opt)
326 i++;
329 /* options parsed below require arguments */
330 if (!strcmp(arg, "--host")) {
331 event_filter |= EVT_HOST;
332 add_interesting_object(opt);
333 continue;
335 if (!strcmp(arg, "--service")) {
336 event_filter |= EVT_SERVICE;
337 add_interesting_object(opt);
338 continue;
340 if (!strcmp(arg, "--interesting") || !strcmp(arg, "-i")) {
341 if (!opt || !*opt)
342 crash("%s requires a filename as argument", arg);
343 hash_interesting(opt);
344 continue;
346 if (!strcmp(arg, "--first") || !strcmp(arg, "--last")) {
347 time_t when;
349 if (!opt || !*opt)
350 crash("%s requires a timestamp as argument", arg);
351 when = strtoul(opt, NULL, 0);
352 if (opt && !eq_opt)
353 i++;
354 if (!strcmp(arg, "--first"))
355 first_time = when;
356 else
357 last_time = when;
358 continue;
360 if (!strcmp(arg, "--state-type")) {
361 if (!strcasecmp(opt, "hard"))
362 statetype_filter = (1 << HARD_STATE);
363 if (!strcasecmp(opt, "soft"))
364 statetype_filter = (1 << SOFT_STATE);
365 continue;
367 if (!strcmp(arg, "--host-states")) {
368 event_filter |= EVT_HOST;
369 parse_host_state_filter(opt);
370 continue;
372 if (!strcmp(arg, "--service-states")) {
373 event_filter |= EVT_SERVICE;
374 parse_service_state_filter(opt);
375 continue;
378 /* non-argument, so treat as file */
379 nf = &nfile[num_nfile++];
380 nf->path = arg;
381 first_log_time(nf);
384 if (debug_level)
385 print_interesting_objects();
387 if (!num_nfile)
388 crash("Usage: %s [--interesting <file>] logfiles\n",
389 __progname);
391 if (reverse)
392 qsort(nfile, num_nfile, sizeof(*nfile), nfile_rev_cmp);
393 else
394 qsort(nfile, num_nfile, sizeof(*nfile), nfile_cmp);
396 for (i = 0; i < num_nfile; i++) {
397 struct naglog_file *nf = &nfile[i];
398 if (last_time && nf->first > last_time) {
399 debug("ignoring %s\n", nf->path);
400 continue;
402 if (first_time && i < num_nfile - 1 && nfile[i + 1].first < first_time) {
403 debug("ignoring %s\n", nf->path);
404 continue;
407 cur_file = nf;
408 debug("importing from %s (%lu : %u)\n", nf->path, nf->first, nf->cmp);
409 line_no = 0;
410 lparse_path_real(reverse, nf->path, nf->size, parse_line);
413 if (warnings && debug_level)
414 fprintf(stderr, "Total warnings: %d\n", warnings);
416 print_unhandled_events();
418 return 0;