File: logging.sh

package info (click to toggle)
shepherd 1.0.9-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,828 kB
  • sloc: lisp: 8,779; sh: 3,586; makefile: 290; ansic: 50
file content (184 lines) | stat: -rw-r--r-- 6,011 bytes parent folder | download
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