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
  -----------------------------------
This commit is contained in:
Willy Tarreau 2023-05-09 20:17:18 +02:00
parent da24bcfad3
commit c147171d57
1 changed files with 180 additions and 0 deletions

180
dev/flags/show-sess-to-flags.sh Executable file
View File

@ -0,0 +1,180 @@
#!/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