mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 15:44:21 +01:00
daemon: dump logs on crash.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
#include "lightningd.h"
|
#include "lightningd.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <ccan/array_size/array_size.h>
|
|
||||||
#include <ccan/err/err.h>
|
#include <ccan/err/err.h>
|
||||||
#include <ccan/opt/opt.h>
|
#include <ccan/opt/opt.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
@@ -22,58 +21,6 @@ static struct lightningd_state *lightningd_state(void)
|
|||||||
return state;
|
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. */
|
/* Tal wrappers for opt. */
|
||||||
static void *opt_allocfn(size_t size)
|
static void *opt_allocfn(size_t size)
|
||||||
{
|
{
|
||||||
@@ -104,18 +51,14 @@ int main(int argc, char *argv[])
|
|||||||
"\n"
|
"\n"
|
||||||
"A bitcoin lightning daemon.",
|
"A bitcoin lightning daemon.",
|
||||||
"Print this message.");
|
"Print this message.");
|
||||||
opt_register_arg("--log-level", arg_log_level, NULL, state,
|
opt_register_logging(state->base_log);
|
||||||
"log level (debug, info, unusual, broken)");
|
|
||||||
opt_register_arg("--log-prefix", arg_log_prefix, NULL, state,
|
|
||||||
"log prefix");
|
|
||||||
opt_register_arg("--log-file=<file>", arg_log_to_file, NULL, state,
|
|
||||||
"log to file instead of stdout");
|
|
||||||
opt_register_version();
|
opt_register_version();
|
||||||
|
|
||||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
errx(1, "no arguments accepted");
|
errx(1, "no arguments accepted");
|
||||||
|
|
||||||
|
crashlog_activate(state->base_log);
|
||||||
log_info(state->base_log, "Hello world!");
|
log_info(state->base_log, "Hello world!");
|
||||||
tal_free(state);
|
tal_free(state);
|
||||||
opt_free_table();
|
opt_free_table();
|
||||||
|
|||||||
108
daemon/log.c
108
daemon/log.c
@@ -1,12 +1,18 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "pseudorand.h"
|
#include "pseudorand.h"
|
||||||
|
#include <ccan/array_size/array_size.h>
|
||||||
#include <ccan/list/list.h>
|
#include <ccan/list/list.h>
|
||||||
|
#include <ccan/opt/opt.h>
|
||||||
#include <ccan/read_write_all/read_write_all.h>
|
#include <ccan/read_write_all/read_write_all.h>
|
||||||
#include <ccan/str/hex/hex.h>
|
#include <ccan/str/hex/hex.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
#include <ccan/time/time.h>
|
#include <ccan/time/time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
struct log_entry {
|
struct log_entry {
|
||||||
struct list_node list;
|
struct list_node list;
|
||||||
@@ -323,6 +329,108 @@ static void log_one_line(unsigned int skipped,
|
|||||||
data->prefix = "\n";
|
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=<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)
|
void log_dump_to_file(int fd, const struct log_record *lr)
|
||||||
{
|
{
|
||||||
const struct log_entry *i;
|
const struct log_entry *i;
|
||||||
|
|||||||
@@ -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 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 */
|
#endif /* LIGHTNING_DAEMON_LOG_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user