Direct xtrace output elsewhere than stderr in zsh

As of zsh 5.7, the answer is no. The trace output always goes to stderr.

Source: reading the source. The trace output is written to the file xtrerr, which looks promising, but the only assignments to xtrerr are to stderr, to a copy of it, or to NULL.

It should be possible to write a dynamically loadable module that sets xtrerr, but writing a module outside the zsh source tree is not easy.

A possible workaround is to emulate xtrace with a DEBUG trap. This provides the same basic information in most cases, but I'm sure there are plenty of corner cases where xtrace would be hard or impossible to emulate perfectly. One difference is that the inheritance of the xtrace option and the inheritance of traps follow different rules in some circumstances related to functions, subshells, emulate, etc. Proof-of-concept:

trap 'print -r -- "+$0:$LINENO>$ZSH_DEBUG_CMD" >>trace_file' DEBUG

Or maybe a bit more sophisticated (untested):

zmodload zsh/system
sysopen -a -o create -u xtrace_fd trace_file
trap 'syswrite -o $xtrace_fd "+$0:$LINENO>$ZSH_DEBUG_CMD"' DEBUG

I'm using a very simple workaround which may be useful if you want to debug only a specific function although the same idea can be applied to complete tracing with set -x:

When I need to debug a specific function, say myfunc, I open a child shell with TRACE_FUNC=myfunc zsh -l 2> debug.err.txt while I have set in my ~/.zshrc something along the lines of:

if [ -n "${TRACE_FUNC}" ]; then
    functions -t "$TRACE_FUNC"
fi

You can apply the same idea by putting in your ~/.zshrc the following:

if [ -n "${TRACE_ZSH}" ]; then
    set -x
fi

And spawn the child shell with TRACE_ZSH=1 zsh -l 2> debug.err.txt.

Tags:

Debugging

Zsh