libplugin: plugin_exit helper which flushes stdout.

We weren't actually getting the last log out; this does that.

We have to fix test_bitcoin_failure which now notices the BROKEN
log message.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-Fixed: libplugin: Fatal error messages from plugin_exit() now logged in lightningd.
This commit is contained in:
Rusty Russell 2021-09-03 19:46:20 +09:30 committed by Christian Decker
parent 1d8aecb44f
commit 2063049559
3 changed files with 28 additions and 3 deletions

View file

@ -12,6 +12,7 @@
#include <plugins/libplugin.h>
#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
@ -78,6 +79,8 @@ struct plugin {
bool manifested;
/* Has init been received ? */
bool initialized;
/* Are we exiting? */
bool exiting;
/* Map from json command names to usage strings: we don't put this inside
* struct json_command as it's good practice to have those const. */
@ -1123,6 +1126,15 @@ void plugin_notify_progress(struct command *cmd,
plugin_notify_end(cmd, js);
}
void NORETURN plugin_exit(struct plugin *p, int exitcode)
{
p->exiting = true;
io_conn_out_exclusive(p->stdout_conn, true);
io_wake(p);
io_loop(NULL, NULL);
exit(exitcode);
}
void NORETURN plugin_err(struct plugin *p, const char *fmt, ...)
{
va_list ap;
@ -1131,8 +1143,10 @@ void NORETURN plugin_err(struct plugin *p, const char *fmt, ...)
plugin_logv(p, LOG_BROKEN, fmt, ap);
va_end(ap);
va_start(ap, fmt);
errx(1, "%s", tal_vfmt(NULL, fmt, ap));
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
plugin_exit(p, 1);
}
void plugin_log(struct plugin *p, enum log_level l, const char *fmt, ...)
@ -1315,6 +1329,9 @@ static struct io_plan *ld_write_json(struct io_conn *conn,
return json_stream_output(plugin->js_arr[0], plugin->stdout_conn,
ld_stream_complete, plugin);
/* If we were simply flushing final output, stop now. */
if (plugin->exiting)
io_break(plugin);
return io_out_wait(conn, plugin, ld_write_json, plugin);
}
@ -1391,7 +1408,7 @@ static struct plugin *new_plugin(const tal_t *ctx,
}
p->init = init;
p->manifested = p->initialized = false;
p->manifested = p->initialized = p->exiting = false;
p->restartability = restartability;
strmap_init(&p->usagemap);
p->in_timer = 0;

View file

@ -164,6 +164,9 @@ struct command_result *command_param_failed(void);
/* Call this on fatal error. */
void NORETURN plugin_err(struct plugin *p, const char *fmt, ...);
/* Normal exit (makes sure to flush output!). */
void NORETURN plugin_exit(struct plugin *p, int exitcode);
/* This command is finished, here's a detailed error; @cmd cannot be
* NULL, data can be NULL; otherwise it must be a JSON object. */
struct command_result *WARN_UNUSED_RESULT

View file

@ -134,11 +134,16 @@ def test_bitcoin_failure(node_factory, bitcoind):
bitcoind.cmd_line += ["-blocksonly"]
bitcoind.start()
l2 = node_factory.get_node(start=False, expect_fail=True)
# Ignore BROKEN log message about blocksonly mode.
l2 = node_factory.get_node(start=False, expect_fail=True,
allow_broken_log=True)
with pytest.raises(ValueError):
l2.start(stderr=subprocess.PIPE)
assert l2.daemon.is_in_stderr(r".*deactivating transaction relay is not"
" supported.") is not None
# wait_for_log gets upset since daemon is not running.
wait_for(lambda: l2.daemon.is_in_log('deactivating transaction'
' relay is not supported'))
def test_bitcoin_ibd(node_factory, bitcoind):