1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
# GNU Shepherd --- Test the logging capabilities of 'make-forkexec-constructor'.
# Copyright © 2022-2025 Ludovic Courtès <ludo@gnu.org>
#
# This file is part of the GNU Shepherd.
#
# The GNU Shepherd is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or (at
# your option) any later version.
#
# The GNU Shepherd is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with the GNU Shepherd. If not, see <https://www.gnu.org/licenses/>.
shepherd --version
herd --version
socket="t-socket-$$"
conf="t-conf-$$"
log="t-log-$$"
pid="t-pid-$$"
service_script="t-service-script-$$"
service_pid="t-service-pid-$$"
service_log="t-service-log-$$"
herd="herd -s $socket"
trap "cat $log || true; rm -f $socket $conf $service_pid $service_log $service_script $log;
test -f $pid && kill \`cat $pid\` || true; rm -f $pid" EXIT
cat > "$service_script" <<EOF
echo STARTING
echo \$\$ > "$PWD/$service_pid"
echo STARTED >&2
echo café anyone?
printf "latin1 garbage: \347a alors !\n"
exec sleep 600
EOF
cat > "$conf"<<EOF
(use-modules (ice-9 match))
(define %command
'("$SHELL" "$PWD/$service_script"))
(register-services
(list (service
;; Service with built-in logging.
'(test-builtin-logging)
#:start (make-forkexec-constructor %command
#:pid-file "$PWD/$service_pid")
#:stop (make-kill-destructor)
#:respawn? #f)
(service
;; Service with built-in logging, not emitting a newline in its log.
'(test-logging-without-newline)
#:start (make-forkexec-constructor
'("$SHELL" "-c" "echo \$first; echo -n \$second")
#:environment-variables
'("first=aaaaa" "second=bbbbb"))
#:stop (make-kill-destructor)
#:respawn? #f)
(service
'(test-logging-upon-stop)
#:start (make-forkexec-constructor
'("$SHELL" "-c" "trap 'while true; do echo refusing to leave; done' TERM; sleep 300"))
#:stop (make-kill-destructor #:grace-period 3) ;don't wait too long
#:respawn? #f)
(service
;; Service with built-in logging.
'(test-file-logging)
#:start (make-forkexec-constructor %command
#:log-file "$PWD/$service_log"
#:pid-file "$PWD/$service_pid")
#:stop (make-kill-destructor)
#:respawn? #f)))
;; Start it upfront to make sure the logging fiber works.
(start-service (lookup-service 'test-file-logging))
EOF
rm -f "$pid"
shepherd -I -s "$socket" -c "$conf" -l "$log" --pid="$pid" &
# Wait till it's ready.
while ! test -f "$pid" ; do sleep 0.3 ; done
shepherd_pid="`cat $pid`"
while ! test -f "$service_pid" ; do sleep 0.3 ; done
until $herd status test-file-logging | grep running; do sleep 1; done
# Wait until all the messages have been logged.
until grep "latin1 garbage" "$service_log"; do sleep 0.3; done
cat "$service_log"
for message in "STARTING" "STARTED" "café" "latin1 garbage: .* alors"
do
grep -E '^2[0-9]{3}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} '"$message" "$service_log"
done
$herd status test-file-logging | grep "Log file: $PWD/$service_log"
$herd status test-file-logging | \
grep -E '^ 2[0-9]{3}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} STARTING'
$herd status test-file-logging | \
grep -E '^ 2[0-9]{3}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} STARTED'
# Return the file descriptor corresponding to the given file.
find_file_descriptor ()
{
for fd in "/proc/$shepherd_pid/fd"/*
do
if [ "$(readlink $fd)" = "$1" ]
then
echo "$fd"
break
fi
done
}
if test -d "/proc/$$/fd"
then
# At this point, the log file is open.
test -n "$(find_file_descriptor "$PWD/$service_log")"
# Stop the service and ensure the log file has been closed.
$herd stop test-file-logging
test -z "$(find_file_descriptor "$PWD/$service_log")"
else
# On GNU/Hurd, /proc, when mounted, does not expose as much information as
# that of Linux; it lacks the 'fd' sub-directory.
echo "cannot inspect open file descriptors; skipping" >&2
fi
rm -f "$service_pid"
$herd start test-builtin-logging
# Wait until all the messages have been logged.
until grep "latin1 garbage" "$log"; do sleep 0.3; done
for message in "STARTING" "STARTED" "café" "latin1 garbage: .* alors"
do
# Those might be logged as "[sh] MESSAGE" or "sh[123] MESSAGE" depending
# on when the 'set-process-id' message is received by the logger.
grep -E '^2[0-9]{3}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} .*'"$(basename $SHELL)"'.* '"$message" "$log"
done
$herd status test-builtin-logging | grep -v "Log file"
$herd status test-builtin-logging | \
grep -E '^ 2[0-9]{3}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} STARTING'
$herd status test-builtin-logging | \
grep -E '^ 2[0-9]{3}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2} STARTED'
# Check what happens when logging without a newline.
$herd start test-logging-without-newline
until $herd status test-logging-without-newline | grep stopped; do sleep 0.3; done
$herd status root -n 10 | grep aaaaa
$herd status root -n 10 | grep bbbbb
grep aaaaa "$log"
grep bbbbb "$log"
# Check what happens with services that start logging once they're stopping.
# This used to deadlock: <https://issues.guix.gnu.org/77373>.
$herd start test-logging-upon-stop
$herd status test-logging-upon-stop | grep running
pid="`$herd status test-logging-upon-stop | grep PID \
| sed -es'/.*PID: \([0-9]\+\)$/\1/g'`"
kill -0 $pid
$herd stop test-logging-upon-stop
$herd status test-logging-upon-stop | grep stopped
grep "$(basename $SHELL)\[$pid\] refusing to leave" "$log"
$herd status
$herd stop root
|