civodul pushed a commit to branch devel in repository shepherd. commit 8c1c74419f4107d36acd41c03e2d0923d229c94b Author: Ludovic Courtès <l...@gnu.org> AuthorDate: Fri Aug 9 16:39:48 2024 +0200
system-log: Implement log rotation. * modules/shepherd/service/system-log.scm (log-dispatcher): Implement log rotation. * tests/services/system-log.sh: Add ‘log-rotation’ service and test it. * doc/shepherd.texi (System Log Service): Mention ‘log-rotation’. (Log Rotation Service): Mention system log. --- doc/shepherd.texi | 8 +++++-- modules/shepherd/service/system-log.scm | 21 ++++++++++++++---- tests/services/system-log.sh | 38 +++++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/doc/shepherd.texi b/doc/shepherd.texi index 29eb27e..b45bb93 100644 --- a/doc/shepherd.texi +++ b/doc/shepherd.texi @@ -1974,7 +1974,10 @@ configuration snippet below instantiates and registers that service for The configuration above starts the service under the names @code{system-log} and @code{syslogd}. Messages are logged in files under @file{/var/log}, on @file{/dev/tty12} (the twelfth console -terminal on Linux), and on the console for emergency messages. +terminal on Linux), and on the console for emergency messages. The +@code{system-log} service is integrated with the log rotation service: +log files it creates are subject to log rotation, in a ``race-free'' +fashion (@pxref{Log Rotation Service}). The destination of syslog messages---the files, terminals, etc.@: where they are written---can be configured by passing a procedure as the @@ -2089,7 +2092,8 @@ wouldn't it be nice to archive them or even delete them periodically? The @dfn{log rotation} service does exactly that. Once you've enabled it, it periodically @dfn{rotates} the log files of services---those specified via the @code{#:log-file} argument of service constructors -(@pxref{Service De- and Constructors})---but also, optionally, +(@pxref{Service De- and Constructors})---those of the system log +(@pxref{System Log Service}), and also, optionally, ``external'' log files produced by some other mechanism. By ``rotating'' we mean this: if a service produces diff --git a/modules/shepherd/service/system-log.scm b/modules/shepherd/service/system-log.scm index 097142c..51d4af7 100644 --- a/modules/shepherd/service/system-log.scm +++ b/modules/shepherd/service/system-log.scm @@ -22,7 +22,8 @@ #:use-module (shepherd service) #:use-module (shepherd support) #:autoload (shepherd config) (%localstatedir) - #:autoload (shepherd logger) (open-log-file) + #:autoload (shepherd logger) (open-log-file + rotate-and-reopen-log-file) #:autoload (shepherd comm) (system-log-file) #:use-module (srfi srfi-1) #:use-module (srfi srfi-9) @@ -309,9 +310,21 @@ in message destination procedure: ")) '() ports)) (loop ports)) - (('rotate requested-file rotated-file reply) - (put-message reply #f) ;TODO: implement it - (loop ports)) + (('rotate file rotated-file reply) + (match (vhash-assoc file ports) + (#f + (local-output (l10n "Ignoring request to rotate unknown \ +system log file '~a'.") + file) + (put-message reply #f) + (loop ports)) + ((_ . port) + (let ((port (rotate-and-reopen-log-file port file + rotated-file))) + (put-message reply (port? port)) + (if (port? port) + (loop (vhash-cons file port (vhash-delete file ports))) + (loop ports)))))) ('terminate (local-output (l10n "Closing ~a system log ports.") (vlist-length ports)) diff --git a/tests/services/system-log.sh b/tests/services/system-log.sh index 78e3c15..742bcea 100644 --- a/tests/services/system-log.sh +++ b/tests/services/system-log.sh @@ -33,14 +33,17 @@ syslog_socket="$PWD/t-syslog-socket-$$" herd="herd -s $socket" -trap "cat $log || true; - rm -f $socket $conf $log $logger $kmsg $syslog_socket; - rm -f $syslog_file $syslog_auth_file $syslog_debug_file $syslog_remote_file; +trap "zcat $log* || true; + rm -f $socket $conf $log* $logger $kmsg $syslog_socket; + rm -f $syslog_file* $syslog_auth_file* $syslog_debug_file* $syslog_remote_file*; test -f $pid && kill \`cat $pid\` || true; rm -f $pid" EXIT cat > "$conf" <<EOF (use-modules (shepherd service system-log) - (shepherd endpoints)) + (shepherd service log-rotation) + (shepherd service timer) + (shepherd endpoints) + (srfi srfi-19)) (define (message-destination message) (pk 'message-destination-> @@ -58,6 +61,14 @@ cat > "$conf" <<EOF (else (list "$syslog_file"))))) +(define today + (time-utc->date (current-time time-utc))) + +(define past-month + (if (= 1 (date-month today)) + 12 + (- (date-month today) 1))) + (define %endpoints (list (endpoint (make-socket-address AF_UNIX "$syslog_socket") #:style SOCK_DGRAM) @@ -68,6 +79,10 @@ cat > "$conf" <<EOF (list (system-log-service %endpoints #:message-destination message-destination #:kernel-log-file "$kmsg") + (log-rotation-service + ;; Arrange so that it does not trigger automatically. + (calendar-event #:months (list past-month)) + #:rotation-size-threshold 0) (service '(logger) #:requirement '(syslogd) @@ -156,6 +171,21 @@ do $herd status system-log | grep "Log files: .*$file" done +# Ensure logs can be rotated. +$herd start log-rotation +$herd trigger log-rotation +for file in "$syslog_file" "$syslog_auth_file" "$syslog_debug_file" \ + "$syslog_remote_file" +do + $herd files log-rotation | grep "$file" + + # Rotation happens asynchronously so wait for a while. + until test -f "$file.1.gz"; do sleep 0.2; done + gunzip < "$file.1.gz" + rm "$file.1.gz" + test -f "$file" # this one should have been recreated +done + $herd stop system-log $herd eval root '(gc)'