#!/bin/bash
+# I, Ian Kelling, follow the GNU license recommendations at
+# https://www.gnu.org/licenses/license-recommendations.en.html. They
+# recommend that small programs, < 300 lines, be licensed under the
+# Apache License 2.0. This file contains or is part of one or more small
+# programs. If a small program grows beyond 300 lines, I plan to switch
+# its license to GPL.
+
+# Copyright 2024 Ian Kelling
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
# Copyright (C) 2019 Ian Kelling
-# SPDX-License-Identifier: AGPL-3.0-or-later
+# Log errors once or so instead of many times.
+
+ # This program 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.
+
+ # This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+# SPDX-License-Identifier: GPL-3.0-or-later
append() {
cat >> "$1"
}
log-once() {
- local cbase c log line i out file o tmp
+ local cbase c log line i out file o tmp mvout mverr verbose
cbase=/var/local/cron-errors
[[ $EUID == 0 ]] || cbase=$HOME/cron-errors
local help="Usage: some-command-that-outputs-on-error |& log-once [OPTION]... LOG_NAME
$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
+-v: Output the errors along the way to ERRORS
You can emulate how cronjobs work by doing this for example:
be an error, but I haven't written it yet.
"
errors=3
+ mverr=0
+ verbose=false
+
while true; do
if [[ $1 == --help ]]; then
echo "$help"
return
+ elif [[ $1 == -v ]]; then
+ verbose=true
+ shift
elif [[ $1 == -[0-9]* ]]; then
errors=${1#-}
shift
i="${file#$c}"
if (( i < errors )); then
new_file=$c$((i+1))
- mv $file $new_file
+ mvout=$(mv $file $new_file 2>&1) || mverr=$?
+ if (( mverr )); then
+ if [[ $mvout == *": No such file or directory" ]]; then
+ # We've very likely hit a race condition, where another
+ # log-once did the mv before us.
+ return 0
+ else
+ echo "log-once: error on mv $file $new_file"
+ return $mverr
+ fi
+ fi
file=$new_file
- if [[ $file == $c$errors ]]; then
+ if [[ $file == $c$errors ]] || $verbose; then
out="tee -a"
fi
fi