simplify log once
authorIan Kelling <iank@fsf.org>
Sun, 27 Mar 2022 10:03:08 +0000 (06:03 -0400)
committerIan Kelling <iank@fsf.org>
Sun, 27 Mar 2022 10:03:51 +0000 (06:03 -0400)
log-once

index 4a2b3480e5c8dbc20771feb9df20bef5646ce008..3aa3c766642b531f812d4d8d08486079497d936a 100755 (executable)
--- a/log-once
+++ b/log-once
@@ -6,23 +6,29 @@ append() {
   cat >> "$1"
 }
 log-once() {
-  local cbase c log x i out file o tmp
+  local cbase c log line i out file o tmp
   cbase=/var/local/cron-errors
   [[ $EUID == 0 ]] || cbase=$HOME/cron-errors
-  local help="Usage: log-once [OPTION]... LOG_NAME [LOG_MESSAGE...]
+  local help="Usage: some-command-that-outputs-on-error |& log-once [OPTION]... LOG_NAME
 
-For cronjobs, email log on repeated failure and success after failure.
-
-Meant for use in cronjobs where LOG_MESSAGE or STDIN represents an error,
+Main use case: in cronjobs where STDIN represents an error,
 but we only want to output that to STDOUT if we've seen this type of
 error ERRORS(default 3) number of times in a row, then we don't
-want to output anything again until we've seen a success (an empty LOG_MESSAGE).
+want to output anything again until we've seen a success: no standard input.
+
+Logs STDIN to /var/local/cron-errors/LOG_NAME\$error_count or
+$HOME/cron-errors if not root, and keeps state in the same directory.
+
+-ERRORS:  ERRORS is the number of errors to accumulate before outputing the error
+
+
+You can emulate how cronjobs work by doing this for example:
 
-Logs LOG_MESSAGE or STDIN to /var/local/cron-errors/LOG_NAME\$error_count
-or $HOME/cron-errors if not root, and keeps
-state in the same directory.
+    cmdname |& log-once | ifne mail -s 'cmdname failed' root@localhost
 
--ERRORS:  ERRORS is the number of errors to accumulate before outputing the error"
+I could imagine a similar command that considers its non-option args to
+be an error, but I haven't written it yet.
+"
   errors=3
   while true; do
     if [[ $1 == --help ]]; then
@@ -42,17 +48,15 @@ state in the same directory.
   # todo, make option & make them overridable based on command line or env variable
   [[ -d $cbase ]] || mkdir -p $cbase
   c=$cbase/$log_name
-  # http://stackoverflow.com/questions/2456750/detect-presence-of-stdin-contents-in-shell-script
   log=false
-  if [[ $2 ]]; then
-    log=true
-    # read stdin for anything which is not just a newline
-  elif [[ ! -t 0 ]]; then
-    while read -r x; do
-      output+=( "$x" )
-      [[ $x ]] && log=true
-    done
-  fi
+  while read -r line; do
+    output+=( "$line" )
+    # If we find something that is not just a newline:
+    if [[ $line ]]; then
+      log=true
+      break
+    fi
+  done
   glob="$c[0-9]*"
   # file is error file indicating previous error
   tmp=($glob); file="${tmp[0]}"
@@ -77,7 +81,7 @@ state in the same directory.
         out="tee -a"
       fi
     fi
-    $out $file <<<"log-once: $(date "+%A, %B %d, %r")"
+    $out $file <<<"log-once: $(date -R)"
     if [[ $2 ]]; then
       $out $file <<<"$*"
     else
@@ -91,7 +95,7 @@ state in the same directory.
   if [[ $file ]]; then
     rm -f $file
     if [[ $file == $c$errors ]]; then
-      echo "log-once success after failure for $c"
+      echo "log-once: $(date -R): success after failure for $c"
     fi
   fi
   return 0