How can I build a Bash logger with timestamps, colors, and printf formatting?

0
2
Asked By MellowPine47 On

I'm writing Bash helper functions such as log_info, log_warn, and log_error. They should add a timestamp and colored severity label, while sending diagnostic output to stderr so stdout remains available for functions that return values. I'd also like the logger to support normal printf-style format strings and arguments, for example:

log_info "What a %s %d" "day" 100
log_error "Error: %s %s" "something went wrong" "{1: "enter"}"

What would a clean implementation of the underlying log function look like, and are ANSI colors portable enough to use without checking terminal support?

3 Answers

Answered By VelvetCanyon5 On

Keeping logs on stderr is a sensible convention for command-line functions whose stdout is part of their data interface. Callers can still redirect the two streams independently. One detail to watch for is that `$*` collapses arguments and prevents printf from interpreting each argument according to the format string; use a format variable plus `"$@"` instead. Also, make sure every format string is trusted input, since passing arbitrary text as a printf format can produce unexpected output.

Answered By CedarOrbit22 On

ANSI escape sequences are widely supported by modern terminal emulators, but they are not guaranteed to be appropriate everywhere. A common improvement is to disable color when stderr is not a terminal, when the user explicitly requests no color, or when output is being redirected. Also, ISO 8601-style timestamps such as `2026-08-20T06:46:11+0000` are generally easier to sort and interpret than a day-month-year format.

For example, you can choose the color conditionally:

```bash
if [[ -t 2 && -z ${NO_COLOR:-} ]]; then
# use color values
else
# use empty strings
fi
```

The exact terminal and shell support still varies, so treating color as an optional presentation feature is safer than assuming it is always available.

HarborWren61 -

That also means redirected logs stay clean instead of containing escape characters, while interactive terminal output can still be colorized.

Answered By QuartzMango8 On

In Bash 4.2 and newer, its date format can be generated directly by printf with the `%(...)T` conversion. To preserve normal printf formatting, keep the format string and arguments separate rather than joining them with `$*`:

```bash
declare -A LOG_COLOR=(
[INFO]='33[0;34m'
[WARNING]='33[1;33m'
[ERROR]='33[0;31m'
)

log() {
local level=$1
shift
local format=$1
shift
local message

printf -v message "$format" "$@"
printf '%s%(%Y-%m-%dT%H:%M:%S%z)T %s33[0m %sn'
"${LOG_COLOR[$level]}" -1 "$level" "$message" >&2
}

log_info() { log INFO "$@"; }
log_warn() { log WARNING "$@"; }
log_error() { log ERROR "$@"; }
```

The `printf -v` line formats the remaining arguments using the caller’s format string, so calls like `log_info 'What a %s %d' day 100` work as expected. The final `>&2` sends the completed log line to stderr.

MellowPine47 -

So the format string needs to be extracted first, and then the remaining arguments can be passed to printf with `"$@"`, rather than combining everything into one string?

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.