11 #define HASH_TABLE_SIZE 128
13 static int ignore_process_events
;
15 static time_t first_time
, last_time
; /* first and last timestamp to show */
16 static time_t ltime
; /* the timestamp from the current log-line */
18 static inline void print_strvec(char **v
, int n
)
22 for (i
= 0; i
< n
; i
++)
23 printf("v[%2d]: %s\n", i
, v
[i
]);
26 static hash_table
*interesting_hosts
, *interesting_services
;
27 static int host_is_interesting(const char *host
)
29 if (interesting_hosts
)
30 return !!hash_find(interesting_hosts
, host
);
35 static int service_is_interesting(const char *host
, const char *service
)
37 /* fall back to just checking if host is interesting */
38 if (!service
|| !interesting_services
)
39 return host_is_interesting(host
);
41 return !!hash_find2(interesting_services
, host
, service
);
44 static int parse_line(char *line
, uint len
)
48 struct string_code
*sc
;
49 static time_t last_ltime
= 0;
53 /* ignore empty lines. whitespace is trimmed in the cfg_* api */
57 /* skip obviously bogus lines */
58 if (len
< 12 || *line
!= '[') {
59 warn("line %d; len too short, or line doesn't start with '[' (%s)", line_no
, line
);
63 ltime
= strtoul(line
+ 1, &ptr
, 10);
64 if (line
+ 1 == ptr
) {
65 crash("Failed to parse log timestamp from '%s'. I can't handle malformed logdata", line
);
69 /* only print lines in the interesting interval */
70 if ((first_time
&& ltime
< first_time
) || (last_time
&& ltime
> last_time
))
73 /* more heuristics should go below, but we remain lazy for now */
77 if (ltime
< last_ltime
) {
83 while (*ptr
== ']' || *ptr
== ' ')
86 if (!is_interesting(ptr
))
89 if (!(colon
= strchr(ptr
, ':'))) {
90 /* stupid heuristic, but might be good for something,
91 * somewhere, sometime. if nothing else, it should suppress
93 if (is_start_event(ptr
) || is_stop_event(ptr
))
96 handle_unknown_event(line
);
100 if (!(sc
= get_event_type(ptr
, colon
- ptr
))) {
101 handle_unknown_event(line
);
105 if (sc
->code
== IGNORE_LINE
)
116 nvecs
= vectorize_string(ptr
, sc
->nvecs
);
118 if (nvecs
!= sc
->nvecs
) {
120 warn("Line %d in %s seems to not have all the fields it should",
121 line_no
, cur_file
->path
);
125 for (i
= 0; i
< sc
->nvecs
; i
++) {
127 /* this should never happen */
128 warn("Line %d in %s seems to be broken, or we failed to parse it into a vector",
129 line_no
, cur_file
->path
);
138 case NEBTYPE_EXTERNALCOMMAND_END
:
139 semi_colon
= strchr(ptr
, ';');
142 if (!(sc
= get_command_type(ptr
, semi_colon
- ptr
))) {
146 nvecs
= vectorize_string(semi_colon
+ 1, sc
->nvecs
);
147 if (nvecs
!= sc
->nvecs
) {
148 warn("nvecs discrepancy: %d vs %d (%s)\n", nvecs
, sc
->nvecs
, ptr
);
152 case NEBTYPE_HOSTCHECK_PROCESSED
:
153 case NEBTYPE_SERVICECHECK_PROCESSED
:
156 case NEBTYPE_DOWNTIME_LOAD
+ CONCERNS_HOST
:
157 case NEBTYPE_DOWNTIME_LOAD
+ CONCERNS_SERVICE
:
168 * hashes one line from an "interesting"-file. We use (void *)1
169 * to mark this as "present in hash-table" as we have no real
170 * data to lookup but still want hash_find{,2} to return non-NULL
171 * when it finds a match
173 static int hash_one_line(char *line
, uint len
)
177 p
= strchr(line
, ';');
180 if (!interesting_services
)
181 interesting_services
= hash_init(16384);
182 hash_add2(interesting_services
, line
, p
, (void *)1);
185 if (!interesting_hosts
)
186 interesting_hosts
= hash_init(16384);
188 hash_add(interesting_hosts
, line
, (void *)1);
194 static int hash_interesting(const char *path
)
198 if (stat(path
, &st
) < 0)
199 crash("failed to stat %s: %s", path
, strerror(errno
));
201 lparse_path(path
, st
.st_size
, hash_one_line
);
206 extern const char *__progname
;
207 int main(int argc
, char **argv
)
210 struct naglog_file
*nfile
;
212 strv
= calloc(sizeof(char *), MAX_NVECS
);
213 nfile
= calloc(sizeof(*nfile
), argc
- 1);
215 crash("Failed to alloc initial structs");
218 for (num_nfile
= 0,i
= 1; i
< argc
; i
++) {
219 char *opt
, *arg
= argv
[i
];
220 struct naglog_file
*nf
;
223 if ((opt
= strchr(arg
, '='))) {
227 else if (i
< argc
- 1) {
231 if (!prefixcmp(arg
, "--ignore-process-events")) {
232 ignore_process_events
= 1;
235 if (!prefixcmp(arg
, "--debug") || !prefixcmp(arg
, "-d")) {
239 if (!prefixcmp(arg
, "--service")) {
242 if (!prefixcmp(arg
, "--host")) {
245 if (!prefixcmp(arg
, "--interesting") || !prefixcmp(arg
, "-i")) {
247 crash("%s requires a filename as argument", arg
);
248 hash_interesting(opt
);
253 if (!prefixcmp(arg
, "--first") || !prefixcmp(arg
, "--last")) {
257 crash("%s requires a timestamp as argument", arg
);
258 when
= strtoul(opt
, NULL
, 0);
261 if (!prefixcmp(arg
, "--first"))
268 /* non-argument, so treat as file */
269 nf
= &nfile
[num_nfile
++];
275 crash("Usage: %s [--ignore-process-events] [--interesting <file>] logfiles\n",
278 qsort(nfile
, num_nfile
, sizeof(*nfile
), nfile_cmp
);
280 for (i
= 0; i
< num_nfile
; i
++) {
281 struct naglog_file
*nf
= &nfile
[i
];
282 if (last_time
&& nf
->first
> last_time
) {
283 debug("ignoring %s\n", nf
->path
);
286 if (first_time
&& i
< num_nfile
- 1 && nfile
[i
+ 1].first
< first_time
) {
287 debug("ignoring %s\n", nf
->path
);
292 debug("importing from %s (%lu : %u)\n", nf
->path
, nf
->first
, nf
->cmp
);
294 lparse_path(nf
->path
, nf
->size
, parse_line
);
297 if (warnings
&& debug_level
)
298 fprintf(stderr
, "Total warnings: %d\n", warnings
);
300 print_unhandled_events();