haproxy/contrib/trace/trace.awk
Willy Tarreau 1296382d0b CONTRIB: trace: add the possibility to place trace calls in the code
Now any call to trace() in the code will automatically appear interleaved
with the call sequence and timestamped in the trace file. They appear with
a '#' on the 3rd argument (caller's pointer) in order to make them easy to
spot. If the trace functionality is not used, a dmumy weak function is used
instead so that it doesn't require to recompile every time traces are
enabled/disabled.

The trace decoder knows how to deal with these messages, detects them and
indents them similarly to the currently traced function. This can be used
to print function arguments for example.

Note that we systematically flush the log when calling trace() to ensure we
never miss important events, so this may impact performance.

The trace() function uses the same format as printf() so it should be easy
to setup during debugging sessions.
2017-10-24 19:54:25 +02:00

79 lines
2.0 KiB
Awk
Executable File

#!/bin/sh
#
# trace.awk - Fast trace symbol resolver - w@1wt.eu - 2012/05/25
#
# Principle: this program launches reads pointers from a trace file and if not
# found in its cache, it passes them over a pipe to addr2line which is forked
# in a coprocess, then stores the result in the cache.
#
# 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
# 2 of the License, or (at your option) any later version.
#
# usage: $0 exec_file < trace.out
#
if [ $# -lt 1 ]; then
echo "Usage: ${0##*/} exec_file < trace.out"
echo "Example: ${0##*/} ./haproxy < trace.out"
echo "Example: HAPROXY_TRACE=/dev/stdout ./haproxy -f cfg | ${0##*/} ./haproxy"
exit 1
fi
if [ ! -s "$1" ]; then
echo "$1 is not a valid executable file"
exit 1
fi
exec awk -v prog="$1" \
'
BEGIN {
if (cmd == "")
cmd=ENVIRON["ADDR2LINE"];
if (cmd == "")
cmd="addr2line";
if (prog == "")
prog=ENVIRON["PROG"];
cmd=cmd " -f -e " prog;
for (i = 1; i < 100; i++) {
indents[">",i] = indents[">",i-1] "->"
indents[">",i-1] = indents[">",i-1] " "
indents["<",i] = indents["<",i-1] " "
indents["<",i-1] = indents["<",i-1] " "
indents[" ",i] = indents[" ",i-1] "##"
indents[" ",i-1] = indents[" ",i-1] " "
}
}
function getptr(ptr)
{
loc=locs[ptr];
name=names[ptr];
if (loc == "" || name == "") {
print ptr |& cmd;
cmd |& getline name;
cmd |& getline loc;
names[ptr]=name
locs[ptr]=loc
}
}
{
# input format: <timestamp> <level> <caller> <dir> <callee> [<ret>|<args>...]
if ($3 == "#") { # this is a trace comment
printf "%s %s ", $1, indents[" ",$2]
$1=""; $2=""; $3=""
print substr($0,4)
next
}
getptr($3); caller_loc=loc; caller_name=name
getptr($5); callee_loc=loc; callee_name=name
printf "%s %s %s %s %s [%s:%s] %s [%s:%s]\n",
$1, indents[$4,$2], caller_name, $4, callee_name, caller_loc, $3, $4, callee_loc, $5
}
'