s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

commit 6c936711c61df41eeb936a98e6bc43584776ab08
parent 3457a5ce01d7df3bc4cdc6259736ca210b4d4765
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date:   Fri, 26 May 2023 15:29:13 +0000

 Add -t lastlinetimeout option to s6-log

Signed-off-by: Laurent Bercot <ska@appnovation.com>

Diffstat:
MNEWS | 1+
Mdoc/s6-log.html | 11++++++++++-
Mdoc/upgrade.html | 2++
Msrc/daemontools-extras/s6-log.c | 71++++++++++++++++++++++++++++++++++++++++-------------------------------
4 files changed, 53 insertions(+), 32 deletions(-)

diff --git a/NEWS b/NEWS @@ -4,6 +4,7 @@ In 2.11.4.0 ----------- - New option to s6-svc: -s, to specify a signal by name (or number). + - New option to s6-log: -t, to specify a timeout for partial last lines. In 2.11.3.2 diff --git a/doc/s6-log.html b/doc/s6-log.html @@ -27,7 +27,7 @@ with full POSIX regular expression support. <h2> Interface </h2> <pre> - s6-log [ -d <em>notif</em> ] [ -q | -v ] [ -b ] [ -p ] [ -l <em>linelimit</em> ] [ -- ] <em>logging script</em> + s6-log [ -d <em>notif</em> ] [ -q | -v ] [ -b ] [ -p ] [ -l <em>linelimit</em> ] [ -t <em>lastlinetimeout</em> ] [ -- ] <em>logging script</em> </pre> <p> @@ -75,6 +75,15 @@ etc. <em>linelimit</em> cannot be less than 48, unless it is 0 (which means infinite). The default is 8192 bytes. Setting <em>linelimit</em> to 0 ensures that lines will never be split; this may cause important memory consumption by s6-log if it is fed extremely long lines, so use with caution. </li> + <li> <tt>-t&nbsp;<em>lastlinetimeout</em></tt>&nbsp;: if s6-log receives +a termination signal but has a read a partial line in its buffer, it will +wait for at most <em>lastlinetimeout</em> milliseconds for its service +to send it the remainder of the line; if it still hasn't read a newline +character by then, it will add a newline character itself and process the +line, then exit. By default, <em>lastlinetimeout</em> is 2000, which means +s6-log will wait for at most 2 seconds for completion of its last partial line. +If <em>lastlinetimeout</em> is given as <strong>0</strong>, then s6-log +will wait forever; it won't exit until it actually reads a newline or EOF. </li> </ul> <h2> Logdirs </h2> diff --git a/doc/upgrade.html b/doc/upgrade.html @@ -23,6 +23,8 @@ <ul> <li> <a href="//skarnet.org/software/skalibs/">skalibs</a> dependency bumped to 2.13.2.0. </li> + <li> New <tt>-s</tt> option to <a href="s6-svc.html">s6-svc</a>. </li> + <li> New <tt>-t</tt> option to <a href="s6-log.html">s6-log</a>. </li> </ul> <h2> in 2.11.3.2 </h2> diff --git a/src/daemontools-extras/s6-log.c b/src/daemontools-extras/s6-log.c @@ -39,7 +39,7 @@ #include <execline/config.h> #endif -#define USAGE "s6-log [ -d notif ] [ -q | -v ] [ -b ] [ -p ] [ -l linelimit ] [ -- ] logging_script" +#define USAGE "s6-log [ -d notif ] [ -q | -v ] [ -b ] [ -p ] [ -l linelimit ] [ -t lastlinetimeout ] [ -- ] logging_script" #define dieusage() strerr_dieusage(100, USAGE) #define dienomem() strerr_diefu1sys(111, "stralloc_catb") @@ -49,10 +49,11 @@ static mode_t mask ; static int flagprotect = 0 ; static int flagexiting = 0 ; static unsigned int verbosity = 1 ; +static tain lastlinetto = TAIN_INFINITE_RELATIVE ; +static tain exit_deadline = TAIN_INFINITE ; static stralloc indata = STRALLOC_ZERO ; - /* Data types */ typedef int qcmp_func (void const *, void const *) ; @@ -1087,6 +1088,13 @@ static void normal_stdin (scriptelem_t const *script, unsigned int scriptlen, si } } +static void process_partial_line (scriptelem_t const *script, unsigned int scriptlen, unsigned int gflags) +{ + if (!stralloc_0(&indata)) dienomem() ; + script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ; + indata.len = 0 ; +} + static void last_stdin (scriptelem_t const *script, unsigned int scriptlen, size_t linelimit, unsigned int gflags) { for (;;) @@ -1097,25 +1105,22 @@ static void last_stdin (scriptelem_t const *script, unsigned int scriptlen, size case 0 : return ; case -1 : if ((errno != EPIPE) && verbosity) strerr_warnwu1sys("read from stdin") ; - if (!indata.len) goto eof ; - addfinalnewline: - c = '\n' ; + if (indata.len) goto lastline ; + goto end ; case 1 : + if (c == '\n' || !c) goto lastline ; if (!stralloc_catb(&indata, &c, 1)) dienomem() ; - if (c == '\n') - { - script_run(script, scriptlen, indata.s, indata.len - 1, gflags) ; - goto eof ; - } - else if (linelimit && indata.len > linelimit) + if (linelimit && indata.len >= linelimit) { if (verbosity) strerr_warnw2x("input line too long, ", "stopping before the end") ; - goto addfinalnewline ; + goto lastline ; } - break ; + else break ; } } - eof: + lastline: + process_partial_line(script, scriptlen, gflags) ; + end: prepare_to_exit() ; } @@ -1170,6 +1175,7 @@ static inline int handle_signals (void) if (flagprotect) break ; case SIGHUP : handle_stdin = &last_stdin ; + tain_add_g(&exit_deadline, &lastlinetto) ; if (!indata.len) { prepare_to_exit() ; e = 1 ; } break ; case SIGCHLD : @@ -1203,9 +1209,10 @@ int main (int argc, char const *const *argv) PROG = "s6-log" ; { subgetopt l = SUBGETOPT_ZERO ; + unsigned int t = 2000 ; for (;;) { - int opt = subgetopt_r(argc, argv, "qvbpl:d:", &l) ; + int opt = subgetopt_r(argc, argv, "qvbpl:d:t:", &l) ; if (opt == -1) break ; switch (opt) { @@ -1219,10 +1226,13 @@ int main (int argc, char const *const *argv) if (notif < 3) strerr_dief1x(100, "notification fd must be 3 or more") ; if (fcntl(notif, F_GETFD) < 0) strerr_dief1sys(100, "invalid notification fd") ; break ; + case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; + if (t) tain_from_millisecs(&lastlinetto, t) ; + else lastlinetto = tain_infinite_relative ; } if (!argc) dieusage() ; if (linelimit && linelimit < LINELIMIT_MIN) linelimit = LINELIMIT_MIN ; @@ -1265,11 +1275,10 @@ int main (int argc, char const *const *argv) for (;;) { - tain deadline ; + tain deadline = exit_deadline ; int r = 0 ; unsigned int xindex0, xindex1 ; unsigned int i = 0, j = 1 ; - tain_add_g(&deadline, &tain_infinite_relative) ; if (bufalloc_1->fd == 1 && bufalloc_len(bufalloc_1)) { r = 1 ; @@ -1285,13 +1294,7 @@ int main (int argc, char const *const *argv) if (bufalloc_len(&logdirs[i].out) || (logdirs[i].rstate != ROTSTATE_WRITABLE)) { r = 1 ; - if (!tain_future(&logdirs[i].deadline)) - { - x[j].fd = logdirs[i].fd ; - x[j].events = IOPAUSE_WRITE ; - logdirs[i].xindex = j++ ; - } - else if (tain_less(&logdirs[i].deadline, &deadline)) + if (tain_less(&logdirs[i].deadline, &deadline)) deadline = logdirs[i].deadline ; } } @@ -1307,7 +1310,18 @@ int main (int argc, char const *const *argv) r = iopause_g(x, j, &deadline) ; if (r < 0) strerr_diefu1sys(111, "iopause") ; - else if (!r) continue ; + else if (!r) + { + if (!tain_future(&exit_deadline)) + { + if (indata.len) process_partial_line(script, scriptlen, gflags) ; + prepare_to_exit() ; + } + for (i = 0 ; i < llen ; i++) + if (!tain_future(&logdirs[i].deadline)) + rotate_or_flush(logdirs + i) ; + continue ; + } if (x[0].revents & (IOPAUSE_READ | IOPAUSE_EXCEPT) && handle_signals()) continue ; @@ -1336,13 +1350,8 @@ int main (int argc, char const *const *argv) (*handle_stdin)(script, scriptlen, linelimit, gflags) ; else { + if (indata.len) process_partial_line(script, scriptlen, gflags) ; prepare_to_exit() ; - if (indata.len) - { - if (!stralloc_0(&indata)) dienomem() ; - script_run(script, scriptlen, indata.s, indata.len-1, gflags) ; - indata.len = 0 ; - } } } }