6 struct naglog_file
*cur_file
; /* the file we're currently importing */
8 uint num_unhandled
= 0;
10 static hash_table
*interesting_hosts
, *interesting_services
;
13 int parse_service_state(const char *str
)
15 if (!strcmp(str
, "OK"))
17 if (!strcmp(str
, "WARNING"))
18 return SERVICE_WARNING
;
19 if (!strcmp(str
, "UNKNOWN"))
20 return SERVICE_UNKNOWN
;
21 if (!strcmp(str
, "CRITICAL"))
22 return SERVICE_CRITICAL
;
24 crash("bad value for service state: '%s'", str
);
27 int parse_host_state(const char *str
)
29 if (!strcmp(str
, "UP"))
31 if (!strcmp(str
, "DOWN"))
33 if (!strcmp(str
, "UNREACHABLE"))
34 return HOST_UNREACHABLE
;
36 crash("bad value for host state: '%s'", str
);
39 int soft_hard(const char *str
)
41 if (!strcmp(str
, "HARD"))
44 if (!strcmp(str
, "SOFT"))
46 crash("wtf kind of value is '%s' to determine 'soft' or 'hard' from?", str
);
49 static int print_string(void *data
)
51 const char *str
= data
;
53 printf("%p: %s\n", str
, str
);
58 * prints the objects we consider interesting
60 void print_interesting_objects(void)
62 if (interesting_hosts
) {
63 printf("\nInteresting hosts:\n");
64 hash_walk_data(interesting_hosts
, print_string
);
66 if (interesting_services
) {
67 printf("\nInteresting services:\n");
68 hash_walk_data(interesting_services
, print_string
);
70 if (interesting_hosts
|| interesting_services
)
74 /* marks one object as 'interesting' */
75 int add_interesting_object(const char *orig_str
)
77 char *semi_colon
, *str
;
79 str
= strdup(orig_str
);
80 semi_colon
= strchr(str
, ';');
82 if (!interesting_hosts
)
83 interesting_hosts
= hash_init(512);
84 if (!interesting_hosts
)
85 crash("Failed to initialize hash table for interesting hosts");
86 hash_add(interesting_hosts
, str
, strdup(orig_str
));
88 if (!interesting_services
)
89 interesting_services
= hash_init(512);
90 if (!interesting_services
)
91 crash("Failed to initialize hash table for interesting services");
93 hash_add2(interesting_services
, str
, semi_colon
, strdup(orig_str
));
99 int is_interesting_host(const char *host
)
101 if (interesting_hosts
)
102 return !!hash_find(interesting_hosts
, host
);
107 int is_interesting_service(const char *host
, const char *service
)
109 /* fall back to checking if host is interesting */
110 if (!service
|| !interesting_services
)
111 return is_interesting_host(host
);
113 return !!hash_find2(interesting_services
, host
, service
);
116 struct unhandled_event
{
120 struct unhandled_event
*next
;
123 static struct unhandled_event
*event_list
;
125 * This is a fairly toothless function, since we can encounter
126 * pretty much any kind of message in the logfiles. In order to
127 * make sure we don't miss anything important though, we stash
128 * the messages and print them at the end if we're debugging.
130 void handle_unknown_event(const char *line
)
132 struct unhandled_event
*event
;
136 if (!(event
= malloc(sizeof(*event
))) || !(event
->line
= strdup(line
))) {
137 crash("Failed to allocate memory for unhandled event [%s]\n", line
);
141 event
->line_no
= line_no
;
142 event
->file
= cur_file
->path
;
144 /* add to "top" of list. we'll print in reverse order */
145 event
->next
= event_list
;
149 void print_unhandled_events(void)
151 struct unhandled_event
*event
;
157 printf("\n%u Unhandled events encountered:\n" \
158 "------------------------------", num_unhandled
);
160 for (x
= 1; num_unhandled
> (x
* 10); x
*= 10)
164 for (event
= event_list
; event
; event
= event
->next
) {
165 printf("%s:%d:\n%s\n----\n", event
->file
, event
->line_no
, event
->line
);
169 int vectorize_string(char *str
, int nvecs
)
175 for (p
= str
; *p
&& i
< nvecs
; p
++) {
186 get_string_code(struct string_code
*codes
, const char *str
, uint len
)
190 for (i
= 0; codes
[i
].str
; i
++)
191 if (codes
[i
].len
== len
&& !memcmp(str
, codes
[i
].str
, len
))
197 int is_interesting(const char *ptr
)
199 if (!prefixcmp(ptr
, "Auto-save of retention data"))
201 if (!prefixcmp(ptr
, "Event broker module"))
203 if (!prefixcmp(ptr
, "You do not have permission"))
205 if (!prefixcmp(ptr
, "Local time is"))
211 int is_start_event(const char *ptr
)
213 if (!prefixcmp(ptr
, "Finished daemonizing..."))
215 if (!prefixcmp(ptr
, "Caught SIGHUP"))
217 if (strstr(ptr
, "starting..."))
223 int is_stop_event(const char *ptr
)
225 if (!prefixcmp(ptr
, "PROGRAM_RESTART"))
227 if (!prefixcmp(ptr
, "Caught SIGTERM"))
229 if (!prefixcmp(ptr
, "Successfully shutdown..."))
231 if (!prefixcmp(ptr
, "Bailing out"))
233 if (!prefixcmp(ptr
, "Lockfile"))
235 if (strstr(ptr
, "shutting down..."))
241 int strtotimet(const char *str
, time_t *val
)
245 *val
= strtoul(str
, &endp
, 10);
247 warn("strtotimet(): %s is not a valid time_t\n", str
);
254 /*** general utility functions ***/
255 void __attribute__((__noreturn__
)) crash(const char *fmt
, ...)
260 vfprintf(stderr
, fmt
, ap
);
265 fprintf(stderr
, "crash() called when parsing line %u in %s\n",
266 line_no
, cur_file
->path
);
272 void pdebug(int lvl
, const char *fmt
, ...)
276 if (debug_level
< lvl
)
282 if (fmt
[strlen(fmt
) - 1] != '\n')
286 void warn(const char *fmt
, ...)
305 * Returns an increasing numeric value for a nagios logfile
306 * For a file with a name such as:
307 * nagios-12-01-2002-00.log
312 uint
path_cmp_number(char *path
)
317 unsigned long part
[NUM_PARTS
];
319 dash
= strrchr(path
, '/');
326 * we special-case nagios.log as always being the
327 * last file to be parsed. It has to be, since it's
328 * the currently active logfile
330 if (!strcmp(dash
, "nagios.log"))
331 return 1 << ((8 * sizeof(ret
)) - 1);
334 if (len
< 18 || strcmp(&dash
[len
- 4], ".log"))
337 for (i
= 0; i
< NUM_PARTS
; i
++) {
340 dash
= strchr(dash
, '-');
342 crash("dash is not");
345 part
[i
] = strtoul(dash
, &endp
, 10);
346 if (!part
[i
] && dash
== endp
)
352 if (part
[0] < 1 || part
[0] > 12)
354 if (part
[1] < 1 || part
[1] > 31)
358 ret
= part
[2] * 1000000;
359 ret
+= part
[0] * 10000;
360 ret
+= part
[1] * 100;
366 #define min(a, b) ((a) < (b) ? (a) : (b))
367 void first_log_time(struct naglog_file
*nf
)
373 if (!(fd
= open(nf
->path
, O_RDONLY
)))
374 crash("Failed to open %s: %s", nf
->path
, strerror(errno
));
377 * since we're looking at every file in here anyway,
378 * we also determine the size of them so we can do an
379 * arena allocation large enough to fit the largest
380 * file + an added newline later
382 if (fstat(fd
, &st
) < 0)
383 crash("Failed to stat %s: %s", nf
->path
, strerror(errno
));
385 nf
->size
= st
.st_size
;
387 if (read(fd
, buf
, sizeof(buf
)) < min(sizeof(buf
), st
.st_size
))
388 crash("Incomplete read of %s", nf
->path
);
390 buf
[sizeof(buf
) - 1] = 0;
391 /* skip empty lines at top of file */
392 while (i
< sizeof(buf
) - 12 && (buf
[i
] == '\n' || buf
[i
] == '\r'))
395 if (strtotimet(buf
+ i
+ 1, &nf
->first
))
396 crash("'%s' has no timestamp for us to parse", buf
);
398 nf
->cmp
= path_cmp_number(nf
->path
);
402 static void filesort_mismatch(const struct naglog_file
*a
, const struct naglog_file
*b
)
404 printf("filesort mismatch:\n");
405 printf(" %s:\n cmp: %d\n first: %lu\n", a
->path
, a
->cmp
, a
->first
);
406 printf(" %s:\n cmp: %d\n first: %lu\n", b
->path
, b
->cmp
, b
->first
);
407 crash("%s and %s have same 'first' and 'cmp'? Bizarre...", a
->path
, b
->path
);
411 * sort function for nagios logfiles. Sorts based on
412 * first logged timestamp and then on filename, ascendingly
414 int nfile_cmp(const void *p1
, const void *p2
)
416 const struct naglog_file
*a
= p1
;
417 const struct naglog_file
*b
= p2
;
419 if (a
->first
> b
->first
)
421 if (b
->first
> a
->first
)
429 filesort_mismatch(a
, b
);
433 /* same as above, but sorts in reverse order */
434 int nfile_rev_cmp(const void *p1
, const void *p2
)
436 const struct naglog_file
*a
= p1
;
437 const struct naglog_file
*b
= p2
;
439 if (a
->first
< b
->first
)
441 if (b
->first
< a
->first
)
449 filesort_mismatch(a
, b
);