diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 2baae10f4..596c69a88 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -1,6 +1,5 @@ #include "lightningd.h" #include "log.h" -#include #include #include #include @@ -22,58 +21,6 @@ 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) { @@ -104,18 +51,14 @@ int main(int argc, char *argv[]) "\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_logging(state->base_log); opt_register_version(); opt_parse(&argc, argv, opt_log_stderr_exit); if (argc != 1) errx(1, "no arguments accepted"); + crashlog_activate(state->base_log); log_info(state->base_log, "Hello world!"); tal_free(state); opt_free_table(); diff --git a/daemon/log.c b/daemon/log.c index f1a87c0ca..65e272bc2 100644 --- a/daemon/log.c +++ b/daemon/log.c @@ -1,12 +1,18 @@ #include "log.h" #include "pseudorand.h" +#include #include +#include #include #include #include #include #include +#include +#include #include +#include +#include struct log_entry { struct list_node list; @@ -323,6 +329,108 @@ static void log_one_line(unsigned int skipped, data->prefix = "\n"; } +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 log *log) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(log_levels); i++) { + if (strcasecmp(arg, log_levels[i].name) == 0) { + set_log_level(log->lr, log_levels[i].level); + return NULL; + } + } + return tal_fmt(NULL, "unknown log level"); +} + +static char *arg_log_prefix(const char *arg, struct log *log) +{ + set_log_prefix(log, arg); + return NULL; +} + +static void log_to_file(const char *prefix, + enum log_level level, + bool continued, + const char *str, + FILE *logf) +{ + if (!continued) { + fprintf(logf, "%s %s\n", prefix, str); + } else { + fprintf(logf, "%s \t%s\n", prefix, str); + } +} + +static char *arg_log_to_file(const char *arg, struct log *log) +{ + FILE *logf = fopen(arg, "a"); + if (!logf) + return tal_fmt(NULL, "Failed to open: %s", strerror(errno)); + set_log_outfn(log->lr, log_to_file, logf); + return NULL; +} + +void opt_register_logging(struct log *log) +{ + opt_register_arg("--log-level", arg_log_level, NULL, log, + "log level (debug, info, unusual, broken)"); + opt_register_arg("--log-prefix", arg_log_prefix, NULL, log, + "log prefix"); + opt_register_arg("--log-file=", arg_log_to_file, NULL, log, + "log to file instead of stdout"); +} + +static struct log *crashlog; + +static void log_crash(int sig) +{ + log_broken(crashlog, "FATAL SIGNAL %i RECEIVED", sig); + /* FIXME: Backtrace! */ + + if (crashlog->lr->print == log_default_print) { + int fd; + const char *logfile; + + /* We expect to be in config dir. */ + logfile = "crash.log"; + fd = open(logfile, O_WRONLY|O_CREAT, 0600); + if (fd < 0) { + logfile = "/tmp/lighning-crash.log"; + fd = open(logfile, O_WRONLY|O_CREAT, 0600); + if (fd < 0) + return; + } + + /* Dump entire log. */ + log_dump_to_file(fd, crashlog->lr); + fprintf(stderr, "Fatal signal %u (see log in %s)\n", + sig, logfile); + } else + /* Log is in default place. */ + fprintf(stderr, "Fatal signal %u\n", sig); +} + +void crashlog_activate(struct log *log) +{ + crashlog = log; + signal(SIGILL, log_crash); + signal(SIGABRT, log_crash); + signal(SIGFPE, log_crash); + signal(SIGSEGV, log_crash); + signal(SIGBUS, log_crash); +} + void log_dump_to_file(int fd, const struct log_record *lr) { const struct log_entry *i; diff --git a/daemon/log.h b/daemon/log.h index 26749bb6a..5d9ede90a 100644 --- a/daemon/log.h +++ b/daemon/log.h @@ -93,4 +93,6 @@ void log_each_line_(const struct log_record *lr, void log_dump_to_file(int fd, const struct log_record *lr); +void opt_register_logging(struct log *log); +void crashlog_activate(struct log *log); #endif /* LIGHTNING_DAEMON_LOG_H */