Skip to content

Commit

Permalink
feat(inputs.haproxy): Add support for tcp endpoints in haproxy plugin (
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnjack authored Feb 17, 2023
1 parent 63ebbf2 commit da675d4
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 64 deletions.
26 changes: 13 additions & 13 deletions etc/telegraf.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4730,25 +4730,25 @@
# # 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]]
# ## An array of address to gather stats about. Specify an ip on hostname
# ## with optional port. ie localhost, 10.10.3.33:1936, etc.
# ## Make sure you specify the complete path to the stats endpoint
# ## including the protocol, ie http://10.10.3.33:1936/haproxy?stats
# ## 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"]
#
# ## Credentials for basic HTTP authentication
# # username = "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.
# ## Setting this option to true results in the plugin keeping the original
# ## field names.
Expand Down
26 changes: 13 additions & 13 deletions etc/telegraf_windows.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4656,25 +4656,25 @@
# # 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]]
# ## An array of address to gather stats about. Specify an ip on hostname
# ## with optional port. ie localhost, 10.10.3.33:1936, etc.
# ## Make sure you specify the complete path to the stats endpoint
# ## including the protocol, ie http://10.10.3.33:1936/haproxy?stats
# ## 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"]
#
# ## Credentials for basic HTTP authentication
# # username = "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.
# ## Setting this option to true results in the plugin keeping the original
# ## field names.
Expand Down
28 changes: 12 additions & 16 deletions plugins/inputs/haproxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,21 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## Configuration

```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]]
## An array of address to gather stats about. Specify an ip on hostname
## with optional port. ie localhost, 10.10.3.33:1936, etc.
## Make sure you specify the complete path to the stats endpoint
## including the protocol, ie http://10.10.3.33:1936/haproxy?stats

## Credentials for basic HTTP authentication
# username = "admin"
# password = "admin"

## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats
## 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"]

## 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.
## Setting this option to true results in the plugin keeping the original
## field names.
Expand Down
20 changes: 14 additions & 6 deletions plugins/inputs/haproxy/haproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (h *haproxy) Gather(acc telegraf.Accumulator) error {
endpoints := make([]string, 0, len(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)
continue
}
Expand Down Expand Up @@ -85,21 +85,29 @@ func (h *haproxy) Gather(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 {
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"))

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 {
Expand Down
31 changes: 31 additions & 0 deletions plugins/inputs/haproxy/haproxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,37 @@ func TestHaproxyGeneratesMetricsUsingSocket(t *testing.T) {
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
// We just want to make sure we did request stat from localhost
func TestHaproxyDefaultGetFromLocalhost(t *testing.T) {
Expand Down
28 changes: 12 additions & 16 deletions plugins/inputs/haproxy/sample.conf
Original file line number Diff line number Diff line change
@@ -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]]
## An array of address to gather stats about. Specify an ip on hostname
## with optional port. ie localhost, 10.10.3.33:1936, etc.
## Make sure you specify the complete path to the stats endpoint
## including the protocol, ie http://10.10.3.33:1936/haproxy?stats

## Credentials for basic HTTP authentication
# username = "admin"
# password = "admin"

## If no servers are specified, then default to 127.0.0.1:1936/haproxy?stats
## 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"]

## 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.
## Setting this option to true results in the plugin keeping the original
## field names.
Expand Down

0 comments on commit da675d4

Please sign in to comment.