diff --git a/Makefile b/Makefile index 102945f2e..b5571eac5 100644 --- a/Makefile +++ b/Makefile @@ -185,7 +185,7 @@ PROGRAMS := $(TEST_CLI_PROGRAMS) $(TEST_PROGRAMS) CWARNFLAGS := -Werror -Wall -Wundef -Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes -Wold-style-definition CDEBUGFLAGS := -g -fstack-protector -CFLAGS := $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) -I secp256k1/include/ $(FEATURES) +CFLAGS := $(CWARNFLAGS) $(CDEBUGFLAGS) -I $(CCANDIR) -I secp256k1/include/ -I . $(FEATURES) LDLIBS := -lcrypto -lprotobuf-c $(PROGRAMS): CFLAGS+=-I. diff --git a/daemon/Makefile b/daemon/Makefile index 1d08d1858..bd1ac6360 100644 --- a/daemon/Makefile +++ b/daemon/Makefile @@ -24,4 +24,4 @@ check-source: $(DAEMON_HEADERS:%=check-hdr-include-order/%) check-daemon-makefile: @if [ "`echo daemon/*.h`" != "$(DAEMON_HEADERS)" ]; then echo DAEMON_HEADERS incorrect; exit 1; fi -daemon/lightningd: $(DAEMON_OBJS) $(CCAN_OBJS) +daemon/lightningd: $(DAEMON_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(CCAN_OBJS) libsecp256k1.a diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 8da40fe5b..2baae10f4 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -1,8 +1,15 @@ #include "lightningd.h" #include "log.h" +#include +#include +#include +#include #include +#include +#include #include #include +#include static struct lightningd_state *lightningd_state(void) { @@ -15,11 +22,102 @@ static struct lightningd_state *lightningd_state(void) return state; } +static struct { + const char *name; + enum log_level level; +} log_levels[] = { + { "IO", LOG_IO }, + { "DEBUG", LOG_DBG }, + { "INFO", LOG_INFORM }, + { "UNUSUAL", LOG_UNUSUAL }, + { "BROKEN", LOG_BROKEN } +}; + +static char *arg_log_level(const char *arg, struct lightningd_state *state) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(log_levels); i++) { + if (strcasecmp(arg, log_levels[i].name) == 0) { + set_log_level(state->log_record, log_levels[i].level); + return NULL; + } + } + return tal_fmt(NULL, "unknown log level"); +} + +static char *arg_log_prefix(const char *arg, struct lightningd_state *state) +{ + set_log_prefix(state->base_log, arg); + return NULL; +} + +static void log_to_file(const char *prefix, + enum log_level level, + bool continued, + const char *str, + struct lightningd_state *state) +{ + if (!continued) { + fprintf(state->logf, "%s %s\n", prefix, str); + } else { + fprintf(state->logf, "%s \t%s\n", prefix, str); + } +} + +static char *arg_log_to_file(const char *arg, struct lightningd_state *state) +{ + state->logf = fopen(arg, "a"); + if (!state->logf) + return tal_fmt(NULL, "Failed to open: %s", strerror(errno)); + set_log_outfn(state->log_record, log_to_file, state); + return NULL; +} + +/* Tal wrappers for opt. */ +static void *opt_allocfn(size_t size) +{ + return tal_alloc_(NULL, size, false, TAL_LABEL("opt_allocfn", "")); +} + +static void *tal_reallocfn(void *ptr, size_t size) +{ + if (!ptr) + return opt_allocfn(size); + tal_resize_(&ptr, 1, size, false); + return ptr; +} + +static void tal_freefn(void *ptr) +{ + tal_free(ptr); +} + int main(int argc, char *argv[]) { struct lightningd_state *state = lightningd_state(); + err_set_progname(argv[0]); + opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); + + opt_register_noarg("--help|-h", opt_usage_and_exit, + "\n" + "A bitcoin lightning daemon.", + "Print this message."); + opt_register_arg("--log-level", arg_log_level, NULL, state, + "log level (debug, info, unusual, broken)"); + opt_register_arg("--log-prefix", arg_log_prefix, NULL, state, + "log prefix"); + opt_register_arg("--log-file=", arg_log_to_file, NULL, state, + "log to file instead of stdout"); + opt_register_version(); + + opt_parse(&argc, argv, opt_log_stderr_exit); + if (argc != 1) + errx(1, "no arguments accepted"); + log_info(state->base_log, "Hello world!"); tal_free(state); + opt_free_table(); return 0; } diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 591345ec9..c9a2a6611 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -1,11 +1,13 @@ #ifndef LIGHTNING_DAEMON_LIGHTNING_H #define LIGHTNING_DAEMON_LIGHTNING_H #include "config.h" +#include /* Here's where the global variables hide! */ struct lightningd_state { /* Where all our logging goes. */ struct log_record *log_record; struct log *base_log; + FILE *logf; }; #endif /* LIGHTNING_DAEMON_LIGHTNING_H */ diff --git a/daemon/log.c b/daemon/log.c index b21544e19..f1a87c0ca 100644 --- a/daemon/log.c +++ b/daemon/log.c @@ -20,7 +20,12 @@ struct log_entry { struct log_record { size_t mem_used; size_t max_mem; - enum log_level print; + void (*print)(const char *prefix, + enum log_level level, + bool continued, + const char *str, void *arg); + void *print_arg; + enum log_level print_level; struct timeabs init_time; struct list_head log; @@ -31,6 +36,18 @@ struct log { const char *prefix; }; +static void log_default_print(const char *prefix, + enum log_level level, + bool continued, + const char *str, void *arg) +{ + if (!continued) { + printf("%s %s\n", prefix, str); + } else { + printf("%s \t%s\n", prefix, str); + } +} + static size_t log_bufsize(const struct log_entry *e) { if (e->level == LOG_IO) @@ -76,7 +93,8 @@ struct log_record *new_log_record(const tal_t *ctx, assert(max_mem > sizeof(struct log) * 2); lr->mem_used = 0; lr->max_mem = max_mem; - lr->print = printlevel; + lr->print = log_default_print; + lr->print_level = printlevel; lr->init_time = time_now(); list_head_init(&lr->log); @@ -101,7 +119,7 @@ new_log(const tal_t *ctx, struct log_record *record, const char *fmt, ...) void set_log_level(struct log_record *lr, enum log_level level) { - lr->print = level; + lr->print_level = level; } void set_log_prefix(struct log *log, const char *prefix) @@ -110,6 +128,17 @@ void set_log_prefix(struct log *log, const char *prefix) log->prefix = tal_strdup(log->lr, prefix); } +void set_log_outfn_(struct log_record *lr, + void (*print)(const char *prefix, + enum log_level level, + bool continued, + const char *str, void *arg), + void *arg) +{ + lr->print = print; + lr->print_arg = arg; +} + const char *log_prefix(const struct log *log) { return log->prefix; @@ -161,8 +190,9 @@ void logv(struct log *log, enum log_level level, const char *fmt, va_list ap) l->log = tal_vfmt(l, fmt, ap); - if (level >= log->lr->print) - printf("%s %s\n", log->prefix, l->log); + if (level >= log->lr->print_level) + log->lr->print(log->prefix, level, false, l->log, + log->lr->print_arg); add_entry(log, l); } @@ -176,12 +206,16 @@ void log_io(struct log *log, bool in, const void *data, size_t len) l->log[0] = in; memcpy(l->log + 1, data, len); - if (LOG_IO >= log->lr->print) { - char *hex = tal_arr(l, char, hex_str_size(len)); - hex_encode(data, len, hex, hex_str_size(len)); - printf("%s[%s] %s\n", log->prefix, in ? "IN" : "OUT", hex); + if (LOG_IO >= log->lr->print_level) { + const char *dir = in ? "[IN]" : "[OUT]"; + char *hex = tal_arr(l, char, strlen(dir) + hex_str_size(len)); + strcpy(hex, dir); + hex_encode(data, len, hex + strlen(dir), hex_str_size(len)); + log->lr->print(log->prefix, LOG_IO, false, l->log, + log->lr->print_arg); tal_free(hex); } + add_entry(log, l); errno = save_errno; } @@ -198,8 +232,9 @@ static void do_log_add(struct log *log, const char *fmt, va_list ap) tal_append_vfmt(&l->log, fmt, ap); add_entry(log, l); - if (l->level >= log->lr->print) - printf("%s \t%s\n", log->prefix, l->log + oldlen); + if (l->level >= log->lr->print_level) + log->lr->print(log->prefix, l->level, true, l->log + oldlen, + log->lr->print_arg); } void log_(struct log *log, enum log_level level, const char *fmt, ...) diff --git a/daemon/log.h b/daemon/log.h index 5cc20c198..26749bb6a 100644 --- a/daemon/log.h +++ b/daemon/log.h @@ -54,6 +54,20 @@ void log_add_enum_(struct log *log, const char *enumname, unsigned int val); void set_log_level(struct log_record *lr, enum log_level level); void set_log_prefix(struct log *log, const char *prefix); const char *log_prefix(const struct log *log); +#define set_log_outfn(lr, print, arg) \ + set_log_outfn_((lr), \ + typesafe_cb_preargs(void, void *, (print), (arg),\ + const char *, \ + enum log_level, \ + bool, \ + const char *), (arg)) + +void set_log_outfn_(struct log_record *lr, + void (*print)(const char *prefix, + enum log_level level, + bool continued, + const char *str, void *arg), + void *arg); size_t log_max_mem(const struct log_record *lr); size_t log_used(const struct log_record *lr);