Message ID | 20171124130614.2875-1-zefir.kurtisi@neratec.com |
---|---|
State | Superseded |
Delegated to: | John Crispin |
Headers | show |
Series | [LEDE-DEV,v2] ubox/logread: add re-connect capability | expand |
On 24/11/17 14:06, Zefir Kurtisi wrote: > When logd is restarted while 'logread -f' is running, the > logread process terminates, which cumbers debugging in > different use-cases. > > This patch adds re-connect functionality to logread. In > follow mode, when the ustream to logd is disconnected, > instead of terminating, it tries to re-connect to logd > and re-issue the original request. > > Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> Hi Zefir, I have just pushed a different version of the patch, thanks for reporting the problem John > --- > v2: in follow mode, don't exit if the initial > ubus lookup for logd fails > > log/logread.c | 143 +++++++++++++++++++++++++++++++++++++--------------------- > 1 file changed, 91 insertions(+), 52 deletions(-) > > diff --git a/log/logread.c b/log/logread.c > index ad06f2a..8229c98 100644 > --- a/log/logread.c > +++ b/log/logread.c > @@ -65,6 +65,10 @@ static int log_type = LOG_STDOUT; > static int log_size, log_udp, log_follow, log_trailer_null = 0; > static int log_timestamp; > static int last_errno = 0; > +static struct ubus_context *ctx; > +static int lines; > + > +static void logread_reconnect_cb(struct uloop_timeout *timeout); > > static const char* getcodetext(int value, CODE *codetable) { > CODE *i; > @@ -268,29 +272,82 @@ static void logread_fd_data_cb(struct ustream *s, int bytes) > } > } > > +/* > + * Reconnect Handling > + * while following log > + * - after logd removal > + * - destroy ustream > + * - cyclically try to re-connect to new logd object > + * - re-issue original request > + * > + * Note: if a re-connection appears while a 'logread -l' request is active, the > + * number of returned lines will not match (i.e. you get some lines from > + * the old instance plus the number of lines requested from the new one) > + */ > + > +/* flag to prevent printing error messages during reconnect cycles */ > +static int object_reconnect_active; > + > +static void logread_restart_reconnect_timer(struct uloop_timeout *timeout) > +{ > + const int LOG_RECONNECT_TIMEOUT_MS = 250; > + uloop_timeout_set(timeout, LOG_RECONNECT_TIMEOUT_MS); > +} > + > static void logread_fd_state_cb(struct ustream *s) > { > - uloop_end(); > + static struct uloop_timeout ubus_timer; > + /* force re-opening of stream */ > + s->free(s); > + > + object_reconnect_active = 1; > + ubus_timer.cb = logread_reconnect_cb; > + logread_restart_reconnect_timer(&ubus_timer); > } > > static void logread_fd_cb(struct ubus_request *req, int fd) > { > static struct ustream_fd test_fd; > - > test_fd.stream.notify_read = logread_fd_data_cb; > test_fd.stream.notify_state = logread_fd_state_cb; > ustream_fd_init(&test_fd, fd); > } > > -int main(int argc, char **argv) > +static int logread_process(void) > { > + static struct blob_buf b; > static struct ubus_request req; > - struct ubus_context *ctx; > uint32_t id; > + int ret = ubus_lookup_id(ctx, "log", &id); > + if (ret) { > + if (!object_reconnect_active) > + fprintf(stderr, "Failed to find log object\n"); > + return ret; > + } > + blob_buf_init(&b, 0); > + blobmsg_add_u8(&b, "stream", 1); > + if (lines) > + blobmsg_add_u32(&b, "lines", lines); > + else if (log_follow) > + blobmsg_add_u32(&b, "lines", 0); > + > + ubus_invoke_async(ctx, id, "read", b.head, &req); > + req.fd_cb = logread_fd_cb; > + ubus_complete_request_async(ctx, &req); > + > + return 0; > +} > + > +static void logread_reconnect_cb(struct uloop_timeout *timeout) > +{ > + if (logread_process()) > + logread_restart_reconnect_timer(timeout); > +} > + > +int main(int argc, char **argv) > +{ > const char *ubus_socket = NULL; > - int ch, ret, lines = 0; > - static struct blob_buf b; > - int tries = 5; > + int ch, ret; > > signal(SIGPIPE, SIG_IGN); > > @@ -354,58 +411,40 @@ int main(int argc, char **argv) > } > ubus_add_uloop(ctx); > > - /* ugly ugly ugly ... we need a real reconnect logic */ > - do { > - ret = ubus_lookup_id(ctx, "log", &id); > - if (ret) { > - fprintf(stderr, "Failed to find log object: %s\n", ubus_strerror(ret)); > - sleep(1); > - continue; > - } > - > - blob_buf_init(&b, 0); > - blobmsg_add_u8(&b, "stream", 1); > - blobmsg_add_u8(&b, "oneshot", !log_follow); > - if (lines) > - blobmsg_add_u32(&b, "lines", lines); > - else if (log_follow) > - blobmsg_add_u32(&b, "lines", 0); > - if (log_follow) { > - if (pid_file) { > - FILE *fp = fopen(pid_file, "w+"); > - if (fp) { > - fprintf(fp, "%d", getpid()); > - fclose(fp); > - } > + if (log_follow) { > + if (pid_file) { > + FILE *fp = fopen(pid_file, "w+"); > + if (fp) { > + fprintf(fp, "%d", getpid()); > + fclose(fp); > } > } > + } > > - if (log_ip && log_port) { > - openlog("logread", LOG_PID, LOG_DAEMON); > - log_type = LOG_NET; > - sender.cb = log_handle_fd; > - retry.cb = log_handle_reconnect; > - uloop_timeout_set(&retry, 1000); > - } else if (log_file) { > - log_type = LOG_FILE; > - sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600); > - if (sender.fd < 0) { > - fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno)); > - exit(-1); > - } > - } else { > - sender.fd = STDOUT_FILENO; > + if (log_ip && log_port) { > + openlog("logread", LOG_PID, LOG_DAEMON); > + log_type = LOG_NET; > + sender.cb = log_handle_fd; > + retry.cb = log_handle_reconnect; > + uloop_timeout_set(&retry, 1000); > + } else if (log_file) { > + log_type = LOG_FILE; > + sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600); > + if (sender.fd < 0) { > + fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno)); > + exit(-1); > } > + } else { > + sender.fd = STDOUT_FILENO; > + } > > - ubus_invoke_async(ctx, id, "read", b.head, &req); > - req.fd_cb = logread_fd_cb; > - ubus_complete_request_async(ctx, &req); > - > + ret = logread_process(); > + /* unless we are following, immediately exit when logd is not up */ > + if (!ret || log_follow) > uloop_run(); > - ubus_free(ctx); > - uloop_done(); > > - } while (ret && tries--); > + ubus_free(ctx); > + uloop_done(); > > return ret; > }
diff --git a/log/logread.c b/log/logread.c index ad06f2a..8229c98 100644 --- a/log/logread.c +++ b/log/logread.c @@ -65,6 +65,10 @@ static int log_type = LOG_STDOUT; static int log_size, log_udp, log_follow, log_trailer_null = 0; static int log_timestamp; static int last_errno = 0; +static struct ubus_context *ctx; +static int lines; + +static void logread_reconnect_cb(struct uloop_timeout *timeout); static const char* getcodetext(int value, CODE *codetable) { CODE *i; @@ -268,29 +272,82 @@ static void logread_fd_data_cb(struct ustream *s, int bytes) } } +/* + * Reconnect Handling + * while following log + * - after logd removal + * - destroy ustream + * - cyclically try to re-connect to new logd object + * - re-issue original request + * + * Note: if a re-connection appears while a 'logread -l' request is active, the + * number of returned lines will not match (i.e. you get some lines from + * the old instance plus the number of lines requested from the new one) + */ + +/* flag to prevent printing error messages during reconnect cycles */ +static int object_reconnect_active; + +static void logread_restart_reconnect_timer(struct uloop_timeout *timeout) +{ + const int LOG_RECONNECT_TIMEOUT_MS = 250; + uloop_timeout_set(timeout, LOG_RECONNECT_TIMEOUT_MS); +} + static void logread_fd_state_cb(struct ustream *s) { - uloop_end(); + static struct uloop_timeout ubus_timer; + /* force re-opening of stream */ + s->free(s); + + object_reconnect_active = 1; + ubus_timer.cb = logread_reconnect_cb; + logread_restart_reconnect_timer(&ubus_timer); } static void logread_fd_cb(struct ubus_request *req, int fd) { static struct ustream_fd test_fd; - test_fd.stream.notify_read = logread_fd_data_cb; test_fd.stream.notify_state = logread_fd_state_cb; ustream_fd_init(&test_fd, fd); } -int main(int argc, char **argv) +static int logread_process(void) { + static struct blob_buf b; static struct ubus_request req; - struct ubus_context *ctx; uint32_t id; + int ret = ubus_lookup_id(ctx, "log", &id); + if (ret) { + if (!object_reconnect_active) + fprintf(stderr, "Failed to find log object\n"); + return ret; + } + blob_buf_init(&b, 0); + blobmsg_add_u8(&b, "stream", 1); + if (lines) + blobmsg_add_u32(&b, "lines", lines); + else if (log_follow) + blobmsg_add_u32(&b, "lines", 0); + + ubus_invoke_async(ctx, id, "read", b.head, &req); + req.fd_cb = logread_fd_cb; + ubus_complete_request_async(ctx, &req); + + return 0; +} + +static void logread_reconnect_cb(struct uloop_timeout *timeout) +{ + if (logread_process()) + logread_restart_reconnect_timer(timeout); +} + +int main(int argc, char **argv) +{ const char *ubus_socket = NULL; - int ch, ret, lines = 0; - static struct blob_buf b; - int tries = 5; + int ch, ret; signal(SIGPIPE, SIG_IGN); @@ -354,58 +411,40 @@ int main(int argc, char **argv) } ubus_add_uloop(ctx); - /* ugly ugly ugly ... we need a real reconnect logic */ - do { - ret = ubus_lookup_id(ctx, "log", &id); - if (ret) { - fprintf(stderr, "Failed to find log object: %s\n", ubus_strerror(ret)); - sleep(1); - continue; - } - - blob_buf_init(&b, 0); - blobmsg_add_u8(&b, "stream", 1); - blobmsg_add_u8(&b, "oneshot", !log_follow); - if (lines) - blobmsg_add_u32(&b, "lines", lines); - else if (log_follow) - blobmsg_add_u32(&b, "lines", 0); - if (log_follow) { - if (pid_file) { - FILE *fp = fopen(pid_file, "w+"); - if (fp) { - fprintf(fp, "%d", getpid()); - fclose(fp); - } + if (log_follow) { + if (pid_file) { + FILE *fp = fopen(pid_file, "w+"); + if (fp) { + fprintf(fp, "%d", getpid()); + fclose(fp); } } + } - if (log_ip && log_port) { - openlog("logread", LOG_PID, LOG_DAEMON); - log_type = LOG_NET; - sender.cb = log_handle_fd; - retry.cb = log_handle_reconnect; - uloop_timeout_set(&retry, 1000); - } else if (log_file) { - log_type = LOG_FILE; - sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600); - if (sender.fd < 0) { - fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno)); - exit(-1); - } - } else { - sender.fd = STDOUT_FILENO; + if (log_ip && log_port) { + openlog("logread", LOG_PID, LOG_DAEMON); + log_type = LOG_NET; + sender.cb = log_handle_fd; + retry.cb = log_handle_reconnect; + uloop_timeout_set(&retry, 1000); + } else if (log_file) { + log_type = LOG_FILE; + sender.fd = open(log_file, O_CREAT | O_WRONLY| O_APPEND, 0600); + if (sender.fd < 0) { + fprintf(stderr, "failed to open %s: %s\n", log_file, strerror(errno)); + exit(-1); } + } else { + sender.fd = STDOUT_FILENO; + } - ubus_invoke_async(ctx, id, "read", b.head, &req); - req.fd_cb = logread_fd_cb; - ubus_complete_request_async(ctx, &req); - + ret = logread_process(); + /* unless we are following, immediately exit when logd is not up */ + if (!ret || log_follow) uloop_run(); - ubus_free(ctx); - uloop_done(); - } while (ret && tries--); + ubus_free(ctx); + uloop_done(); return ret; }
When logd is restarted while 'logread -f' is running, the logread process terminates, which cumbers debugging in different use-cases. This patch adds re-connect functionality to logread. In follow mode, when the ustream to logd is disconnected, instead of terminating, it tries to re-connect to logd and re-issue the original request. Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> --- v2: in follow mode, don't exit if the initial ubus lookup for logd fails log/logread.c | 143 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 52 deletions(-)