Guess Datadog socket type when prefix is unix

This commit is contained in:
Kevin Pollet 2024-09-19 15:30:05 +02:00 committed by GitHub
parent 7e75dc0819
commit f3eba8d3a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 63 additions and 15 deletions

View file

@ -27,7 +27,9 @@ _Required, Default="127.0.0.1:8125"_
Address instructs exporter to send metrics to datadog-agent at this address. Address instructs exporter to send metrics to datadog-agent at this address.
This address can be a Unix Domain Socket (UDS) address with the following form: `unix:///path/to/datadog.socket`. This address can be a Unix Domain Socket (UDS) in the following format: `unix:///path/to/datadog.socket`.
When the prefix is set to `unix`, the socket type will be automatically determined.
To explicitly define the socket type and avoid automatic detection, you can use the prefixes `unixgram` for `SOCK_DGRAM` (datagram sockets) and `unixstream` for `SOCK_STREAM` (stream sockets), respectively.
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"
metrics: metrics:

View file

@ -2,23 +2,30 @@ package metrics
import ( import (
"context" "context"
"net"
"strings" "strings"
"time" "time"
"github.com/go-kit/kit/metrics/dogstatsd" "github.com/go-kit/kit/metrics/dogstatsd"
"github.com/go-kit/kit/util/conn"
gokitlog "github.com/go-kit/log"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/logs"
"github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/safe"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
) )
const (
unixAddressPrefix = "unix://"
unixAddressDatagramPrefix = "unixgram://"
unixAddressStreamPrefix = "unixstream://"
)
var ( var (
datadogClient *dogstatsd.Dogstatsd datadogClient *dogstatsd.Dogstatsd
datadogLoopCancelFunc context.CancelFunc datadogLoopCancelFunc context.CancelFunc
) )
const unixAddressPrefix = "unix://"
// Metric names consistent with https://github.com/DataDog/integrations-extras/pull/64 // Metric names consistent with https://github.com/DataDog/integrations-extras/pull/64
const ( const (
ddConfigReloadsName = "config.reload.total" ddConfigReloadsName = "config.reload.total"
@ -58,9 +65,10 @@ func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
config.Prefix = defaultMetricsPrefix config.Prefix = defaultMetricsPrefix
} }
datadogClient = dogstatsd.New(config.Prefix+".", logs.NewGoKitWrapper(log.Logger.With().Str(logs.MetricsProviderName, "datadog").Logger())) datadogLogger := logs.NewGoKitWrapper(log.Logger.With().Str(logs.MetricsProviderName, "datadog").Logger())
datadogClient = dogstatsd.New(config.Prefix+".", datadogLogger)
initDatadogClient(ctx, config) initDatadogClient(ctx, config, datadogLogger)
registry := &standardRegistry{ registry := &standardRegistry{
configReloadsCounter: datadogClient.NewCounter(ddConfigReloadsName, 1.0), configReloadsCounter: datadogClient.NewCounter(ddConfigReloadsName, 1.0),
@ -101,7 +109,7 @@ func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
return registry return registry
} }
func initDatadogClient(ctx context.Context, config *types.Datadog) { func initDatadogClient(ctx context.Context, config *types.Datadog, logger gokitlog.LoggerFunc) {
network, address := parseDatadogAddress(config.Address) network, address := parseDatadogAddress(config.Address)
ctx, datadogLoopCancelFunc = context.WithCancel(ctx) ctx, datadogLoopCancelFunc = context.WithCancel(ctx)
@ -110,10 +118,38 @@ func initDatadogClient(ctx context.Context, config *types.Datadog) {
ticker := time.NewTicker(time.Duration(config.PushInterval)) ticker := time.NewTicker(time.Duration(config.PushInterval))
defer ticker.Stop() defer ticker.Stop()
datadogClient.SendLoop(ctx, ticker.C, network, address) dialer := func(network, address string) (net.Conn, error) {
switch network {
case "unix":
// To mimic the Datadog client when the network is unix we will try to guess the UDS type.
newConn, err := net.Dial("unixgram", address)
if err != nil && strings.Contains(err.Error(), "protocol wrong type for socket") {
return net.Dial("unix", address)
}
return newConn, err
case "unixgram":
return net.Dial("unixgram", address)
case "unixstream":
return net.Dial("unix", address)
default:
return net.Dial(network, address)
}
}
datadogClient.WriteLoop(ctx, ticker.C, conn.NewManager(dialer, network, address, time.After, logger))
}) })
} }
// StopDatadog stops the Datadog metrics pusher.
func StopDatadog() {
if datadogLoopCancelFunc != nil {
datadogLoopCancelFunc()
datadogLoopCancelFunc = nil
}
}
func parseDatadogAddress(address string) (string, string) { func parseDatadogAddress(address string) (string, string) {
network := "udp" network := "udp"
@ -122,6 +158,12 @@ func parseDatadogAddress(address string) (string, string) {
case strings.HasPrefix(address, unixAddressPrefix): case strings.HasPrefix(address, unixAddressPrefix):
network = "unix" network = "unix"
addr = address[len(unixAddressPrefix):] addr = address[len(unixAddressPrefix):]
case strings.HasPrefix(address, unixAddressDatagramPrefix):
network = "unixgram"
addr = address[len(unixAddressDatagramPrefix):]
case strings.HasPrefix(address, unixAddressStreamPrefix):
network = "unixstream"
addr = address[len(unixAddressStreamPrefix):]
case address != "": case address != "":
addr = address addr = address
default: default:
@ -130,11 +172,3 @@ func parseDatadogAddress(address string) (string, string) {
return network, addr return network, addr
} }
// StopDatadog stops the Datadog metrics pusher.
func StopDatadog() {
if datadogLoopCancelFunc != nil {
datadogLoopCancelFunc()
datadogLoopCancelFunc = nil
}
}

View file

@ -64,6 +64,18 @@ func TestDatadog_parseDatadogAddress(t *testing.T) {
expNetwork: "unix", expNetwork: "unix",
expAddress: "/path/to/datadog.socket", expAddress: "/path/to/datadog.socket",
}, },
{
desc: "unixgram address",
address: "unixgram:///path/to/datadog.socket",
expNetwork: "unixgram",
expAddress: "/path/to/datadog.socket",
},
{
desc: "unixstream address",
address: "unixstream:///path/to/datadog.socket",
expNetwork: "unixstream",
expAddress: "/path/to/datadog.socket",
},
} }
for _, test := range tests { for _, test := range tests {