haproxy/dev/flags/show-sess-to-flags.sh

181 lines
9.1 KiB
Bash
Raw Normal View History

DEV: flags: add a script to decode most flags in the "show sess all" output This ugly script decodes most flags in the "show sess all" output and summarizes them after each stream in an aligned format that makes it relatively easy to spot the ones of interest. It relies on "flags", and if not found in various places, will replace its output with a copy- pastable command that will produce it. h3/quic are not covered yet. In order to compact the output format, the front and back stream conns and connections are noted "f.sc", "f.co", "f.h1s", "b.co" etc. That's sufficiently understandable and entries are grouped by context anyway. Example of output: 0x7f51a43f7e30: [09/May/2023:20:28:57.183945] id=53704 proto=tcpv4 source=xx.xx.xx.xx:xxxx flags=0x100c4a, conn_retries=0, conn_exp=<NEVER> conn_et=0x000 srv_conn=0x464e4e0, pend_pos=(nil) waiting=0 epoch=0xa2 frontend=public (id=2 mode=http), listener=SSL (id=4) addr=xx.xx.xx.xx:443 backend=static (id=7 mode=http) addr=xx.xx.xx.xx:50916 server=srv1 (id=1) addr=xx.xx.xx.xx:80 task=0x7f51a42190a0 (state=0x00 nice=0 calls=2 rate=0 exp=59s tid=1(1/1) age=0s) txn=0x7f51a4397300 flags=0x43000 meth=1 status=200 req.st=MSG_DONE rsp.st=MSG_DATA req.f=0x4c rsp.f=0x0d scf=0x57af8b0 flags=0x00000482 state=EST endp=CONN,0x7f51a4269fa0,0x04005001 sub=3 rex=59s wex=59s h2s=0x7f51a4269fa0 h2s.id=1 .st=HCR .flg=0x207001 .rxbuf=0@(nil)+0/0 .sc=0x57af8b0(.flg=0x00000482 .app=0x7f51a43f7e30) .sd=0x5832eb0(.flg=0x04005001) .subs=0x57af8c8(ev=3 tl=0x7f51a40dd390 tl.calls=4 tl.ctx=0x57af8b0 tl.fct=sc_conn_io_cb) h2c=0x7f51a44144d0 h2c.st0=FRH .err=0 .maxid=1 .lastid=-1 .flg=0x0200 .nbst=1 .nbsc=1 .fctl_cnt=0 .send_cnt=1 .tree_cnt=1 .orph_cnt=0 .sub=3 .dsi=0 .dbuf=0@(nil)+0/0 .mbuf=[3..4|32],h=[32730@0x57ec920+16431/32768],t=[32730@0x7f51a4322660+16431/32768] .task=0x5722d40 .exp=<NEVER> co0=0x5727120 ctrl=tcpv4 xprt=SSL mux=H2 data=STRM target=LISTENER:0x1cc62d0 flags=0x80000300 fd=30 fd.state=411 updt=0 fd.tmask=0x2 scb=0x7f51a4064710 flags=0x00001211 state=EST endp=CONN,0x7f51a433eb50,0x011c0001 sub=0 rex=59s wex=<NEVER> h1s=0x7f51a433eb50 h1s.flg=0x4094 .sd.flg=0x11c0001 .req.state=MSG_DONE .res.state=MSG_DATA .meth=GET status=200 .sd.flg=0x011c0001 .sc.flg=0x00001211 .sc.app=0x7f51a43f7e30 .subs=(nil) h1c=0x7f51a4218b70 h1c.flg=0x80000020 .sub=0 .ibuf=32704@0x57d48c0+56/32768 .obuf=0@(nil)+0/0 .task=0x7f51a408ebb0 .exp=<NEVER> co1=0x57264e0 ctrl=tcpv4 xprt=RAW mux=H1 data=STRM target=SERVER:0x464e4e0 flags=0x00000300 fd=26 fd.state=10122 updt=0 fd.tmask=0x2 req=0x7f51a43f7e50 (f=0x21840000 an=0x48000 pipe=0 tofwd=0 total=142) an_exp=<NEVER> buf=0x7f51a43f7e58 data=(nil) o=0 p=0 i=0 size=0 htx=0x818e40 flags=0x0 size=0 data=0 used=0 wrap=NO extra=0 res=0x7f51a43f7ea0 (f=0xa0040101 an=0x24000000 pipe=0 tofwd=-1 total=163472) an_exp=<NEVER> buf=0x7f51a43f7ea8 data=0x7f51a43c2f50 o=16328 p=16328 i=16440 size=32768 htx=0x7f51a43c2f50 flags=0x0 size=32720 data=16328 used=1 wrap=NO extra=3852188 ----------------------------------- task.state 0 0 txn.meth 1 GET txn.flg 0x43000 TX_NOT_FIRST TX_CACHE_COOK TX_CACHEABLE txn.req.flg 0x4c HTTP_MSGF_BODYLESS HTTP_MSGF_VER_11 HTTP_MSGF_XFER_LEN txn.rsp.flg 0xd HTTP_MSGF_VER_11 HTTP_MSGF_XFER_LEN HTTP_MSGF_CNT_LEN f.sc.flg 0x482 SC_FL_RCV_ONCE SC_FL_WONT_READ SC_FL_EOI f.sc.sd.flg 0x4005001 SE_FL_HAVE_NO_DATA SE_FL_EOI SE_FL_NOT_FIRST SE_FL_T_MUX f.h2s.flg 0x207001 H2_SF_MORE_HTX_DATA H2_SF_HEADERS_RCVD H2_SF_OUTGOING_DATA H2_SF_HEADERS_SENT H2_SF_ES_RCVD f.h2s.sd.flg 0x4005001 SE_FL_HAVE_NO_DATA SE_FL_EOI SE_FL_NOT_FIRST SE_FL_T_MUX f.h2c.flg 0x200 H2_CF_DEM_SHORT_READ f.co.flg 0x80000300 CO_FL_XPRT_TRACKED CO_FL_XPRT_READY CO_FL_CTRL_READY f.co.fd.st 0x19b FD_POLL_IN FD_EV_ERR_RW FD_EV_READY_R FD_EV_ACTIVE_W FD_EV_ACTIVE_R 0x8 b.sc.flg 0x1211 SC_FL_SND_NEVERWAIT SC_FL_NEED_ROOM SC_FL_NOHALF SC_FL_ISBACK b.sc.sd.flg 0x11c0001 SE_FL_WAIT_DATA SE_FL_WANT_ROOM SE_FL_RCV_MORE SE_FL_MAY_SPLICE SE_FL_T_MUX b.h1s.sd.flg 0x11c0001 SE_FL_WAIT_DATA SE_FL_WANT_ROOM SE_FL_RCV_MORE SE_FL_MAY_SPLICE SE_FL_T_MUX b.h1s.flg 0x4094 H1S_F_HAVE_O_CONN H1S_F_NOT_FIRST H1S_F_WANT_KAL H1S_F_RX_CONGESTED b.h1c.flg 0x80000020 H1C_F_IS_BACK H1C_F_IN_FULL b.co.flg 0x300 CO_FL_XPRT_READY CO_FL_CTRL_READY b.co.fd.st 0x278a FD_POLL_OUT FD_POLL_PRI FD_POLL_IN FD_EV_ERR_RW FD_EV_READY_R 0x2008 req.flg 0x21840000 CF_FLT_ANALYZE CF_DONT_READ CF_AUTO_CONNECT CF_WROTE_DATA req.ana 0x48000 AN_REQ_FLT_END AN_REQ_HTTP_XFER_BODY req.htx.flg 0 0 res.flg 0xa0040101 CF_ISRESP CF_FLT_ANALYZE CF_WROTE_DATA CF_WRITE_EVENT CF_READ_EVENT res.ana 0x24000000 AN_RES_FLT_END AN_RES_HTTP_XFER_BODY res.htx.flg 0 0 -----------------------------------
2023-05-09 18:17:18 +00:00
#!/usr/bin/env bash
# This script is used to resolve various flags that appear on "show sess all".
# All identified ones will be appended at the end, with a short name and their
# value, followed by either the value resolved by "flags" when it's found, or
# by the copy-pastable command to use to resolve them. The path to FLAGS is
# searched in this order: 1) $FLAGS, 2) in the path, 3) dev/flags/flags, 4)
# in the same directory as the script.
#
# This script is horrendous, but it's not a reason for making it even more
# disgusting. The big regex flag mapping mess at the end is readable on a
# large screen and it's easier to spot mistakes using this aligned format,
# so please preserve this as much as possible and avoid multi-line formats.
#
# The append_* functions provide different variants that are still commented
# out. It's mostly a matter of taste, they're equivalent.
#
# Usage: socat /path/to/socket - <<< "show sess all" | ./$0 > output
# look for "flags in path then in dev/flags/flags then next to the script"
FLAGS="${FLAGS:-$(command -v flags)}"
if [ -z "$FLAGS" ]; then
if [ -e dev/flags/flags ]; then
FLAGS=dev/flags/flags;
elif [ -e "${0%/*}/flags" ]; then
FLAGS="${0%/*}/flags"
else
# OK still not found,let's write a copy-pastable command
FLAGS="echo ./flags"
fi
fi
HTTP_METH=( "OPTIONS" "GET" "HEAD" "POST" "PUT" "DELETE" "TRACE" "CONNECT" "OTHER" )
out=( )
decode=( )
# returns str $2 and $3 concatenated with enough spaces in between so that the
# total size doesn't exceed $1 chars, but always inserts at least one space.
justify() {
local pad=" "
local str
while str="${2}${pad}${3}" && [ ${#str} -le $1 ]; do
pad="${pad} "
done
echo -n "$str"
}
# remove spaces at the beginning and end in "$1"
trim() {
while [ -n "$1" -a -z "${1## *}" ]; do
set -- "${1# }"
done
while [ -n "$1" -a -z "${1%%* }" ]; do
set -- "${1% }"
done
echo -n "$1"
}
# pass $1=ctx name, $2=argname, $3=value, append the decoded line to decode[]
append_flag() {
set -- "$1" "$2" "$(printf "%#x" $3)"
#decode[${#decode[@]}]="$1=$3 [ $(set -- $($FLAGS $2 $3 | cut -f2- -d=); echo $*) ]"
#decode[${#decode[@]}]="$(printf "%-14s %10s %s" $1 $3 "$(set -- $($FLAGS $2 $3 | cut -f2- -d=); echo $*)")"
#decode[${#decode[@]}]="$(justify 22 "$1" "$3") $(set -- $($FLAGS $2 $3 | cut -f2- -d=); echo $*)"
decode[${#decode[@]}]="$(justify 22 "$1" "$3") $(set -- $($FLAGS $2 $3 | cut -f2- -d= | tr -d '|'); echo "$*")"
#decode[${#decode[@]}]="$(justify 22 "$1" "$3") $(set -- $($FLAGS $2 $(printf "%#x" $3) | cut -f2- -d= | tr -d '|'); echo "$*")"
#decode[${#decode[@]}]="$(justify 22 "$1" "$3") $(trim "$($FLAGS $2 $3 | cut -f2- -d= | tr -d '|')")"
#decode[${#decode[@]}]="$(justify 22 "$1" "$3") $(trim "$($FLAGS $2 $3 | cut -f2- -d= | tr -d ' ')")"
}
# pass $1=ctx name, $2=value, $3=decoded value
append_str() {
#decode[${#decode[@]}]="$1=$2 [ $3 ]"
#decode[${#decode[@]}]="$(printf "%-14s %10s %s" $1 $2 $3)"
decode[${#decode[@]}]="$(justify 22 "$1" "$2") $(trim $3)"
}
# dump and reset the buffers
dump_and_reset() {
local line
line=0
while [ $line -lt ${#out[@]} ]; do
echo "${out[$line]}"
((line++))
done
[ ${#decode[@]} -eq 0 ] || echo " -----------------------------------"
line=0
while [ $line -lt ${#decode[@]} ]; do
echo " ${decode[$line]}"
((line++, total++))
done
[ ${#decode[@]} -eq 0 ] || echo " -----------------------------------"
decode=( )
out=( )
}
### main entry point
ctx=top
while read -r; do
[ "$REPLY" != "EOF" ] || break # for debugging
if [[ "$REPLY" =~ ^[[:blank:]]*task= ]]; then
ctx=task;
elif [[ "$REPLY" =~ ^[[:blank:]]*txn= ]]; then
ctx=txn;
elif [[ "$REPLY" =~ ^[[:blank:]]*scf= ]]; then
ctx=scf;
elif [[ "$REPLY" =~ ^[[:blank:]]*co0= ]]; then
ctx=cof;
elif [[ "$REPLY" =~ ^[[:blank:]]*app0= ]]; then
ctx=appf;
elif [[ "$REPLY" =~ ^[[:blank:]]*req= ]]; then
ctx=req;
elif [[ "$REPLY" =~ ^[[:blank:]]*scb= ]]; then
ctx=scb;
elif [[ "$REPLY" =~ ^[[:blank:]]*co1= ]]; then
ctx=cob;
elif [[ "$REPLY" =~ ^[[:blank:]]*app1= ]]; then
ctx=appb;
elif [[ "$REPLY" =~ ^[[:blank:]]*res= ]]; then
ctx=res;
elif [[ "$REPLY" =~ ^0x ]]; then
# here we dump what we have and we reset
dump_and_reset
ctx=top;
fi
if [ $ctx = task ]; then
! [[ "$REPLY" =~ \(state=([^[:blank:]]*) ]] || append_flag task.state task "${BASH_REMATCH[1]}"
elif [ $ctx = txn ]; then
! [[ "$REPLY" =~ [[:blank:]]meth=([^[:blank:]]*) ]] || append_str txn.meth "${BASH_REMATCH[1]}" "${HTTP_METH[$((${BASH_REMATCH[1]}))]}"
! [[ "$REPLY" =~ [[:blank:]]flags=([^[:blank:]]*) ]] || append_flag txn.flg txn "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]req\.f=([^[:blank:]]*) ]] || append_flag txn.req.flg hmsg "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]rsp\.f=([^[:blank:]]*) ]] || append_flag txn.rsp.flg hmsg "${BASH_REMATCH[1]}"
elif [ $ctx = scf ]; then
! [[ "$REPLY" =~ [[:blank:]]flags=([^[:blank:]]*) ]] || append_flag f.sc.flg sc "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]endp=[[:alnum:]]*,[[:alnum:]]*,([^[:blank:]]*) ]] || append_flag f.sc.sd.flg sd "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h1s.*\.sd\.flg=([^[:blank:]]*) ]] || append_flag f.h1s.sd.flg sd "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h1s\.flg=([^[:blank:]]*) ]] || append_flag f.h1s.flg h1s "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h1c\.flg=([^[:blank:]]*) ]] || append_flag f.h1c.flg h1c "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ ^[[:blank:]]*\.sc=.*\.flg=.*\.app=.*\.sd=[^=]*\.flg=([^[:blank:]]*) ]] || append_flag f.h2s.sd.flg sd "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h2s.*\.flg=([^[:blank:]]*) ]] || append_flag f.h2s.flg h2s "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h2c.*\.flg=([^[:blank:]]*) ]] || append_flag f.h2c.flg h2c "${BASH_REMATCH[1]}"
elif [ $ctx = cof ]; then
! [[ "$REPLY" =~ [[:blank:]]flags=([^[:blank:]]*) ]] || append_flag f.co.flg conn "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]fd.state=([^[:blank:]]*) ]] || append_flag f.co.fd.st fd "${BASH_REMATCH[1]}"
elif [ $ctx = req ]; then
! [[ "$REPLY" =~ [[:blank:]]\(f=([^[:blank:]]*) ]] || append_flag req.flg chn "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]an=([^[:blank:]]*) ]] || append_flag req.ana ana "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]htx.*flags=([^[:blank:]]*) ]] || append_flag req.htx.flg htx "${BASH_REMATCH[1]}"
elif [ $ctx = scb ]; then
! [[ "$REPLY" =~ [[:blank:]]flags=([^[:blank:]]*) ]] || append_flag b.sc.flg sc "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]endp=[[:alnum:]]*,[[:alnum:]]*,([^[:blank:]]*) ]] || append_flag b.sc.sd.flg sd "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h1s.*\.sd\.flg=([^[:blank:]]*) ]] || append_flag b.h1s.sd.flg sd "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h1s\.flg=([^[:blank:]]*) ]] || append_flag b.h1s.flg h1s "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h1c\.flg=([^[:blank:]]*) ]] || append_flag b.h1c.flg h1c "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ ^[[:blank:]]*\.sc=.*\.flg=.*\.app=.*\.sd=[^=]*\.flg=([^[:blank:]]*) ]] || append_flag b.h2s.sd.flg sd "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h2s.*\.flg=([^[:blank:]]*) ]] || append_flag b.h2s.flg h2s "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]h2c.*\.flg=([^[:blank:]]*) ]] || append_flag b.h2c.flg h2c "${BASH_REMATCH[1]}"
elif [ $ctx = cob ]; then
! [[ "$REPLY" =~ [[:blank:]]flags=([^[:blank:]]*) ]] || append_flag b.co.flg conn "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]fd.state=([^[:blank:]]*) ]] || append_flag b.co.fd.st fd "${BASH_REMATCH[1]}"
elif [ $ctx = res ]; then
! [[ "$REPLY" =~ [[:blank:]]\(f=([^[:blank:]]*) ]] || append_flag res.flg chn "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]an=([^[:blank:]]*) ]] || append_flag res.ana ana "${BASH_REMATCH[1]}"
! [[ "$REPLY" =~ [[:blank:]]htx.*flags=([^[:blank:]]*) ]] || append_flag res.htx.flg htx "${BASH_REMATCH[1]}"
fi
out[${#out[@]}]="$REPLY"
done
# dump the last stream
dump_and_reset