minor fixes
[log-quiet] / log-once
1 #!/bin/bash
2 # Copyright (C) 2019 Ian Kelling
3 # SPDX-License-Identifier: AGPL-3.0-or-later
4
5 append() {
6 cat >> "$1"
7 }
8 log-once() {
9 local cbase c log x i out file o tmp
10 cbase=/var/local/cron-errors
11 [[ $EUID == 0 ]] || cbase=$HOME/cron-errors
12 local help="Usage: log-once [OPTION]... LOG_NAME [LOG_MESSAGE...]
13
14 For cronjobs, email log on repeated failure and success after failure.
15
16 Meant for use in cronjobs where LOG_MESSAGE or STDIN represents an error,
17 but we only want to output that to STDOUT if we've seen this type of
18 error ERRORS(default 3) number of times in a row, then we don't
19 want to output anything again until we've seen a success (an empty LOG_MESSAGE).
20
21 Logs LOG_MESSAGE or STDIN to /var/local/cron-errors/LOG_NAME\$error_count
22 or $HOME/cron-errors if not root, and keeps
23 state in the same directory.
24
25 -ERRORS: ERRORS is the number of errors to accumulate before outputing the error"
26 errors=3
27 while true; do
28 if [[ $1 == --help ]]; then
29 echo "$help"
30 return
31 elif [[ $1 == -[0-9]* ]]; then
32 errors=${1#-}
33 shift
34 elif [[ $1 == -- ]]; then
35 shift
36 break
37 else
38 break
39 fi
40 done
41 log_name=$1
42 # todo, make option & make them overridable based on command line or env variable
43 [[ -d $cbase ]] || mkdir -p $cbase
44 c=$cbase/$log_name
45 # http://stackoverflow.com/questions/2456750/detect-presence-of-stdin-contents-in-shell-script
46 log=false
47 if [[ $2 ]]; then
48 log=true
49 # read stdin for anything which is not just a newline
50 elif [[ ! -t 0 ]]; then
51 while read -r x; do
52 output+=( "$x" )
53 [[ $x ]] && log=true
54 done
55 fi
56 glob="$c[0-9]*"
57 # file is error file indicating previous error
58 tmp=($glob); file="${tmp[0]}"
59 if [[ $file == "$glob" ]]; then
60 file=
61 fi
62 if $log; then
63 out=append
64 if [[ $file ]]; then
65 i="${file#$c}"
66 if (( i < errors )); then
67 new_file=$c$((i+1))
68 mv $file $new_file
69 file=$new_file
70 if [[ $file == $c$errors ]]; then
71 out="tee -a"
72 fi
73 fi
74 else
75 file=${c}1
76 if (( errors == 1 )); then
77 out="tee -a"
78 fi
79 fi
80 $out $file <<<"log-once: $(date "+%A, %B %d, %r")"
81 if [[ $2 ]]; then
82 $out $file <<<"$*"
83 else
84 for o in "${output[@]}"; do
85 $out $file <<<"$o"
86 done
87 $out $file
88 fi
89 return 0
90 fi
91 if [[ $file ]]; then
92 rm -f $file
93 if [[ $file == $c$errors ]]; then
94 echo "log-once success after failure for $c"
95 fi
96 fi
97 return 0
98 }
99 log-once "$@"