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
),
58 static void print_line(char *line
, uint len
)
63 for (i
= 0; i
< len
; i
++) {
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
,
77 static int parse_line(char *orig_line
, uint len
)
79 char *ptr
, *colon
, *line
;
81 struct string_code
*sc
;
85 /* ignore empty lines */
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)",
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",
103 /* only print lines in the interesting interval */
104 if ((first_time
&& ltime
< first_time
) || (last_time
&& ltime
> last_time
))
107 while (*ptr
== ']' || *ptr
== ' ')
111 len
-= line
- orig_line
;
113 if (!is_interesting(ptr
))
116 if (!(colon
= strchr(ptr
, ':'))) {
117 /* stupid heuristic, but might be good for something,
118 * somewhere, sometime. if nothing else, it should suppress
120 if (is_start_event(ptr
) || is_stop_event(ptr
)) {
121 if (event_filter
& EVT_PROCESS
)
122 print_line(line
, len
);
126 handle_unknown_event(line
);
130 if (!(sc
= get_event_type(ptr
, colon
- ptr
))) {
131 handle_unknown_event(line
);
135 if (sc
->code
== IGNORE_LINE
)
137 if ((sc
->code
& event_filter
) != sc
->code
)
147 nvecs
= vectorize_string(ptr
, sc
->nvecs
);
149 if (nvecs
!= sc
->nvecs
) {
151 warn("Line %d in %s seems to not have all the fields it should",
152 line_no
, cur_file
->path
);
156 for (i
= 0; i
< sc
->nvecs
; 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
);
167 case EVT_ALERT
| EVT_HOST
:
168 case EVT_STATE
| EVT_HOST
:
169 if (!(statetype_filter
& (1 << soft_hard(strv
[2]))))
171 if (!(host_state_filter
& (1 << parse_host_state(strv
[1]))))
173 if (!is_interesting_host(strv
[0]))
175 print_line(line
, len
);
178 case EVT_ALERT
| EVT_SERVICE
:
179 case EVT_STATE
| EVT_SERVICE
:
180 if (!(statetype_filter
& (1 << soft_hard(strv
[3]))))
182 if (!(service_state_filter
& (1 << parse_service_state(strv
[2]))))
184 if (!is_interesting_service(strv
[0], strv
[1]))
187 print_line(line
, len
);
190 case EVT_FLAPPING
| EVT_HOST
:
191 case EVT_DOWNTIME
| EVT_HOST
:
192 if (!is_interesting_host(strv
[0]))
194 print_line(line
, len
);
197 case EVT_FLAPPING
| EVT_SERVICE
:
198 case EVT_DOWNTIME
| EVT_SERVICE
:
199 if (!is_interesting_service(strv
[0], strv
[1]))
201 print_line(line
, len
);
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
)
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
);
234 static void parse_host_state_filter(char *p
)
236 host_state_filter
= 0;
240 host_state_filter
= -1;
243 host_state_filter
|= 1 << HOST_UNREACHABLE
;
246 host_state_filter
|= 1 << HOST_DOWN
;
249 host_state_filter
|= 1 << HOST_UP
;
255 static void parse_service_state_filter(char *p
)
257 service_state_filter
= 0;
261 service_state_filter
= -1;
264 service_state_filter
|= 1 << SERVICE_OK
;
267 service_state_filter
|= 1 << SERVICE_WARNING
;
270 service_state_filter
|= 1 << SERVICE_CRITICAL
;
273 service_state_filter
|= 1 << SERVICE_UNKNOWN
;
278 extern const char *__progname
;
279 int main(int argc
, char **argv
)
282 struct naglog_file
*nfile
;
284 strv
= calloc(sizeof(char *), MAX_NVECS
);
285 nfile
= calloc(sizeof(*nfile
), argc
- 1);
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
;
294 if ((opt
= strchr(arg
, '='))) {
298 else if (i
< argc
- 1) {
302 if (!strcmp(arg
, "--reverse")) {
306 if (!strcmp(arg
, "--debug") || !strcmp(arg
, "-d")) {
310 if (!prefixcmp(arg
, "--hide-flapping")) {
311 event_filter
&= ~EVT_FLAPPING
;
314 if (!prefixcmp(arg
, "--hide-downtime")) {
315 event_filter
&= ~EVT_DOWNTIME
;
317 if (!prefixcmp(arg
, "--hide-process")) {
318 event_filter
&= ~EVT_PROCESS
;
322 if (!prefixcmp(arg
, "--")) {
324 crash("Option '%s' requires an argument\n", arg
);
329 /* options parsed below require arguments */
330 if (!strcmp(arg
, "--host")) {
331 event_filter
|= EVT_HOST
;
332 add_interesting_object(opt
);
335 if (!strcmp(arg
, "--service")) {
336 event_filter
|= EVT_SERVICE
;
337 add_interesting_object(opt
);
340 if (!strcmp(arg
, "--interesting") || !strcmp(arg
, "-i")) {
342 crash("%s requires a filename as argument", arg
);
343 hash_interesting(opt
);
346 if (!strcmp(arg
, "--first") || !strcmp(arg
, "--last")) {
350 crash("%s requires a timestamp as argument", arg
);
351 when
= strtoul(opt
, NULL
, 0);
354 if (!strcmp(arg
, "--first"))
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
);
367 if (!strcmp(arg
, "--host-states")) {
368 event_filter
|= EVT_HOST
;
369 parse_host_state_filter(opt
);
372 if (!strcmp(arg
, "--service-states")) {
373 event_filter
|= EVT_SERVICE
;
374 parse_service_state_filter(opt
);
378 /* non-argument, so treat as file */
379 nf
= &nfile
[num_nfile
++];
385 print_interesting_objects();
388 crash("Usage: %s [--interesting <file>] logfiles\n",
392 qsort(nfile
, num_nfile
, sizeof(*nfile
), nfile_rev_cmp
);
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
);
402 if (first_time
&& i
< num_nfile
- 1 && nfile
[i
+ 1].first
< first_time
) {
403 debug("ignoring %s\n", nf
->path
);
408 debug("importing from %s (%lu : %u)\n", nf
->path
, nf
->first
, nf
->cmp
);
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();