Skip to content

Commit 4e8e9c2

Browse files
committed
lightningd: add support for per-logfile filters.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent e0c1c8e commit 4e8e9c2

File tree

1 file changed

+99
-39
lines changed

1 file changed

+99
-39
lines changed

lightningd/log.c

Lines changed: 99 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,18 @@
2323
struct logger *crashlog;
2424

2525
struct print_filter {
26+
/* In list log_book->print_filters / log_file->print_filters */
2627
struct list_node list;
2728

2829
const char *prefix;
2930
enum log_level level;
3031
};
3132

33+
struct log_file {
34+
struct list_head print_filters;
35+
FILE *f;
36+
};
37+
3238
struct log_book {
3339
size_t mem_used;
3440
size_t max_mem;
@@ -43,7 +49,7 @@ struct log_book {
4349
struct list_head loggers;
4450

4551
/* Array of log files: one per ld->logfiles[] */
46-
FILE **outfiles;
52+
struct log_file **log_files;
4753
bool print_timestamps;
4854

4955
struct log_entry *log;
@@ -131,6 +137,23 @@ static const char *level_prefix(enum log_level level)
131137
abort();
132138
}
133139

140+
/* What do these filters say about level to log this entry at? */
141+
static bool filter_level(const struct list_head *print_filters,
142+
const char *prefix,
143+
const char *node_id_str,
144+
enum log_level *level)
145+
{
146+
struct print_filter *i;
147+
148+
list_for_each(print_filters, i, list) {
149+
if (strstr(prefix, i->prefix) || strstr(node_id_str, i->prefix)) {
150+
*level = i->level;
151+
return true;
152+
}
153+
}
154+
return false;
155+
}
156+
134157
static void log_to_files(const char *log_prefix,
135158
const char *entry_prefix,
136159
enum log_level level,
@@ -140,10 +163,11 @@ static void log_to_files(const char *log_prefix,
140163
const u8 *io,
141164
size_t io_len,
142165
bool print_timestamps,
143-
FILE **outfiles)
166+
const enum log_level *default_print_level,
167+
struct log_file **log_files)
144168
{
145169
char tstamp[sizeof("YYYY-mm-ddTHH:MM:SS.nnnZ ")];
146-
char *entry;
170+
char *entry, *nodestr;
147171

148172
if (print_timestamps) {
149173
char iso8601_msec_fmt[sizeof("YYYY-mm-ddTHH:MM:SS.%03dZ ")];
@@ -152,6 +176,10 @@ static void log_to_files(const char *log_prefix,
152176
} else
153177
tstamp[0] = '\0';
154178

179+
if (node_id)
180+
nodestr = node_id_to_hexstr(tmpctx, node_id);
181+
else
182+
nodestr = "";
155183
if (level == LOG_IO_IN || level == LOG_IO_OUT) {
156184
const char *dir = level == LOG_IO_IN ? "[IN]" : "[OUT]";
157185
char *hex = tal_hexstr(NULL, io, io_len);
@@ -161,7 +189,7 @@ static void log_to_files(const char *log_prefix,
161189
else
162190
entry = tal_fmt(tmpctx, "%s%s%s-%s: %s%s %s\n",
163191
log_prefix, tstamp,
164-
node_id_to_hexstr(tmpctx, node_id),
192+
nodestr,
165193
entry_prefix, str, dir, hex);
166194
tal_free(hex);
167195
} else {
@@ -171,18 +199,31 @@ static void log_to_files(const char *log_prefix,
171199
else
172200
entry = tal_fmt(tmpctx, "%s%s%s %s-%s: %s\n",
173201
log_prefix, tstamp, level_prefix(level),
174-
node_id_to_hexstr(tmpctx, node_id),
202+
nodestr,
175203
entry_prefix, str);
176204
}
177205

178206
/* Default if nothing set is stdout */
179-
if (!outfiles) {
207+
if (!log_files) {
180208
fwrite(entry, strlen(entry), 1, stdout);
181209
fflush(stdout);
182210
}
183-
for (size_t i = 0; i < tal_count(outfiles); i++) {
184-
fwrite(entry, strlen(entry), 1, outfiles[i]);
185-
fflush(outfiles[i]);
211+
212+
/* We may have to apply per-file filters. */
213+
for (size_t i = 0; i < tal_count(log_files); i++) {
214+
enum log_level filter;
215+
if (!filter_level(&log_files[i]->print_filters,
216+
entry_prefix, nodestr, &filter)) {
217+
/* If we haven't set default yet, only log UNUSUAL */
218+
if (default_print_level)
219+
filter = *default_print_level;
220+
else
221+
filter = LOG_UNUSUAL;
222+
}
223+
if (level < filter)
224+
continue;
225+
fwrite(entry, strlen(entry), 1, log_files[i]->f);
226+
fflush(log_files[i]->f);
186227
}
187228
}
188229

@@ -278,7 +319,7 @@ struct log_book *new_log_book(struct lightningd *ld, size_t max_mem)
278319
log_book->mem_used = 0;
279320
log_book->num_entries = 0;
280321
log_book->max_mem = max_mem;
281-
log_book->outfiles = NULL;
322+
log_book->log_files = NULL;
282323
log_book->default_print_level = NULL;
283324
/* We have to allocate this, since we tal_free it on resetting */
284325
log_book->prefix = tal_strdup(log_book, "");
@@ -295,19 +336,33 @@ struct log_book *new_log_book(struct lightningd *ld, size_t max_mem)
295336
return log_book;
296337
}
297338

298-
static enum log_level filter_level(struct log_book *log_book,
299-
const struct log_prefix *lp,
300-
const struct node_id *node_id)
339+
/* What's the minimum level to print for this log book? */
340+
static enum log_level print_level(struct log_book *log_book,
341+
const struct log_prefix *lp,
342+
const struct node_id *node_id)
301343
{
302-
struct print_filter *i;
344+
enum log_level level;
303345
const char *node_id_str = node_id ? node_id_to_hexstr(tmpctx, node_id) : "";
304346

305347
assert(log_book->default_print_level != NULL);
306-
list_for_each(&log_book->print_filters, i, list) {
307-
if (strstr(lp->prefix, i->prefix) || strstr(node_id_str, i->prefix))
308-
return i->level;
348+
if (!filter_level(&log_book->print_filters, lp->prefix,
349+
node_id_str, &level)) {
350+
level = *log_book->default_print_level;
309351
}
310-
return *log_book->default_print_level;
352+
353+
/* We need to look into per-file filters as well: might give a
354+
* lower filter! */
355+
for (size_t i = 0; i < tal_count(log_book->log_files); i++) {
356+
enum log_level sublevel;
357+
if (filter_level(&log_book->log_files[i]->print_filters,
358+
lp->prefix, node_id_str, &sublevel)) {
359+
if (sublevel < level) {
360+
level = sublevel;
361+
}
362+
}
363+
}
364+
365+
return level;
311366
}
312367

313368
static void destroy_logger(struct logger *log)
@@ -337,7 +392,7 @@ new_logger(const tal_t *ctx, struct log_book *log_book,
337392
if (!log->log_book->default_print_level)
338393
log->print_level = LOG_UNUSUAL;
339394
else
340-
log->print_level = filter_level(log->log_book, log->prefix, default_node_id);
395+
log->print_level = print_level(log->log_book, log->prefix, default_node_id);
341396
list_add(&log->log_book->loggers, &log->list);
342397
tal_add_destructor(log, destroy_logger);
343398
return log;
@@ -350,7 +405,7 @@ const char *log_prefix(const struct logger *log)
350405

351406
bool log_has_io_logging(const struct logger *log)
352407
{
353-
return filter_level(log->log_book, log->prefix, log->default_node_id) < LOG_DBG;
408+
return print_level(log->log_book, log->prefix, log->default_node_id) < LOG_DBG;
354409
}
355410

356411
/* This may move entry! */
@@ -415,7 +470,8 @@ static void maybe_print(struct logger *log, const struct log_entry *l)
415470
&l->time, l->log,
416471
l->io, tal_bytelen(l->io),
417472
log->log_book->print_timestamps,
418-
log->log_book->outfiles);
473+
log->log_book->default_print_level,
474+
log->log_book->log_files);
419475
}
420476

421477
void logv(struct logger *log, enum log_level level,
@@ -465,7 +521,8 @@ void log_io(struct logger *log, enum log_level dir,
465521
&l->time, str,
466522
data, len,
467523
log->log_book->print_timestamps,
468-
log->log_book->outfiles);
524+
log->log_book->default_print_level,
525+
log->log_book->log_files);
469526

470527
/* Save a tal header, by using raw malloc. */
471528
l->log = strdup(str);
@@ -656,12 +713,12 @@ static struct io_plan *setup_read(struct io_conn *conn, struct lightningd *ld);
656713
static struct io_plan *rotate_log(struct io_conn *conn, struct lightningd *ld)
657714
{
658715
log_info(ld->log, "Ending log due to SIGHUP");
659-
for (size_t i = 0; i < tal_count(ld->log->log_book->outfiles); i++) {
716+
for (size_t i = 0; i < tal_count(ld->log->log_book->log_files); i++) {
660717
if (streq(ld->logfiles[i], "-"))
661718
continue;
662-
fclose(ld->log->log_book->outfiles[i]);
663-
ld->log->log_book->outfiles[i] = fopen(ld->logfiles[i], "a");
664-
if (!ld->log->log_book->outfiles[i])
719+
fclose(ld->log->log_book->log_files[i]->f);
720+
ld->log->log_book->log_files[i]->f = fopen(ld->logfiles[i], "a");
721+
if (!ld->log->log_book->log_files[i]->f)
665722
err(1, "failed to reopen log file %s", ld->logfiles[i]);
666723
}
667724

@@ -712,29 +769,31 @@ static void setup_log_rotation(struct lightningd *ld)
712769
char *arg_log_to_file(const char *arg, struct lightningd *ld)
713770
{
714771
int size;
715-
FILE *outf;
772+
struct log_file *logf;
716773

717774
if (!ld->logfiles) {
718775
setup_log_rotation(ld);
719776
ld->logfiles = tal_arr(ld, const char *, 0);
720-
ld->log->log_book->outfiles = tal_arr(ld->log->log_book, FILE *, 0);
777+
ld->log_book->log_files = tal_arr(ld->log_book, struct log_file *, 0);
721778
}
722779

780+
logf = tal(ld->log_book->log_files, struct log_file);
781+
list_head_init(&logf->print_filters);
723782
if (streq(arg, "-"))
724-
outf = stdout;
783+
logf->f = stdout;
725784
else {
726-
outf = fopen(arg, "a");
727-
if (!outf)
785+
logf->f = fopen(arg, "a");
786+
if (!logf->f)
728787
return tal_fmt(tmpctx, "Failed to open: %s", strerror(errno));
729788
}
730789

731790
tal_arr_expand(&ld->logfiles, tal_strdup(ld->logfiles, arg));
732-
tal_arr_expand(&ld->log->log_book->outfiles, outf);
791+
tal_arr_expand(&ld->log_book->log_files, logf);
733792

734793
/* For convenience make a block of empty lines just like Bitcoin Core */
735-
size = ftell(outf);
794+
size = ftell(logf->f);
736795
if (size > 0)
737-
fprintf(outf, "\n\n\n\n");
796+
fprintf(logf->f, "\n\n\n\n");
738797

739798
log_debug(ld->log, "Opened log file %s", arg);
740799
return NULL;
@@ -770,22 +829,23 @@ void logging_options_parsed(struct log_book *log_book)
770829

771830
/* Set print_levels for each log, depending on filters. */
772831
list_for_each(&log_book->loggers, log, list) {
773-
log->print_level = filter_level(log_book,
774-
log->prefix,
775-
log->default_node_id);
832+
log->print_level = print_level(log_book,
833+
log->prefix,
834+
log->default_node_id);
776835
}
777836

778837
/* Catch up, since before we were only printing BROKEN msgs */
779838
for (size_t i = 0; i < log_book->num_entries; i++) {
780839
const struct log_entry *l = &log_book->log[i];
781840

782-
if (l->level >= filter_level(log_book, l->prefix, l->nc ? &l->nc->node_id : NULL))
841+
if (l->level >= print_level(log_book, l->prefix, l->nc ? &l->nc->node_id : NULL))
783842
log_to_files(log_book->prefix, l->prefix->prefix, l->level,
784843
l->nc ? &l->nc->node_id : NULL,
785844
&l->time, l->log,
786845
l->io, tal_bytelen(l->io),
787846
log_book->print_timestamps,
788-
log_book->outfiles);
847+
log_book->default_print_level,
848+
log_book->log_files);
789849
}
790850
}
791851

0 commit comments

Comments
 (0)