1
0
Fork 0

Adding upstream version 1.34.4.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-24 07:26:29 +02:00
parent e393c3af3f
commit 4978089aab
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
4963 changed files with 677545 additions and 0 deletions

View file

@ -0,0 +1,128 @@
# HAProxy Input Plugin
This plugin gathers statistics of [HAProxy][haproxy] servers using sockets or
the HTTP protocol.
⭐ Telegraf v0.1.5
🏷️ network, server
💻 all
[haproxy]: http://www.haproxy.org/
## Global configuration options <!-- @/docs/includes/plugin_config.md -->
In addition to the plugin-specific configuration settings, plugins support
additional global and plugin configuration settings. These settings are used to
modify metrics, tags, and field or create aliases and configure ordering, etc.
See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
[CONFIGURATION.md]: ../../../docs/CONFIGURATION.md#plugins
## Configuration
```toml @sample.conf
# Read metrics of HAProxy, via stats socket or http endpoints
[[inputs.haproxy]]
## List of stats endpoints. Metrics can be collected from both http and socket
## endpoints. Examples of valid endpoints:
## - http://myhaproxy.com:1936/haproxy?stats
## - https://myhaproxy.com:8000/stats
## - socket:/run/haproxy/admin.sock
## - /run/haproxy/*.sock
## - tcp://127.0.0.1:1936
##
## Server addresses not starting with 'http://', 'https://', 'tcp://' will be
## treated as possible sockets. When specifying local socket, glob patterns are
## supported.
servers = ["http://myhaproxy.com:1936/haproxy?stats"]
## By default, some of the fields are renamed from what haproxy calls them.
## Setting this option to true results in the plugin keeping the original
## field names.
# keep_field_names = false
## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Use TLS but skip chain & host verification
# insecure_skip_verify = false
```
### HAProxy Configuration
The following information may be useful when getting started, but please consult
the HAProxy documentation for complete and up to date instructions.
The [`stats enable`][4] option can be used to add unauthenticated access over
HTTP using the default settings. To enable the unix socket begin by reading
about the [`stats socket`][5] option.
[4]: https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#4-stats%20enable
[5]: https://cbonte.github.io/haproxy-dconv/1.8/configuration.html#3.1-stats%20socket
### servers
Server addresses must explicitly start with 'http' if you wish to use HAProxy
status page. Otherwise, addresses will be assumed to be an UNIX socket and any
protocol (if present) will be discarded.
When using socket names, wildcard expansion is supported so plugin can gather
stats from multiple sockets at once.
To use HTTP Basic Auth add the username and password in the userinfo section of
the URL: `http://user:password@1.2.3.4/haproxy?stats`. The credentials are sent
via the `Authorization` header and not using the request URL.
### keep_field_names
By default, some of the fields are renamed from what haproxy calls them.
Setting the `keep_field_names` parameter to `true` will result in the plugin
keeping the original field names.
The following renames are made:
- `pxname` -> `proxy`
- `svname` -> `sv`
- `act` -> `active_servers`
- `bck` -> `backup_servers`
- `cli_abrt` -> `cli_abort`
- `srv_abrt` -> `srv_abort`
- `hrsp_1xx` -> `http_response.1xx`
- `hrsp_2xx` -> `http_response.2xx`
- `hrsp_3xx` -> `http_response.3xx`
- `hrsp_4xx` -> `http_response.4xx`
- `hrsp_5xx` -> `http_response.5xx`
- `hrsp_other` -> `http_response.other`
## Metrics
For more details about collected metrics reference the [HAProxy CSV format
documentation][6].
- haproxy
- tags:
- `server` - address of the server data was gathered from
- `proxy` - proxy name
- `sv` - service name
- `type` - proxy session type
- fields:
- `status` (string)
- `check_status` (string)
- `last_chk` (string)
- `mode` (string)
- `tracked` (string)
- `agent_status` (string)
- `last_agt` (string)
- `addr` (string)
- `cookie` (string)
- `lastsess` (int)
- **all other stats** (int)
[6]: https://cbonte.github.io/haproxy-dconv/1.8/management.html#9.1
## Example Output
```text
haproxy,server=/run/haproxy/admin.sock,proxy=public,sv=FRONTEND,type=frontend http_response.other=0i,req_rate_max=1i,comp_byp=0i,status="OPEN",rate_lim=0i,dses=0i,req_rate=0i,comp_rsp=0i,bout=9287i,comp_in=0i,mode="http",smax=1i,slim=2000i,http_response.1xx=0i,conn_rate=0i,dreq=0i,ereq=0i,iid=2i,rate_max=1i,http_response.2xx=1i,comp_out=0i,intercepted=1i,stot=2i,pid=1i,http_response.5xx=1i,http_response.3xx=0i,http_response.4xx=0i,conn_rate_max=1i,conn_tot=2i,dcon=0i,bin=294i,rate=0i,sid=0i,req_tot=2i,scur=0i,dresp=0i 1513293519000000000
```

View file

@ -0,0 +1,283 @@
//go:generate ../../../tools/readme_config_includer/generator
package haproxy
import (
_ "embed"
"encoding/csv"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/common/tls"
"github.com/influxdata/telegraf/plugins/inputs"
)
//go:embed sample.conf
var sampleConfig string
var (
typeNames = []string{"frontend", "backend", "server", "listener"}
fieldRenames = map[string]string{
"pxname": "proxy",
"svname": "sv",
"act": "active_servers",
"bck": "backup_servers",
"cli_abrt": "cli_abort",
"srv_abrt": "srv_abort",
"hrsp_1xx": "http_response.1xx",
"hrsp_2xx": "http_response.2xx",
"hrsp_3xx": "http_response.3xx",
"hrsp_4xx": "http_response.4xx",
"hrsp_5xx": "http_response.5xx",
"hrsp_other": "http_response.other",
}
)
// CSV format: https://cbonte.github.io/haproxy-dconv/1.5/configuration.html#9.1
type HAProxy struct {
Servers []string `toml:"servers"`
KeepFieldNames bool `toml:"keep_field_names"`
Username string `toml:"username"`
Password string `toml:"password"`
tls.ClientConfig
client *http.Client
}
func (*HAProxy) SampleConfig() string {
return sampleConfig
}
func (h *HAProxy) Gather(acc telegraf.Accumulator) error {
if len(h.Servers) == 0 {
return h.gatherServer("http://127.0.0.1:1936/haproxy?stats", acc)
}
endpoints := make([]string, 0, len(h.Servers))
for _, endpoint := range h.Servers {
if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") || strings.HasPrefix(endpoint, "tcp://") {
endpoints = append(endpoints, endpoint)
continue
}
socketPath := getSocketAddr(endpoint)
matches, err := filepath.Glob(socketPath)
if err != nil {
return err
}
if len(matches) == 0 {
endpoints = append(endpoints, socketPath)
} else {
endpoints = append(endpoints, matches...)
}
}
var wg sync.WaitGroup
wg.Add(len(endpoints))
for _, server := range endpoints {
go func(serv string) {
defer wg.Done()
if err := h.gatherServer(serv, acc); err != nil {
acc.AddError(err)
}
}(server)
}
wg.Wait()
return nil
}
func (h *HAProxy) gatherServerSocket(addr string, acc telegraf.Accumulator) error {
var network, address string
if strings.HasPrefix(addr, "tcp://") {
network = "tcp"
address = strings.TrimPrefix(addr, "tcp://")
} else {
network = "unix"
address = getSocketAddr(addr)
}
c, err := net.Dial(network, address)
if err != nil {
return fmt.Errorf("could not connect to '%s://%s': %w", network, address, err)
}
_, errw := c.Write([]byte("show stat\n"))
if errw != nil {
return fmt.Errorf("could not write to socket '%s://%s': %w", network, address, errw)
}
return h.importCsvResult(c, acc, address)
}
func (h *HAProxy) gatherServer(addr string, acc telegraf.Accumulator) error {
if !strings.HasPrefix(addr, "http") {
return h.gatherServerSocket(addr, acc)
}
if h.client == nil {
tlsCfg, err := h.ClientConfig.TLSConfig()
if err != nil {
return err
}
tr := &http.Transport{
ResponseHeaderTimeout: 3 * time.Second,
TLSClientConfig: tlsCfg,
}
client := &http.Client{
Transport: tr,
Timeout: 4 * time.Second,
}
h.client = client
}
if !strings.HasSuffix(addr, ";csv") {
addr += "/;csv"
}
u, err := url.Parse(addr)
if err != nil {
return fmt.Errorf("unable parse server address %q: %w", addr, err)
}
req, err := http.NewRequest("GET", addr, nil)
if err != nil {
return fmt.Errorf("unable to create new request %q: %w", addr, err)
}
if u.User != nil {
p, _ := u.User.Password()
req.SetBasicAuth(u.User.Username(), p)
u.User = &url.Userinfo{}
addr = u.String()
}
if h.Username != "" || h.Password != "" {
req.SetBasicAuth(h.Username, h.Password)
}
res, err := h.client.Do(req)
if err != nil {
return fmt.Errorf("unable to connect to haproxy server %q: %w", addr, err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
return fmt.Errorf("unable to get valid stat result from %q, http response code : %d", addr, res.StatusCode)
}
if err := h.importCsvResult(res.Body, acc, u.Host); err != nil {
return fmt.Errorf("unable to parse stat result from %q: %w", addr, err)
}
return nil
}
func getSocketAddr(sock string) string {
socketAddr := strings.Split(sock, ":")
if len(socketAddr) >= 2 {
return socketAddr[1]
}
return socketAddr[0]
}
func (h *HAProxy) importCsvResult(r io.Reader, acc telegraf.Accumulator, host string) error {
csvr := csv.NewReader(r)
now := time.Now()
headers, err := csvr.Read()
if err != nil {
return err
}
if len(headers[0]) <= 2 || headers[0][:2] != "# " {
return errors.New("did not receive standard haproxy headers")
}
headers[0] = headers[0][2:]
for {
row, err := csvr.Read()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return err
}
fields := make(map[string]interface{})
tags := map[string]string{
"server": host,
}
if len(row) != len(headers) {
return fmt.Errorf("number of columns does not match number of headers. headers=%d columns=%d", len(headers), len(row))
}
for i, v := range row {
if v == "" {
continue
}
colName := headers[i]
fieldName := colName
if !h.KeepFieldNames {
if fieldRename, ok := fieldRenames[colName]; ok {
fieldName = fieldRename
}
}
switch colName {
case "pxname", "svname":
tags[fieldName] = v
case "type":
vi, err := strconv.ParseInt(v, 10, 64)
if err != nil {
return fmt.Errorf("unable to parse type value %q", v)
}
if vi >= int64(len(typeNames)) {
return fmt.Errorf("received unknown type value: %d", vi)
}
tags[fieldName] = typeNames[vi]
case "check_desc", "agent_desc":
// do nothing. These fields are just a more verbose description of the check_status & agent_status fields
case "status", "check_status", "last_chk", "mode", "tracked", "agent_status", "last_agt", "addr", "cookie":
// these are string fields
fields[fieldName] = v
case "lastsess":
vi, err := strconv.ParseInt(v, 10, 64)
if err != nil {
// TODO log the error. And just once (per column) so we don't spam the log
continue
}
fields[fieldName] = vi
default:
vi, err := strconv.ParseUint(v, 10, 64)
if err != nil {
// TODO log the error. And just once (per column) so we don't spam the log
continue
}
fields[fieldName] = vi
}
}
acc.AddFields("haproxy", fields, tags, now)
}
return err
}
func init() {
inputs.Add("haproxy", func() telegraf.Input {
return &HAProxy{}
})
}

View file

@ -0,0 +1,344 @@
package haproxy
import (
"crypto/rand"
"encoding/binary"
"fmt"
"net"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf/testutil"
)
func serverSocket(l net.Listener) {
for {
conn, err := l.Accept()
if err != nil {
return
}
go func(c net.Conn) {
defer c.Close()
buf := make([]byte, 1024)
n, err := c.Read(buf)
if err != nil {
return
}
data := buf[:n]
if string(data) == "show stat\n" {
c.Write(csvOutputSample) //nolint:errcheck // we return anyway
}
}(conn)
}
}
func TestHaproxyGeneratesMetricsWithAuthentication(t *testing.T) {
// We create a fake server to return test data
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
username, password, ok := r.BasicAuth()
if !ok {
w.WriteHeader(http.StatusNotFound)
if _, err := fmt.Fprint(w, "Unauthorized"); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
return
}
if username == "user" && password == "password" {
if _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
} else {
w.WriteHeader(http.StatusNotFound)
if _, err := fmt.Fprint(w, "Unauthorized"); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
}
}))
defer ts.Close()
// Now we tested again above server, with our authentication data
r := &HAProxy{
Servers: []string{strings.Replace(ts.URL, "http://", "http://user:password@", 1)},
}
var acc testutil.Accumulator
err := r.Gather(&acc)
require.NoError(t, err)
tags := map[string]string{
"server": ts.Listener.Addr().String(),
"proxy": "git",
"sv": "www",
"type": "server",
}
fields := haproxyGetFieldValues()
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
// Here, we should get error because we don't pass authentication data
r = &HAProxy{
Servers: []string{ts.URL},
}
require.NoError(t, r.Gather(&acc))
require.NotEmpty(t, acc.Errors)
}
func TestHaproxyGeneratesMetricsWithoutAuthentication(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
}))
defer ts.Close()
r := &HAProxy{
Servers: []string{ts.URL},
}
var acc testutil.Accumulator
require.NoError(t, r.Gather(&acc))
tags := map[string]string{
"server": ts.Listener.Addr().String(),
"proxy": "git",
"sv": "www",
"type": "server",
}
fields := haproxyGetFieldValues()
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
}
func TestHaproxyGeneratesMetricsUsingSocket(t *testing.T) {
var randomNumber int64
var sockets [5]net.Listener
// The Maximum length of the socket path is 104/108 characters, path created with t.TempDir() is too long for some cases
// (it combines test name with subtest name and some random numbers in the path). Therefore, in this case, it is safer to stick with `os.MkdirTemp()`.
//nolint:usetesting // Ignore "os.TempDir() could be replaced by t.TempDir() in TestHaproxyGeneratesMetricsUsingSocket" finding.
tempDir := os.TempDir()
_globmask := filepath.Join(tempDir, "test-haproxy*.sock")
_badmask := filepath.Join(tempDir, "test-fail-haproxy*.sock")
for i := 0; i < 5; i++ {
require.NoError(t, binary.Read(rand.Reader, binary.LittleEndian, &randomNumber))
sockname := filepath.Join(tempDir, fmt.Sprintf("test-haproxy%d.sock", randomNumber))
sock, err := net.Listen("unix", sockname)
require.NoError(t, err, "Cannot initialize socket")
sockets[i] = sock
defer sock.Close() //nolint:revive,gocritic // done on purpose, closing will be executed properly
go serverSocket(sock)
}
r := &HAProxy{
Servers: []string{_globmask},
}
var acc testutil.Accumulator
err := r.Gather(&acc)
require.NoError(t, err)
fields := haproxyGetFieldValues()
for _, sock := range sockets {
tags := map[string]string{
"server": getSocketAddr(sock.Addr().String()),
"proxy": "git",
"sv": "www",
"type": "server",
}
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
}
// This mask should not match any socket
r.Servers = []string{_badmask}
require.NoError(t, r.Gather(&acc))
require.NotEmpty(t, acc.Errors)
}
func TestHaproxyGeneratesMetricsUsingTcp(t *testing.T) {
l, err := net.Listen("tcp", "localhost:8192")
if err != nil {
t.Fatal(err)
}
defer l.Close()
go serverSocket(l)
r := &HAProxy{
Servers: []string{"tcp://" + l.Addr().String()},
}
var acc testutil.Accumulator
require.NoError(t, r.Gather(&acc))
fields := haproxyGetFieldValues()
tags := map[string]string{
"server": l.Addr().String(),
"proxy": "git",
"sv": "www",
"type": "server",
}
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
require.NoError(t, r.Gather(&acc))
}
// When not passing server config, we default to localhost
// We just want to make sure we did request stat from localhost
func TestHaproxyDefaultGetFromLocalhost(t *testing.T) {
r := &HAProxy{}
var acc testutil.Accumulator
err := r.Gather(&acc)
require.Error(t, err)
require.Contains(t, err.Error(), "127.0.0.1:1936/haproxy?stats/;csv")
}
func TestHaproxyKeepFieldNames(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
if _, err := fmt.Fprint(w, string(csvOutputSample)); err != nil {
w.WriteHeader(http.StatusInternalServerError)
t.Error(err)
return
}
}))
defer ts.Close()
r := &HAProxy{
Servers: []string{ts.URL},
KeepFieldNames: true,
}
var acc testutil.Accumulator
require.NoError(t, r.Gather(&acc))
tags := map[string]string{
"server": ts.Listener.Addr().String(),
"pxname": "git",
"svname": "www",
"type": "server",
}
fields := haproxyGetFieldValues()
fields["act"] = fields["active_servers"]
delete(fields, "active_servers")
fields["bck"] = fields["backup_servers"]
delete(fields, "backup_servers")
fields["cli_abrt"] = fields["cli_abort"]
delete(fields, "cli_abort")
fields["srv_abrt"] = fields["srv_abort"]
delete(fields, "srv_abort")
fields["hrsp_1xx"] = fields["http_response.1xx"]
delete(fields, "http_response.1xx")
fields["hrsp_2xx"] = fields["http_response.2xx"]
delete(fields, "http_response.2xx")
fields["hrsp_3xx"] = fields["http_response.3xx"]
delete(fields, "http_response.3xx")
fields["hrsp_4xx"] = fields["http_response.4xx"]
delete(fields, "http_response.4xx")
fields["hrsp_5xx"] = fields["http_response.5xx"]
delete(fields, "http_response.5xx")
fields["hrsp_other"] = fields["http_response.other"]
delete(fields, "http_response.other")
acc.AssertContainsTaggedFields(t, "haproxy", fields, tags)
}
func mustReadSampleOutput() []byte {
filePath := "testdata/sample_output.csv"
data, err := os.ReadFile(filePath)
if err != nil {
panic(fmt.Errorf("could not read from file %s: %w", filePath, err))
}
return data
}
func haproxyGetFieldValues() map[string]interface{} {
fields := map[string]interface{}{
"active_servers": uint64(1),
"backup_servers": uint64(0),
"bin": uint64(5228218),
"bout": uint64(303747244),
"check_code": uint64(200),
"check_duration": uint64(3),
"check_fall": uint64(3),
"check_health": uint64(4),
"check_rise": uint64(2),
"check_status": "L7OK",
"chkdown": uint64(84),
"chkfail": uint64(559),
"cli_abort": uint64(690),
"ctime": uint64(1),
"downtime": uint64(3352),
"dresp": uint64(0),
"econ": uint64(0),
"eresp": uint64(21),
"http_response.1xx": uint64(0),
"http_response.2xx": uint64(5668),
"http_response.3xx": uint64(8710),
"http_response.4xx": uint64(140),
"http_response.5xx": uint64(0),
"http_response.other": uint64(0),
"iid": uint64(4),
"last_chk": "OK",
"lastchg": uint64(1036557),
"lastsess": int64(1342),
"lbtot": uint64(9481),
"mode": "http",
"pid": uint64(1),
"qcur": uint64(0),
"qmax": uint64(0),
"qtime": uint64(1268),
"rate": uint64(0),
"rate_max": uint64(2),
"rtime": uint64(2908),
"sid": uint64(1),
"scur": uint64(0),
"slim": uint64(2),
"smax": uint64(2),
"srv_abort": uint64(0),
"status": "UP",
"stot": uint64(14539),
"ttime": uint64(4500),
"weight": uint64(1),
"wredis": uint64(0),
"wretr": uint64(0),
}
return fields
}
// Can obtain from official haproxy demo: 'http://demo.haproxy.org/;csv'
var csvOutputSample = mustReadSampleOutput()

View file

@ -0,0 +1,26 @@
# Read metrics of HAProxy, via stats socket or http endpoints
[[inputs.haproxy]]
## List of stats endpoints. Metrics can be collected from both http and socket
## endpoints. Examples of valid endpoints:
## - http://myhaproxy.com:1936/haproxy?stats
## - https://myhaproxy.com:8000/stats
## - socket:/run/haproxy/admin.sock
## - /run/haproxy/*.sock
## - tcp://127.0.0.1:1936
##
## Server addresses not starting with 'http://', 'https://', 'tcp://' will be
## treated as possible sockets. When specifying local socket, glob patterns are
## supported.
servers = ["http://myhaproxy.com:1936/haproxy?stats"]
## By default, some of the fields are renamed from what haproxy calls them.
## Setting this option to true results in the plugin keeping the original
## field names.
# keep_field_names = false
## Optional TLS Config
# tls_ca = "/etc/telegraf/ca.pem"
# tls_cert = "/etc/telegraf/cert.pem"
# tls_key = "/etc/telegraf/key.pem"
## Use TLS but skip chain & host verification
# insecure_skip_verify = false

View file

@ -0,0 +1,15 @@
# pxname,svname,qcur,qmax,scur,smax,slim,stot,bin,bout,dreq,dresp,ereq,econ,eresp,wretr,wredis,status,weight,act,bck,chkfail,chkdown,lastchg,downtime,qlimit,pid,iid,sid,throttle,lbtot,tracked,type,rate,rate_lim,rate_max,check_status,check_code,check_duration,hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,req_rate,req_rate_max,req_tot,cli_abrt,srv_abrt,comp_in,comp_out,comp_byp,comp_rsp,lastsess,last_chk,last_agt,qtime,ctime,rtime,ttime,agent_status,agent_code,agent_duration,check_desc,agent_desc,check_rise,check_fall,check_health,agent_rise,agent_fall,agent_health,addr,cookie,mode,algo,conn_rate,conn_rate_max,conn_tot,intercepted,dcon,dses,
http-in,FRONTEND,,,3,100,100,2639994,813557487,65937668635,505252,0,47567,,,,,OPEN,,,,,,,,,1,2,0,,,,0,1,0,157,,,,0,1514640,606647,136264,496535,14948,,1,155,2754255,,,36370569635,17435137766,0,642264,,,,,,,,,,,,,,,,,,,,,http,,1,157,2649922,339471,0,0,
http-in,IPv4-direct,,,3,41,100,349801,57445827,1503928881,269899,0,287,,,,,OPEN,,,,,,,,,1,2,1,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,
http-in,IPv4-cached,,,0,33,100,1786155,644395819,57905460294,60511,0,1,,,,,OPEN,,,,,,,,,1,2,2,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,
http-in,IPv6-direct,,,0,100,100,325619,92414745,6205208728,3399,0,47279,,,,,OPEN,,,,,,,,,1,2,3,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,
http-in,local,,,0,0,100,0,0,0,0,0,0,,,,,OPEN,,,,,,,,,1,2,4,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,
http-in,local-https,,,0,5,100,188347,19301096,323070732,171443,0,0,,,,,OPEN,,,,,,,,,1,2,5,,,,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,http,,,,,,0,0,
www,www,0,0,0,20,20,1719698,672044109,64806076656,,0,,0,5285,22,0,UP,1,1,0,561,84,1036557,3356,,1,3,1,,1715117,,2,0,,45,L7OK,200,5,671,1144889,481714,87038,4,0,,,,,105016,167,,,,,5,OK,,0,5,16,1167,,,,Layer7 check passed,,2,3,4,,,,,,http,,,,,,,,
www,bck,0,0,0,10,10,1483,537137,7544118,,0,,0,0,0,0,UP,1,0,1,4,0,5218087,0,,1,3,2,,1371,,2,0,,17,L7OK,200,2,0,629,99,755,0,0,,,,,16,0,,,,,1036557,OK,,756,1,13,1184,,,,Layer7 check passed,,2,5,6,,,,,,http,,,,,,,,
www,BACKEND,0,25,0,46,100,1721835,674684790,64813732170,314,0,,130,5285,22,0,UP,1,1,1,,0,5218087,0,,1,3,0,,1716488,,1,0,,45,,,,0,1145518,481813,88664,5719,121,,,,1721835,105172,167,35669268059,17250148556,0,556042,5,,,0,5,16,1167,,,,,,,,,,,,,,http,,,,,,,,
git,www,0,0,0,2,2,14539,5228218,303747244,,0,,0,21,0,0,UP,1,1,0,559,84,1036557,3352,,1,4,1,,9481,,2,0,,2,L7OK,200,3,0,5668,8710,140,0,0,,,,,690,0,,,,,1342,OK,,1268,1,2908,4500,,,,Layer7 check passed,,2,3,4,,,,,,http,,,,,,,,
git,bck,0,0,0,0,2,0,0,0,,0,,0,0,0,0,UP,1,0,1,2,0,5218087,0,,1,4,2,,0,,2,0,,0,L7OK,200,2,0,0,0,0,0,0,,,,,0,0,,,,,-1,OK,,0,0,0,0,,,,Layer7 check passed,,2,3,4,,,,,,http,,,,,,,,
git,BACKEND,0,6,0,8,2,14541,8082393,303747668,0,0,,2,21,0,0,UP,1,1,1,,0,5218087,0,,1,4,0,,9481,,1,0,,7,,,,0,5668,8710,140,23,0,,,,14541,690,0,133458298,38104818,0,4379,1342,,,1268,1,2908,4500,,,,,,,,,,,,,,http,,,,,,,,
demo,BACKEND,0,0,1,5,20,24063,7876647,659864417,48,0,,1,0,0,0,UP,0,0,0,,0,5218087,,,1,17,0,,0,,1,1,,26,,,,0,23983,21,0,1,57,,,,24062,111,0,567843278,146884392,0,1083,0,,,2706,0,0,887,,,,,,,,,,,,,,http,,,,,,,,
1 # pxname svname qcur qmax scur smax slim stot bin bout dreq dresp ereq econ eresp wretr wredis status weight act bck chkfail chkdown lastchg downtime qlimit pid iid sid throttle lbtot tracked type rate rate_lim rate_max check_status check_code check_duration hrsp_1xx hrsp_2xx hrsp_3xx hrsp_4xx hrsp_5xx hrsp_other hanafail req_rate req_rate_max req_tot cli_abrt srv_abrt comp_in comp_out comp_byp comp_rsp lastsess last_chk last_agt qtime ctime rtime ttime agent_status agent_code agent_duration check_desc agent_desc check_rise check_fall check_health agent_rise agent_fall agent_health addr cookie mode algo conn_rate conn_rate_max conn_tot intercepted dcon dses
2 http-in FRONTEND 3 100 100 2639994 813557487 65937668635 505252 0 47567 OPEN 1 2 0 0 1 0 157 0 1514640 606647 136264 496535 14948 1 155 2754255 36370569635 17435137766 0 642264 http 1 157 2649922 339471 0 0
3 http-in IPv4-direct 3 41 100 349801 57445827 1503928881 269899 0 287 OPEN 1 2 1 3 http 0 0
4 http-in IPv4-cached 0 33 100 1786155 644395819 57905460294 60511 0 1 OPEN 1 2 2 3 http 0 0
5 http-in IPv6-direct 0 100 100 325619 92414745 6205208728 3399 0 47279 OPEN 1 2 3 3 http 0 0
6 http-in local 0 0 100 0 0 0 0 0 0 OPEN 1 2 4 3 http 0 0
7 http-in local-https 0 5 100 188347 19301096 323070732 171443 0 0 OPEN 1 2 5 3 http 0 0
8 www www 0 0 0 20 20 1719698 672044109 64806076656 0 0 5285 22 0 UP 1 1 0 561 84 1036557 3356 1 3 1 1715117 2 0 45 L7OK 200 5 671 1144889 481714 87038 4 0 105016 167 5 OK 0 5 16 1167 Layer7 check passed 2 3 4 http
9 www bck 0 0 0 10 10 1483 537137 7544118 0 0 0 0 0 UP 1 0 1 4 0 5218087 0 1 3 2 1371 2 0 17 L7OK 200 2 0 629 99 755 0 0 16 0 1036557 OK 756 1 13 1184 Layer7 check passed 2 5 6 http
10 www BACKEND 0 25 0 46 100 1721835 674684790 64813732170 314 0 130 5285 22 0 UP 1 1 1 0 5218087 0 1 3 0 1716488 1 0 45 0 1145518 481813 88664 5719 121 1721835 105172 167 35669268059 17250148556 0 556042 5 0 5 16 1167 http
11 git www 0 0 0 2 2 14539 5228218 303747244 0 0 21 0 0 UP 1 1 0 559 84 1036557 3352 1 4 1 9481 2 0 2 L7OK 200 3 0 5668 8710 140 0 0 690 0 1342 OK 1268 1 2908 4500 Layer7 check passed 2 3 4 http
12 git bck 0 0 0 0 2 0 0 0 0 0 0 0 0 UP 1 0 1 2 0 5218087 0 1 4 2 0 2 0 0 L7OK 200 2 0 0 0 0 0 0 0 0 -1 OK 0 0 0 0 Layer7 check passed 2 3 4 http
13 git BACKEND 0 6 0 8 2 14541 8082393 303747668 0 0 2 21 0 0 UP 1 1 1 0 5218087 0 1 4 0 9481 1 0 7 0 5668 8710 140 23 0 14541 690 0 133458298 38104818 0 4379 1342 1268 1 2908 4500 http
14 demo BACKEND 0 0 1 5 20 24063 7876647 659864417 48 0 1 0 0 0 UP 0 0 0 0 5218087 1 17 0 0 1 1 26 0 23983 21 0 1 57 24062 111 0 567843278 146884392 0 1083 0 2706 0 0 887 http