#! /bin/bash # Use ps, netstat and p4 monitor to create a combined line of stat info # for each p4 client connection. # To do: # - add an option to select which fields to output from each of ps, # netstat, and p4 monitor. Just like ps's -o | --format <format>. # - rewrite it in python or C, perhaps by adding netstat and p4 monitor # capabilities to a bespoke version of ps. # - add an option for CSV or Json output for P4JsApi dashboards, and others. usage () { me=`basename $0` echo "Usage: $me [ -n <sec> ]" exit 1 } let sec=0 while getopts ":n:" opt; do case "$opt" in n) sec=${OPTARG} ;; *) usage ;; esac done tfile=/tmp/pipe.$USER.$$ cleanup_and_exit () { rm -f $tfile.* exit $? } trap cleanup_and_exit SIGINT if [ ! -p $tfile.ps ]; then mkfifo $tfile.ps; fi if [ ! -p $tfile.ns ]; then mkfifo $tfile.ns; fi if [ ! -p $tfile.p4 ]; then mkfifo $tfile.p4; fi # Get some ps output psinfo () { ps -C p4d --no-headers -o pid,comm,state,%cpu,cputime,etimes,class,pri,nlwp,maj_flt,min_flt |awk '{printf "%06d,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11}' |sort >$tfile.ps } # Get the netstat info for each p4 client connection nsinfo () { sudo netstat -tanp |grep p4d |sed 's/\/p4d//' |awk '{printf "%06d,%s,%s,%s,%s\n", $7, $2, $3, $5, $6}' |sort >$tfile.ns } # Get the p4 monitor info p4info () { p4 monitor show -ale all |awk '{cmd=$8; for (i=9; i<=NF; i++) {cmd = cmd " " $(i)};printf "%06d,%s,%s,%s,%s,%s,%s,%s\n", $1, $2, $3, $4, $5, $6, $7, cmd}' |sort >$tfile.p4 } # Now join it all together # # For the join to work each field must be separated by a "," with no space. # And the first field must be the PID in zero-padded 6 digit format. # p4join () { join -t, $tfile.p4 $tfile.ns | join -t, - $tfile.ps >$tfile.stat } # The combined output looks like this (in CSV format) # # PID Client Client IP S User RHost etime Cmd+args BW Client/Peer IP:Port TCP State , State, %cpu, cputime, etimes, class, pri, nlwp, maj_flt, min_flt # # 010169,p4/2014.2/LINUX26X86_64/962050,10.5.10.100,R,aedgar,warp,00:34:42,client test1,0,0,10.5.10.100:50491,ESTABLISHED,p4d,S,0.0,00:00:00,1792,TS,19,1,0,615 # Filter it for just the info you want # PID, User, P4 Status, Proc State, % CPU, etime, Recv-Q, Send-Q, client IP, Conn State, Client cmd p4filter1 () { cat $tfile.stat |awk 'BEGIN{FS=","}{printf "%6d %s %s %s %s %s %s %s %s %s %s\n", $1, $5, $4, $14, $15, $7, $9, $10, $11, $12, $8}' } p4stat () { # We're currently using fifos so run the stat gathering bits in the background, # p4join() then reads the fifos. psinfo & nsinfo & p4info & p4join p4filter1 } # Run once or loop? if expr $sec == 0 >/dev/null then p4stat else while true; do p4stat; sleep $sec; done fi cleanup_and_exit