feat(inputs.haproxy): Add support for tcp endpoints in haproxy plugin (#12680)

This commit is contained in:
Yauhen Shulitski 2023-02-17 15:17:32 +01:00 committed by GitHub
parent 63ebbf2977
commit da675d4788
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 64 deletions

View File

@ -4730,25 +4730,25 @@
# # insecure_skip_verify = false # # insecure_skip_verify = false
# # Read metrics of HAProxy, via socket or HTTP stats page # # Read metrics of HAProxy, via stats socket or http endpoints
# [[inputs.haproxy]] # [[inputs.haproxy]]
# ## An array of address to gather stats about. Specify an ip on hostname # ## List of stats endpoints. Metrics can be collected from both http and socket
# ## with optional port. ie localhost, 10.10.3.33:1936, etc. # ## endpoints. Examples of valid endpoints:
# ## Make sure you specify the complete path to the stats endpoint # ## - http://myhaproxy.com:1936/haproxy?stats
# ## including the protocol, ie http://10.10.3.33: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"]
# #
# ## Credentials for basic HTTP authentication # ## Credentials for basic HTTP authentication
# # username = "admin" # # username = "admin"
# # password = "admin" # # password = "admin"
# #
# ## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats
# servers = ["http://myhaproxy.com:1936/haproxy?stats"]
#
# ## You can also use local socket with standard wildcard globbing.
# ## Server address not starting with 'http' will be treated as a possible
# ## socket, so both examples below are valid.
# # servers = ["socket:/run/haproxy/admin.sock", "/run/haproxy/*.sock"]
#
# ## By default, some of the fields are renamed from what haproxy calls them. # ## 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 # ## Setting this option to true results in the plugin keeping the original
# ## field names. # ## field names.

View File

@ -4656,25 +4656,25 @@
# # insecure_skip_verify = false # # insecure_skip_verify = false
# # Read metrics of HAProxy, via socket or HTTP stats page # # Read metrics of HAProxy, via stats socket or http endpoints
# [[inputs.haproxy]] # [[inputs.haproxy]]
# ## An array of address to gather stats about. Specify an ip on hostname # ## List of stats endpoints. Metrics can be collected from both http and socket
# ## with optional port. ie localhost, 10.10.3.33:1936, etc. # ## endpoints. Examples of valid endpoints:
# ## Make sure you specify the complete path to the stats endpoint # ## - http://myhaproxy.com:1936/haproxy?stats
# ## including the protocol, ie http://10.10.3.33: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"]
# #
# ## Credentials for basic HTTP authentication # ## Credentials for basic HTTP authentication
# # username = "admin" # # username = "admin"
# # password = "admin" # # password = "admin"
# #
# ## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats
# servers = ["http://myhaproxy.com:1936/haproxy?stats"]
#
# ## You can also use local socket with standard wildcard globbing.
# ## Server address not starting with 'http' will be treated as a possible
# ## socket, so both examples below are valid.
# # servers = ["socket:/run/haproxy/admin.sock", "/run/haproxy/*.sock"]
#
# ## By default, some of the fields are renamed from what haproxy calls them. # ## 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 # ## Setting this option to true results in the plugin keeping the original
# ## field names. # ## field names.

View File

@ -19,25 +19,21 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Configuration ## Configuration
```toml @sample.conf ```toml @sample.conf
# Read metrics of HAProxy, via socket or HTTP stats page # Read metrics of HAProxy, via stats socket or http endpoints
[[inputs.haproxy]] [[inputs.haproxy]]
## An array of address to gather stats about. Specify an ip on hostname ## List of stats endpoints. Metrics can be collected from both http and socket
## with optional port. ie localhost, 10.10.3.33:1936, etc. ## endpoints. Examples of valid endpoints:
## Make sure you specify the complete path to the stats endpoint ## - http://myhaproxy.com:1936/haproxy?stats
## including the protocol, ie http://10.10.3.33:1936/haproxy?stats ## - https://myhaproxy.com:8000/stats
## - socket:/run/haproxy/admin.sock
## Credentials for basic HTTP authentication ## - /run/haproxy/*.sock
# username = "admin" ## - tcp://127.0.0.1:1936
# password = "admin" ##
## Server addresses not starting with 'http://', 'https://', 'tcp://' will be
## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats ## treated as possible sockets. When specifying local socket, glob patterns are
## supported.
servers = ["http://myhaproxy.com:1936/haproxy?stats"] servers = ["http://myhaproxy.com:1936/haproxy?stats"]
## You can also use local socket with standard wildcard globbing.
## Server address not starting with 'http' will be treated as a possible
## socket, so both examples below are valid.
# servers = ["socket:/run/haproxy/admin.sock", "/run/haproxy/*.sock"]
## By default, some of the fields are renamed from what haproxy calls them. ## 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 ## Setting this option to true results in the plugin keeping the original
## field names. ## field names.

View File

@ -49,7 +49,7 @@ func (h *haproxy) Gather(acc telegraf.Accumulator) error {
endpoints := make([]string, 0, len(h.Servers)) endpoints := make([]string, 0, len(h.Servers))
for _, endpoint := range h.Servers { for _, endpoint := range h.Servers {
if strings.HasPrefix(endpoint, "http") { if strings.HasPrefix(endpoint, "http://") || strings.HasPrefix(endpoint, "https://") || strings.HasPrefix(endpoint, "tcp://") {
endpoints = append(endpoints, endpoint) endpoints = append(endpoints, endpoint)
continue continue
} }
@ -85,21 +85,29 @@ func (h *haproxy) Gather(acc telegraf.Accumulator) error {
} }
func (h *haproxy) gatherServerSocket(addr string, acc telegraf.Accumulator) error { func (h *haproxy) gatherServerSocket(addr string, acc telegraf.Accumulator) error {
socketPath := getSocketAddr(addr) var network string
var address string
if strings.HasPrefix(addr, "tcp://") {
network = "tcp"
address = strings.TrimPrefix(addr, "tcp://")
} else {
network = "unix"
address = getSocketAddr(addr)
}
c, err := net.Dial("unix", socketPath) c, err := net.Dial(network, address)
if err != nil { if err != nil {
return fmt.Errorf("could not connect to socket '%s': %s", addr, err) return fmt.Errorf("could not connect to '%s://%s': %s", network, address, err)
} }
_, errw := c.Write([]byte("show stat\n")) _, errw := c.Write([]byte("show stat\n"))
if errw != nil { if errw != nil {
return fmt.Errorf("could not write to socket '%s': %s", addr, errw) return fmt.Errorf("could not write to socket '%s://%s': %s", network, address, errw)
} }
return h.importCsvResult(c, acc, socketPath) return h.importCsvResult(c, acc, address)
} }
func (h *haproxy) gatherServer(addr string, acc telegraf.Accumulator) error { func (h *haproxy) gatherServer(addr string, acc telegraf.Accumulator) error {

View File

@ -170,6 +170,37 @@ func TestHaproxyGeneratesMetricsUsingSocket(t *testing.T) {
require.NotEmpty(t, acc.Errors) 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()
s := statServer{}
go s.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 // When not passing server config, we default to localhost
// We just want to make sure we did request stat from localhost // We just want to make sure we did request stat from localhost
func TestHaproxyDefaultGetFromLocalhost(t *testing.T) { func TestHaproxyDefaultGetFromLocalhost(t *testing.T) {

View File

@ -1,22 +1,18 @@
# Read metrics of HAProxy, via socket or HTTP stats page # Read metrics of HAProxy, via stats socket or http endpoints
[[inputs.haproxy]] [[inputs.haproxy]]
## An array of address to gather stats about. Specify an ip on hostname ## List of stats endpoints. Metrics can be collected from both http and socket
## with optional port. ie localhost, 10.10.3.33:1936, etc. ## endpoints. Examples of valid endpoints:
## Make sure you specify the complete path to the stats endpoint ## - http://myhaproxy.com:1936/haproxy?stats
## including the protocol, ie http://10.10.3.33:1936/haproxy?stats ## - https://myhaproxy.com:8000/stats
## - socket:/run/haproxy/admin.sock
## Credentials for basic HTTP authentication ## - /run/haproxy/*.sock
# username = "admin" ## - tcp://127.0.0.1:1936
# password = "admin" ##
## Server addresses not starting with 'http://', 'https://', 'tcp://' will be
## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats ## treated as possible sockets. When specifying local socket, glob patterns are
## supported.
servers = ["http://myhaproxy.com:1936/haproxy?stats"] servers = ["http://myhaproxy.com:1936/haproxy?stats"]
## You can also use local socket with standard wildcard globbing.
## Server address not starting with 'http' will be treated as a possible
## socket, so both examples below are valid.
# servers = ["socket:/run/haproxy/admin.sock", "/run/haproxy/*.sock"]
## By default, some of the fields are renamed from what haproxy calls them. ## 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 ## Setting this option to true results in the plugin keeping the original
## field names. ## field names.