How do http-response track-sc and sc-inc-gpc work?

Hello.

I am trying to get the number of status codes for each domain separated by protocol.

I can get the number of request data in the domain using http-request track-sc.
However, when tested with the config below, the http-response track-sc and http-response sc-inc-gpc do not seem to work correctly.

I would like to know what is wrong in the config and how to use http-response track-sc and http-response sc-inc-gpc correctly.

I would be grateful if you could give me a guide on what is wrong and what needs to be corrected.

config

frontend HTTP

bind        *:80

http-request    set-var(txn.host)   req.hdr(host),lower,field(1,:)

http-request    track-sc0    var(txn.host)  table BK_ALL
http-request    track-sc1    var(txn.host)  table BK_HTTP


http-response   track-sc0    var(txn.host)  table BK_HTTP_23    if   { status ge 200 } { status lt 400 }
http-response   sc-inc-gpc0(0)  if { status ge 200 } { status lt 300 }
http-response   sc-inc-gpc1(0)  if { status ge 300 } { status lt 400 }

http-response   track-sc0    var(txn.host)  table BK_HTTP_45    if   { status ge 400 } { status lt 600 }
http-response   sc-inc-gpc0(0)  if { status ge 400 } { status lt 500 }
http-response   sc-inc-gpc1(0)  if { status ge 500 } { status lt 600 }

default_backend     BK_DEFAULT

frontend HTTPS

bind        *:443       ssl crt-list /etc/haproxy/ssl/cert-list.txt    tls-ticket-keys /etc/haproxy/ssl/tls-ticket.key    alpn h2,http/1.1      npn h2,http/1.1

acl http2  ssl_fc_alpn -i h2
acl http2  ssl_fc_npn  -i h2

http-request    set-var(txn.host)   req.hdr(host),lower,field(1,:)

http-request    track-sc0    var(txn.host)  table BK_ALL
http-request    track-sc1    var(txn.host)  table BK_HTTPS    if   !http2
http-request    track-sc2    var(txn.host)  table BK_HTTP2    if    http2


http-response   track-sc0    var(txn.host)  table BK_HTTPS_23   if   { status ge 200 } { status lt 400 } !http2
http-response   sc-inc-gpc0(0)                      if { status ge 200 } { status lt 300 } !http2
http-response   sc-inc-gpc1(0)                      if { status ge 300 } { status lt 400 } !http2

http-response   track-sc0    var(txn.host)  table BK_HTTPS_45   if   { status ge 400 } { status lt 600 } !http2
http-response   sc-inc-gpc0(0)                      if { status ge 400 } { status lt 500 } !http2
http-response   sc-inc-gpc1(0)                      if { status ge 500 } { status lt 600 } !http2


http-response   track-sc1    var(txn.host)  table BK_HTTP2_23   if   { status ge 200 } { status lt 400 } http2
http-response   sc-inc-gpc0(1)                      if { status ge 200 } { status lt 300 } http2
http-response   sc-inc-gpc1(1)                      if { status ge 300 } { status lt 400 } http2

http-response   track-sc1    var(txn.host)  table BK_HTTP2_45   if   { status ge 400 } { status lt 600 } http2
http-response   sc-inc-gpc0(1)                      if { status ge 400 } { status lt 500 } http2
http-response   sc-inc-gpc1(1)                      if { status ge 500 } { status lt 600 } http2

default_backend     BK_DEFAULT

backend BK_DEFAULT

server localhost 127.0.0.1:8080 check

backend BK_ALL

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,sess_cnt,http_req_cnt,http_err_cnt,bytes_out_cnt

backend BK_HTTP

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,sess_cnt,http_req_cnt,http_err_cnt,bytes_out_cnt

backend BK_HTTP_23

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,gpc0,gpc1

backend BK_HTTP_45

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,gpc0,gpc1

backend BK_HTTPS

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,sess_cnt,http_req_cnt,http_err_cnt,bytes_out_cnt

backend BK_HTTPS_23

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,gpc0,gpc1

backend BK_HTTPS_45

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,gpc0,gpc1

backend BK_HTTP2

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,sess_cnt,http_req_cnt,http_err_cnt,bytes_out_cnt

backend BK_HTTP2_23

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,gpc0,gpc1

backend BK_HTTP2_45

stick-table    type string    len 256    size 10k    expire 7d    store    conn_cnt,gpc0,gpc1

test

[root]# echo “show table BK_ALL” | socat /var/run/haproxy.stat1 stdio
# table: BK_ALL, type: string, size:10240, used:1
0x17e2688: key=test.com use=0 exp=604789122 conn_cnt=3 sess_cnt=0 http_req_cnt=3 http_err_cnt=0 bytes_out_cnt=636

[root]# echo “show table BK_HTTP” | socat /var/run/haproxy.stat1 stdio
# table: BK_HTTP, type: string, size:10240, used:1
0x17e2858: key=test.com use=0 exp=604784378 conn_cnt=3 sess_cnt=0 http_req_cnt=3 http_err_cnt=0 bytes_out_cnt=636

[root]# echo “show table BK_HTTP_23” | socat /var/run/haproxy.stat1 stdio
# table: BK_HTTP_23, type: string, size:10240, used:0

[root]# echo “show table BK_HTTP_45” | socat /var/run/haproxy.stat1 stdio
# table: BK_HTTP_45, type: string, size:10240, used:0

HAProxy version
haproxy -vv

HA-Proxy version 1.9.15 2020/04/02 - https://haproxy.org/
Build options :
TARGET = linux2628
CPU = generic
CC = gcc
CFLAGS = -O2 -g -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-old-style-declaration -Wno-ignored-qualifiers -Wno-clobbered -Wno-missing-field-initializers -Wtype-limits
OPTIONS = USE_DL=1 USE_OPENSSL=1 USE_LUA=1 USE_SYSTEMD=1 USE_PCRE=1

Default settings :
maxconn = 2000, bufsize = 16384, maxrewrite = 1024, maxpollevents = 200

Built with OpenSSL version : OpenSSL 1.1.1g 21 Apr 2020
Running on OpenSSL version : OpenSSL 1.1.1g 21 Apr 2020
OpenSSL library supports TLS extensions : yes
OpenSSL library supports SNI : yes
OpenSSL library supports : TLSv1.0 TLSv1.1 TLSv1.2 TLSv1.3
Built with Lua version : Lua 5.3.5
Built with transparent proxy support using: IP_TRANSPARENT IPV6_TRANSPARENT IP_FREEBIND
Built without compression support (neither USE_ZLIB nor USE_SLZ are set).
Compression algorithms supported : identity(“identity”)
Built with PCRE version : 8.32 2012-11-30
Running on PCRE version : 8.32 2012-11-30
PCRE library supports JIT : no (USE_PCRE_JIT not set)
Encrypted password support via crypt(3): yes
Built with multi-threading support.

Available polling systems :
epoll : pref=300, test result OK
poll : pref=200, test result OK
select : pref=150, test result OK
Total: 3 (3 usable), will use epoll.

Available multiplexer protocols :
(protocols marked as cannot be specified using ‘proto’ keyword)
h2 : mode=HTX side=FE|BE
h2 : mode=HTTP side=FE
: mode=HTX side=FE|BE
: mode=TCP|HTTP side=FE|BE

Available filters :
[SPOE] spoe
[COMP] compression
[CACHE] cache
[TRACE] trace

If you set multiple track-sc rules for a given stick counter only the first rule applies for a given counter/ request. In your case it’s the track-sc rules on the request path.

Please try something like the snippet below.

global
  stats socket /tmp/foo

defaults
  mode http

peers foo
  bind *:12345
  server foo
  table t_23 type string len 64 size 10 expire 10m store conn_cnt,gpc0,gpc1
  table t_45 type string len 64 size 10 expire 10m store conn_cnt,gpc0,gpc1
  table t_http type string len 64 size 10 expire 10m store conn_cnt,sess_cnt,http_req_cnt,http_err_cnt,bytes_out_cnt

frontend fe
  bind *:8080
  http-request set-var(txn.host) hdr(host),field(1,:)
  http-request track-sc2 var(txn.host) table foo/t_http
  default_backend be

backend be
  http-response track-sc0 var(txn.host) table foo/t_23 if { status ge 200 } { status lt 400 }
  http-response track-sc1 var(txn.host) table foo/t_45 if { status ge 400 } { status lt 600 }
  http-response sc-inc-gpc0(0) if { status ge 200 } { status lt 300 }
  http-response sc-inc-gpc1(0) if { status ge 300 } { status lt 400 }
  http-response sc-inc-gpc0(1) if { status ge 400 } { status lt 500 }
  http-response sc-inc-gpc1(1) if { status ge 500 } { status lt 600 }
  server s1 127.0.0.1:8888

listen s1
  bind *:8888
  http-request return status 200 if { path /foo }
  http-request return status 300 if { path /fo }
  http-request return status 400 if { path /f }
  http-request return status 500 if { path / }