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)'
 

Reply via email to