civodul pushed a commit to branch wip-syslogd
in repository shepherd.

commit 917b9b50c78e9a06e1f4ed98e1612512b04e5d27
Author: Ludovic Courtès <[email protected]>
AuthorDate: Thu Jul 18 23:05:04 2024 +0200

    squash! #:log-files returns a list of files rather than a single file.
---
 modules/shepherd/service/system-log.scm | 78 +++++++++++++++++++++++----------
 tests/services/system-log.sh            | 21 +++++----
 2 files changed, 68 insertions(+), 31 deletions(-)

diff --git a/modules/shepherd/service/system-log.scm 
b/modules/shepherd/service/system-log.scm
index 1a672af..302d9f0 100644
--- a/modules/shepherd/service/system-log.scm
+++ b/modules/shepherd/service/system-log.scm
@@ -23,6 +23,7 @@
   #:autoload   (shepherd config) (%localstatedir)
   #:autoload   (shepherd logger) (open-log-file)
   #:autoload   (shepherd comm) (system-log-file)
+  #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-9)
   #:use-module (srfi srfi-71)
   #:use-module (ice-9 match)
@@ -218,10 +219,10 @@ messages to be logged on @var{socket} and passing them to 
@var{dispatcher}."
        (close-port socket)
        (put-message dispatcher `(terminate ,reply))))))
 
-(define (log-dispatcher channel log-file)
+(define (log-dispatcher channel log-files)
   "Dispatch system log messages received on @var{channel} to log files.  Call
-@var{log-file} for each system log message to determine the destination file
-name."
+@var{log-files} for each system log message to determine the destination
+file(s)."
   (define (log-line message output)
     ;; Write MESSAGE to OUTPUT and return its timestamp.
     (let* ((now (current-time))
@@ -240,23 +241,34 @@ name."
       (newline output)
       now))
 
-  (define default-log-file
+  (define default-log-files
     (default-log-file-procedure))
 
   (lambda ()
     (let loop ((ports vlist-null))
       (match (get-message channel)
         ((? system-log-message? message)
-         (let ((file (or (false-if-exception (log-file message))
-                         (default-log-file message))))
-           (match (vhash-assoc file ports)
-             (#f
-              (let ((port (open-log-file file)))
-                (log-line message port)
-                (loop (vhash-cons file port ports))))
-             ((_ . port)
-              (log-line message port)
-              (loop ports)))))
+         ;; Write MESSAGE to the target file(s).
+         (let ((files (or (false-if-exception (log-files message))
+                          (default-log-files message))))
+           (loop (fold (lambda (file ports)
+                         (match (vhash-assoc file ports)
+                           (#f
+                            (catch 'system-error
+                              (lambda ()
+                                (let ((port (open-log-file file)))
+                                  (log-line message port)
+                                  (vhash-cons file port ports)))
+                              (lambda args
+                                (local-output
+                                 (l10n "Failed to open log file '~a': ~a")
+                                 file (strerror (system-error-errno args)))
+                                ports)))
+                           ((_ . port)
+                            (log-line message port)
+                            ports)))
+                       ports
+                       files))))
         (('terminate reply)
          (local-output (l10n "Closing ~a system log ports.")
                        (vlist-length ports))
@@ -267,28 +279,48 @@ name."
                      ports)
          (put-message reply #t))))))
 
-(define (spawn-log-dispatcher log-file)
+(define (spawn-log-dispatcher log-files)
   "Spawn the log dispatcher, responsible for writing system log messages to
-the file returned by @var{log-file} for each message."
+the file(s) returned by @var{log-files} for each message."
   (let ((channel (make-channel)))
-    (spawn-fiber (log-dispatcher channel log-file))
+    (spawn-fiber (log-dispatcher channel log-files))
     channel))
 
 (define (default-log-file-procedure)
   (if (zero? (getuid))
-      (const (in-vicinity %localstatedir "log/syslog"))
-      (const (in-vicinity %user-log-dir "syslog"))))
+      (lambda (message)
+        `(,@(if (member (system-log-message-facility message)
+                        (list (system-log-facility mail)
+                              (system-log-facility authorization/private)))
+                '()
+                (list (in-vicinity %localstatedir "log/messages")
+                      "/dev/tty12"))
+          ,@(if (member (system-log-message-priority message)
+                        (list (system-log-priority emergency)
+                              (system-log-priority alert)))
+                '("/dev/console")
+                '())
+          ,@(if (= (system-log-message-priority message)
+                   (system-log-priority debug))
+                (list (in-vicinity %localstatedir "log/debug"))
+                '())
+          ,@(if (member (system-log-message-facility message)
+                        (list (system-log-facility authorization)
+                              (system-log-facility authorization/private)))
+                (list (in-vicinity %localstatedir "log/secure"))
+                '())))
+      (const (list (in-vicinity %user-log-dir "syslog")))))
 
 (define* (system-log-service #:optional (file (system-log-file))
                              #:key
                              (provision '(system-log syslogd))
                              (requirement '())
-                             (log-file (default-log-file-procedure)))
+                             (log-files (default-log-file-procedure)))
   "Return the system log service (@dfn{syslogd}) with the given
 @var{provision} and @var{requirement} (lists of symbols).  The service accepts
 connections on @var{file}, a Unix-domain socket.  Log messages are passed to
-@var{log-file}, a one-argument procedure that must return the name of the file
-to write to."
+@var{log-files}, a one-argument procedure that must return the list of files
+to write it to."
   (define channel
     (make-channel))
 
@@ -296,7 +328,7 @@ to write to."
            #:requirement requirement
            #:start (lambda ()
                      (let ((socket (open-socket file))
-                           (dispatcher (spawn-log-dispatcher log-file)))
+                           (dispatcher (spawn-log-dispatcher log-files)))
                        (spawn-fiber
                         (lambda ()
                           (run-system-log channel socket dispatcher)))
diff --git a/tests/services/system-log.sh b/tests/services/system-log.sh
index 074f949..1ab7431 100644
--- a/tests/services/system-log.sh
+++ b/tests/services/system-log.sh
@@ -39,20 +39,23 @@ trap "cat $log || true;
 cat > "$conf" <<EOF
 (use-modules (shepherd service system-log))
 
-(define (log-file message)
-  (pk 'log-file->
+(define (log-files message)
+  (pk 'log-files->
       (cond ((= (system-log-message-facility message)
                (system-log-facility authorization/private))
-            "$syslog_auth_file")
+            (list "$syslog_auth_file"))
+            ((= (system-log-message-facility message)
+               (system-log-facility mail))
+            '())  ;too much mail: discard these messages
            ((= (system-log-message-priority message)
                (system-log-priority debug))
-            "$syslog_debug_file")
+            (list "$syslog_debug_file" "$syslog_file"))
            (else
-            "$syslog_file"))))
+            (list "$syslog_file")))))
 
 (register-services
   (list (system-log-service "$syslog_socket"
-                            #:log-file log-file)
+                            #:log-files log-files)
         (service
           '(logger)
           #:requirement '(syslogd)
@@ -73,7 +76,8 @@ cat > "$logger" <<EOF
   (display "<81>Jul 14 12:33:01 sudo: ludo : 3 incorrect password attempts ; 
TTY=pts/34\n" sock)
   (display "<31>Jul 14 12:18:28 ntpd[427]: new interface(s) found: waking up 
resolver\n" sock)
   (display "<38>Jul 14 12:47:33 elogind[286]: Power key pressed short.\n" sock)
-  (display "<30>Jul 14 12:47:33 NetworkManager[319]: <info>  [1720954053.6685] 
manager: sleep: sleep requested\n" sock))
+  (display "<30>Jul 14 12:47:33 NetworkManager[319]: <info>  [1720954053.6685] 
manager: sleep: sleep requested\n" sock)
+  (display "<20>Jul 18 22:22:22 exim[42]: too much mail in your inbox\n" sock))
 EOF
 
 chmod +x "$logger"
@@ -104,12 +108,13 @@ grep "sudo:.* session opened" "$syslog_auth_file"
 grep "sudo:.* authentication failure" "$syslog_auth_file"
 grep "3 incorrect password attempts" "$syslog_auth_file"
 grep "ntpd\[427\]: new interface" "$syslog_debug_file"
+grep "ntpd\[427\]: new interface" "$syslog_file" # this one in both files
 grep "elogind\[286\]: Power key pressed short" "$syslog_file"
 grep "NetworkManager\[319\]: .*sleep" "$syslog_file"
 
 test $(wc -l < "$syslog_auth_file") -eq 3
 test $(wc -l < "$syslog_debug_file") -eq 1
-test $(wc -l < "$syslog_file") -eq 2
+test $(wc -l < "$syslog_file") -eq 3
 
 for file in "$syslog_file" "$syslog_auth_file" "$syslog_debug_file"
 do

Reply via email to