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