diff options
| author | Laurent Bercot <ska-skaware@skarnet.org> | 2025-07-26 00:07:29 +0000 |
|---|---|---|
| committer | Laurent Bercot <ska@appnovation.com> | 2025-07-26 00:07:29 +0000 |
| commit | 57ea798d76263abd5ade1438afaf40292a6f367c (patch) | |
| tree | 2bd55b15d8ccb11dff1a2f3793edde8323f720f6 | |
| parent | 9310225247a826cffb950680dd07929fa6d970a8 (diff) | |
| download | s6-57ea798d76263abd5ade1438afaf40292a6f367c.tar.gz | |
Seriously clean up s6-log; add Rperiod for periodic log rotations.
Signed-off-by: Laurent Bercot <ska@appnovation.com>
| -rw-r--r-- | doc/s6-log.html | 5 | ||||
| -rw-r--r-- | src/daemontools-extras/s6-log.c | 153 |
2 files changed, 92 insertions, 66 deletions
diff --git a/doc/s6-log.html b/doc/s6-log.html index 850da06..9b8b2a3 100644 --- a/doc/s6-log.html +++ b/doc/s6-log.html @@ -228,6 +228,11 @@ when the size of <tt>current</tt> goes higher than <em>filesize</em> minus on the next logdirs, retry every <em>cooldown</em> milliseconds. By default, <em>cooldown</em> is 2000; it's strongly discouraged to set it to a value under 50. </li> + <li> <strong>R<em>period</em></strong>: if <em>period</em> is not zero, +the next logdirs will be automatically rotated every <em>period</em> seconds, +even if the <tt>current</tt> file has not reached the size limit. If +<em>period</em> is zero (the default), the next logdirs will not be +periodically rotated. </li> <li> <strong>E<em>alertsize</em></strong>: only the first <em>alertsize</em> bytes of the selected lines will be used in the next alerts. An <em>alertsize</em> of 0 means no limit. By default, <em>alertsize</em> is diff --git a/src/daemontools-extras/s6-log.c b/src/daemontools-extras/s6-log.c index a8ad950..1fa5a1e 100644 --- a/src/daemontools-extras/s6-log.c +++ b/src/daemontools-extras/s6-log.c @@ -63,6 +63,7 @@ typedef enum rotstate_e rotstate_t, *rotstate_t_ref ; enum rotstate_e { ROTSTATE_WRITABLE, + ROTSTATE_FLUSHING, ROTSTATE_START, ROTSTATE_RENAME, ROTSTATE_NEWCURRENT, @@ -151,8 +152,10 @@ struct logdir_s bufalloc out ; unsigned int xindex ; tain retrytto ; - tain deadline ; + tain rotdeadline ; + tain retrydeadline ; uint64_t maxdirsize ; + uint32_t rotsecs ; uint32_t b ; uint32_t n ; uint32_t s ; @@ -170,8 +173,9 @@ struct logdir_s .out = BUFALLOC_ZERO, \ .xindex = 0, \ .retrytto = TAIN_ZERO, \ - .deadline = TAIN_ZERO, \ + .deadline = TAIN_INFINITE, \ .maxdirsize = 0, \ + .rotsecs = 0, \ .b = 0, \ .n = 0, \ .s = 0, \ @@ -290,6 +294,12 @@ static inline int logdir_trim (logdir_t *ldp) return n ; } +static void logdir_set_writable (logdir_t *ldp) +{ + ldp->rstate = ROTSTATE_WRITABLE ; + tain_add_g(&ldp->retrydeadline, &tain_infinite_relative) ; +} + static int finish (logdir_t *ldp, char const *name, char suffix) { struct stat st ; @@ -300,7 +310,7 @@ static int finish (logdir_t *ldp, char const *name, char suffix) x[dirlen] = '/' ; memcpy(x + dirlen + 1, name, namelen + 1) ; if (stat(x, &st) < 0) return errno == ENOENT ? 0 : -1 ; - if (st.st_nlink == 1) + if (st.st_nlink == 1 && st.st_size) { char y[dirlen + 29] ; memcpy(y, ldp->dir, dirlen) ; @@ -379,8 +389,7 @@ static int rotator (logdir_t *ldp) if (verbosity) strerr_warnwu2sys("finish previous .s to logdir ", ldp->dir) ; goto fail ; } - tain_copynow(&ldp->deadline) ; - ldp->rstate = ROTSTATE_WRITABLE ; + logdir_set_writable(ldp) ; break ; runprocessor: ldp->rstate = ROTSTATE_RUNPROCESSOR ; @@ -406,7 +415,7 @@ static int rotator (logdir_t *ldp) goto fail ; } ldp->pid = pid ; - tain_add_g(&ldp->deadline, &tain_infinite_relative) ; + tain_add_g(&ldp->retrydeadline, &tain_infinite_relative) ; ldp->rstate = ROTSTATE_WAITPROCESSOR ; } case ROTSTATE_WAITPROCESSOR : @@ -493,17 +502,39 @@ static int rotator (logdir_t *ldp) if (verbosity) strerr_warnwu2sys("finish processed .s to logdir ", ldp->dir) ; goto fail ; } - tain_copynow(&ldp->deadline) ; - ldp->rstate = ROTSTATE_WRITABLE ; + logdir_set_writable(ldp) ; break ; default : strerr_dief1x(101, "inconsistent state in rotator()") ; } return 1 ; fail: - tain_add_g(&ldp->deadline, &ldp->retrytto) ; + tain_add_g(&ldp->retrydeadline, &ldp->retrytto) ; return 0 ; } +static void logdir_flush (logdir_t *ldp) +{ + if (bufalloc_flush(&ldp->out)) logdir_set_writable(ldp) ; +} + +static void logdir_rotate (logdir_t *ldp) +{ + enum rotstate_e oldstate = ldp->rstate ; + if (ldp->rstate == ROTSTATE_FLUSHING || ldp->rstate == ROTSTATE_WRITABLE) ldp->rstate = ROTSTATE_START ; + if (!rotator(ldp)) return ; + if (oldstate == ROTSTATE_FLUSHING) + { + tain_add_g(&ldp->retrydeadline, &ldp->retrytto) ; + ldp->rstate = ROTSTATE_FLUSHING ; + } +} + +static void logdir_retry (logdir_t *ldp) +{ + if (ldp->rstate == ROTSTATE_FLUSHING) logdir_flush(ldp) ; + else rotator(ldp) ; +} + static ssize_t logdir_write (int i, char const *s, size_t len) { logdir_t *ldp = logdirs + i ; @@ -514,36 +545,22 @@ static ssize_t logdir_write (int i, char const *s, size_t len) if (m < n) n = m+1 ; } r = fd_write(ldp->fd, s, n) ; - if (r < 0) + if (r <= 0) { - if (!error_isagain(errno)) - { - tain_add_g(&ldp->deadline, &ldp->retrytto) ; - if (verbosity) strerr_warnwu3sys("write to ", ldp->dir, "/current") ; - } - return r ; + ldp->rstate = ROTSTATE_FLUSHING ; + tain_add_g(&ldp->retrydeadline, &ldp->retrytto) ; + return -1 ; } ldp->b += r ; - if ((ldp->b + ldp->tolerance >= ldp->s) && (s[r-1] == '\n')) + if (ldp->b + ldp->tolerance >= ldp->s && s[r-1] == '\n') { ldp->rstate = ROTSTATE_START ; - rotator(ldp) ; + return rotator(ldp) ? r : -1 ; } - return r ; -} - -static inline void rotate_or_flush (logdir_t *ldp) -{ - if ((ldp->rstate != ROTSTATE_WRITABLE) && !rotator(ldp)) return ; - if (ldp->b >= ldp->s) - { - ldp->rstate = ROTSTATE_START ; - if (!rotator(ldp)) return ; - } - bufalloc_flush(&ldp->out) ; + else return r ; } -static inline void logdir_init (unsigned int index, uint32_t s, uint32_t n, uint32_t tolerance, uint64_t maxdirsize, tain const *retrytto, char const *processor, char const *name, unsigned int flags) +static inline void logdir_init (unsigned int index, uint32_t s, uint32_t n, uint32_t tolerance, uint64_t maxdirsize, uint32_t rotsecs, tain const *retrytto, char const *processor, char const *name, unsigned int flags) { logdir_t *ldp = logdirs + index ; struct stat st ; @@ -555,12 +572,12 @@ static inline void logdir_init (unsigned int index, uint32_t s, uint32_t n, uint ldp->pid = 0 ; ldp->tolerance = tolerance ; ldp->maxdirsize = maxdirsize ; + ldp->rotsecs = rotsecs ; ldp->retrytto = *retrytto ; ldp->processor = processor ; ldp->flags = flags ; ldp->dir = name ; ldp->fd = -1 ; - ldp->rstate = ROTSTATE_WRITABLE ; r = mkdir(ldp->dir, S_IRWXU | S_ISGID) ; if (r < 0 && errno != EEXIST) strerr_diefu2sys(111, "mkdir ", name) ; memcpy(x, name, dirlen) ; @@ -613,10 +630,14 @@ static inline void logdir_init (unsigned int index, uint32_t s, uint32_t n, uint opencurrent: ldp->fd = openc_append(x) ; if (ldp->fd < 0) strerr_diefu2sys(111, "open_append ", x) ; + if (ndelay_off(ldp->fd) == -1) + strerr_diefu2sys(111, "ndelay_off ", x) ; if (fd_chmod(ldp->fd, mask) == -1) strerr_diefu2sys(111, "fd_chmod ", x) ; ldp->b = st.st_size ; - tain_copynow(&ldp->deadline) ; + if (rotsecs) tain_addsec_g(&ldp->rotdeadline, rotsecs) ; + else tain_add_g(&ldp->rotdeadline, &tain_infinite_relative) ; + logdir_set_writable(ldp) ; bufalloc_init(&ldp->out, &logdir_write, index) ; } @@ -648,7 +669,7 @@ static inline int logdir_finalize (logdir_t *ldp) } return 1 ; fail: - tain_add_g(&ldp->deadline, &ldp->retrytto) ; + tain_add_g(&ldp->retrydeadline, &ldp->retrytto) ; return 0 ; } @@ -664,8 +685,8 @@ static inline void finalize (void) if (logdirs[i].rstate != ROTSTATE_END) { if (logdir_finalize(logdirs + i)) n-- ; - else if (tain_less(&logdirs[i].deadline, &deadline)) - deadline = logdirs[i].deadline ; + else if (tain_less(&logdirs[i].retrydeadline, &deadline)) + deadline = logdirs[i].retrydeadline ; } if (!n) break ; { @@ -701,6 +722,7 @@ static inline void script_firstpass (char const *const *argv, unsigned int *sell case 'S' : case 'l' : case 'r' : + case 'R' : case 'E' : case '^' : case 'p' : @@ -758,6 +780,7 @@ static inline void script_secondpass (char const *const *argv, scriptelem_t *scr tain retrytto ; unsigned int fd2_size = 200 ; unsigned int status_size = 1001 ; + uint32_t rotsecs = 0 ; uint32_t s = 99999 ; uint32_t n = 10 ; uint32_t tolerance = 2000 ; @@ -825,6 +848,9 @@ static inline void script_secondpass (char const *const *argv, scriptelem_t *scr if (!tain_from_millisecs(&retrytto, t)) goto fail ; break ; } + case 'R' : + if (!uint320_scan(*argv + 1, &rotsecs)) goto fail ; + break ; case 'E' : if (!uint0_scan(*argv + 1, &fd2_size)) goto fail ; break ; @@ -873,7 +899,7 @@ static inline void script_secondpass (char const *const *argv, scriptelem_t *scr case '/' : { act_t a = { .type = ACTTYPE_DIR, .flags = flags, .prefix = prefix, .prefixlen = prefixlen, .data = { .ld = lidx } } ; - logdir_init(lidx, s, n, tolerance, maxdirsize, &retrytto, processor, *argv, flags) ; + logdir_init(lidx, s, n, tolerance, maxdirsize, rotsecs, &retrytto, processor, *argv, flags) ; lidx++ ; actions[act++] = a ; flagacted = 1 ; flags = 0 ; break ; @@ -1121,13 +1147,13 @@ static inline void processor_died (logdir_t *ldp, int wstat) if (WIFSIGNALED(wstat)) { if (verbosity) strerr_warnw2x("processor crashed in ", ldp->dir) ; - tain_add_g(&ldp->deadline, &ldp->retrytto) ; + tain_add_g(&ldp->retrydeadline, &ldp->retrytto) ; ldp->rstate = ROTSTATE_RUNPROCESSOR ; } else if (WEXITSTATUS(wstat)) { if (verbosity) strerr_warnw2x("processor failed in ", ldp->dir) ; - tain_add_g(&ldp->deadline, &ldp->retrytto) ; + tain_add_g(&ldp->retrydeadline, &ldp->retrytto) ; ldp->rstate = ROTSTATE_RUNPROCESSOR ; } else @@ -1147,16 +1173,8 @@ static inline int handle_signals (void) case -1 : strerr_diefu1sys(111, "selfpipe_read") ; case 0 : return e ; case SIGALRM : - { - unsigned int i = 0 ; - for (; i < llen ; i++) - if ((logdirs[i].rstate == ROTSTATE_WRITABLE) && logdirs[i].b) - { - logdirs[i].rstate = ROTSTATE_START ; - rotator(logdirs + i) ; - } + for (unsigned int i = 0 ; i < llen ; i++) logdir_rotate(logdirs + i) ; break ; - } case SIGTERM : if (flagprotect) break ; case SIGHUP : @@ -1232,11 +1250,11 @@ int main (int argc, char const *const *argv) mask = ~mask & 0666 ; script_firstpass(argv, &sellen, &actlen, &scriptlen, &gflags) ; { + iopause_fd x[3] = { { .events = IOPAUSE_READ } } ; sel_t selections[sellen ? sellen : 1] ; act_t actions[actlen] ; scriptelem_t script[scriptlen] ; logdir_t logdirblob[llen] ; - iopause_fd x[3 + llen] ; logdirs = logdirblob ; script_secondpass(argv, script, selections, actions) ; x[0].fd = selfpipe_init() ; @@ -1252,7 +1270,6 @@ int main (int argc, char const *const *argv) if (!selfpipe_trapset(&set)) strerr_diefu1sys(111, "selfpipe_trapset") ; } - x[0].events = IOPAUSE_READ ; if (notif) { fd_write(notif, "\n", 1) ; @@ -1264,26 +1281,27 @@ int main (int argc, char const *const *argv) tain deadline = exit_deadline ; int r = 0 ; unsigned int xindex0, xindex1 ; - unsigned int i = 0, j = 1 ; + unsigned int j = 1 ; if (bufalloc_1->fd == 1 && bufalloc_len(bufalloc_1)) { r = 1 ; x[j].fd = 1 ; - x[j].events = IOPAUSE_EXCEPT | (bufalloc_len(bufalloc_1) ? IOPAUSE_WRITE : 0) ; + x[j].events = bufalloc_len(bufalloc_1) ? IOPAUSE_WRITE : 0 ; xindex1 = j++ ; } else xindex1 = 0 ; - for (; i < llen ; i++) + for (unsigned int i = 0 ; i < llen ; i++) { - logdirs[i].xindex = 0 ; - if (bufalloc_len(&logdirs[i].out) || (logdirs[i].rstate != ROTSTATE_WRITABLE)) + if (bufalloc_len(&logdirs[i].out)) { - r = 1 ; - if (tain_less(&logdirs[i].deadline, &deadline)) - deadline = logdirs[i].deadline ; + if (logdirs[i].rstate == ROTSTATE_WRITABLE) logdir_flush(logdirs + i) ; + if (logdirs[i].rstate != ROTSTATE_WRITABLE) r = 1 ; } + if (tain_less(&logdirs[i].retrydeadline, &deadline)) deadline = logdirs[i].retrydeadline ; + if (tain_less(&logdirs[i].rotdeadline, &deadline)) deadline = logdirs[i].rotdeadline ; } + if (!flagexiting && !(flagblock && r)) { x[j].fd = 0 ; @@ -1303,13 +1321,20 @@ int main (int argc, char const *const *argv) 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) ; + for (unsigned int i = 0 ; i < llen ; i++) + { + if (!tain_future(&logdirs[i].retrydeadline)) logdir_retry(logdirs + i) ; + if (!tain_future(&logdirs[i].rotdeadline)) + { + if (logdirs[i].rotsecs) tain_addsec_g(&logdirs[i].rotdeadline, logdirs[i].rotsecs) ; + else tain_add_g(&logdirs[i].rotdeadline, &tain_infinite_relative) ; + logdir_rotate(logdirs + i) ; + } + } continue ; } - if (x[0].revents & (IOPAUSE_READ | IOPAUSE_EXCEPT) && handle_signals()) continue ; + if (x[0].revents & IOPAUSE_READ && handle_signals()) continue ; if (xindex1 && x[xindex1].revents) { @@ -1326,10 +1351,6 @@ int main (int argc, char const *const *argv) } } - for (i = 0 ; i < llen ; i++) - if (logdirs[i].xindex && x[logdirs[i].xindex].revents & IOPAUSE_WRITE) - rotate_or_flush(logdirs + i) ; - if (xindex0 && x[xindex0].revents) { if (x[xindex0].revents & IOPAUSE_READ) |
