Simple log function in Bash
There's quite a bit of repetition:

echo &amp;&amp; print with roughly the same arguments - tee is probably better here
error and non-error paths - perhaps use one function to prepend the ERROR: tag and call the other?

It might be best to have the filename first, then any number of message words?  That would make the interface more like echo, for example.
There's also a problem with our use of printf - any % characters in the error message will be interpreted as replacement indicators.  Not what we want.  We could use printf %b to expand escape sequences instead:
# log FILE MESSAGE...
log () {
    local file=&quot;$1&quot;; shift
    printf '%b ' &quot;$@&quot; '\n' | tee -a &quot;$file&quot;
}

# log_err FILE MESSAGE...
log_error () {
    local file=&quot;$1&quot;; shift
    local message=&quot;ERROR: $1&quot;; shift
    log &quot;$file&quot; &quot;$message&quot; &quot;$@&quot; &gt;&amp;2
}

If we do want to have a single function with arguments (e.g. to add more options), then we might want to use the while/case approach of option parsing that's often used at the program level:
#!/bin/bash

set -eu

# log [-e] [-f FILE] MESSAGE...
log() {
    local prefix=&quot;&quot;
    local stream=1
    local files=()
    # handle options
    while ! ${1+false}
    do case &quot;$1&quot; in
        -e|--error) prefix=&quot;ERROR:&quot;; stream=2 ;;
        -f|--file) shift; files+=(&quot;${1-}&quot;) ;;
        --) shift; break ;; # end of arguments
        -*) log -e &quot;log: invalid option '$1'&quot;; return 1;;
        *) break ;; # start of message
       esac
       shift
    done
    if ${1+false}
    then log -e &quot;log: no message!&quot;; return 1;
    fi
    # if we have a prefix, update our argument list
    if [ &quot;$prefix&quot; ]
    then set -- &quot;$prefix&quot; &quot;$@&quot;
    fi
    # now perform the action
    printf '%b ' &quot;$@&quot; '\n' | tee -a &quot;${files[@]}&quot; &gt;&amp;$stream
}

There's a non-obvious trick in there that might need explanation: I've used ${1+false} to expand to false when there's at least one argument remaining, or to an empty command when there are no arguments (empty command is considered &quot;true&quot; by if and while).