diff --git a/README.md b/README.md index 603f910d0..9720342f1 100644 --- a/README.md +++ b/README.md @@ -57,9 +57,16 @@ Find a list of all the available options for your DogStatsD Client in the [Datad ### Supported environment variables -* If the `addr` parameter is empty, the client uses the `DD_AGENT_HOST` environment variables to build a target address. - Example: `DD_AGENT_HOST=127.0.0.1:8125` for UDP, `DD_AGENT_HOST=unix:///path/to/socket` for UDS and `DD_AGENT_HOST=\\.\pipe\my_windows_pipe` for Windows -* If the `DD_ENTITY_ID` environment variable is found, its value is injected as a global `dd.internal.entity_id` tag. The Datadog Agent uses this tag to insert container tags into the metrics. To avoid overwriting this global tag, only `append` to the `c.Tags` slice. +* If the `addr` parameter is empty, the client uses the `DD_DOGSTATSD_HOST` and then `DD_AGENT_HOST` environment + variables to build a target address. `DD_DOGSTATSD_HOST` takes precedence over `DD_AGENT_HOST`, but both use the same + format. + Example: `DD_AGENT_HOST=127.0.0.1:8125` for UDP, `DD_AGENT_HOST=unix:///path/to/socket` for UDS and + `DD_AGENT_HOST=\\.\pipe\my_windows_pipe` for named pipes +* `DD_DOGSTATSD_PORT` can be use to set the UDP port. If `DD_DOGSTATSD_HOST` or `DD_AGENT_HOST` already contains a port + then `DD_DOGSTATSD_PORT` is ignored. + Example: `DD_AGENT_HOST=127.0.0.1` with `DD_DOGSTATSD_PORT=8125`. +* If the `DD_ENTITY_ID` environment variable is found, its value is injected as a global `dd.internal.entity_id` tag. + The Datadog Agent uses this tag to insert container tags into the metrics. To enable origin detection and set the `DD_ENTITY_ID` environment variable, add the following lines to your application manifest: diff --git a/statsd/statsd.go b/statsd/statsd.go index 5a29618a2..988fd0ef0 100644 --- a/statsd/statsd.go +++ b/statsd/statsd.go @@ -64,9 +64,10 @@ traffic instead of UDP. const WindowsPipeAddressPrefix = `\\.\pipe\` const ( - agentHostEnvVarName = "DD_AGENT_HOST" - agentPortEnvVarName = "DD_DOGSTATSD_PORT" - defaultUDPPort = "8125" + agentHostEnvVarName = "DD_AGENT_HOST" + dogstatsdHostEnvVarName = "DD_DOGSTATSD_HOST" + dogstatsdPortEnvVarName = "DD_DOGSTATSD_PORT" + defaultUDPPort = "8125" ) /* @@ -230,8 +231,12 @@ var _ ClientInterface = &Client{} func resolveAddr(addr string) string { envPort := "" if addr == "" { - addr = os.Getenv(agentHostEnvVarName) - envPort = os.Getenv(agentPortEnvVarName) + if dsdHost := os.Getenv(dogstatsdHostEnvVarName); dsdHost != "" { + addr = dsdHost + } else { + addr = os.Getenv(agentHostEnvVarName) + } + envPort = os.Getenv(dogstatsdPortEnvVarName) } if addr == "" { diff --git a/statsd/statsd_test.go b/statsd/statsd_test.go index b73f2e53c..1a5ab2f94 100644 --- a/statsd/statsd_test.go +++ b/statsd/statsd_test.go @@ -192,11 +192,11 @@ func TestResolveAddressFromEnvironment(t *testing.T) { } else { defer os.Unsetenv(agentHostEnvVarName) } - portInitialValue, portInitiallySet := os.LookupEnv(agentPortEnvVarName) + portInitialValue, portInitiallySet := os.LookupEnv(dogstatsdPortEnvVarName) if portInitiallySet { - defer os.Setenv(agentPortEnvVarName, portInitialValue) + defer os.Setenv(dogstatsdPortEnvVarName, portInitialValue) } else { - defer os.Unsetenv(agentPortEnvVarName) + defer os.Unsetenv(dogstatsdPortEnvVarName) } for _, tc := range []struct { @@ -224,7 +224,7 @@ func TestResolveAddressFromEnvironment(t *testing.T) { } { t.Run(tc.name, func(t *testing.T) { os.Setenv(agentHostEnvVarName, tc.hostEnv) - os.Setenv(agentPortEnvVarName, tc.portEnv) + os.Setenv(dogstatsdPortEnvVarName, tc.portEnv) addr := resolveAddr(tc.addrParam) assert.Equal(t, tc.expectedAddr, addr) @@ -269,3 +269,95 @@ func TestGetTelemetry(t *testing.T) { assert.Equal(t, uint64(1), tlm.AggregationNbContextDistribution, "telmetry AggregationNbContextDistribution was wrong") assert.Equal(t, uint64(2), tlm.AggregationNbContextTiming, "telmetry AggregationNbContextTiming was wrong") } + +func TestEnvAgentHost(t *testing.T) { + defer func() { os.Unsetenv("DD_AGENT_HOST") }() + + os.Setenv("DD_AGENT_HOST", "localhost:8765") + + ts, client := newClientAndTestServerCustomAddr(t, + "udp", + "", + "localhost:8765", + nil, + ) + + ts.sendAllAndAssert(t, client) +} + +func TestEnvAgentHostAndPort(t *testing.T) { + defer func() { os.Unsetenv("DD_AGENT_HOST") }() + defer func() { os.Unsetenv("DD_DOGSTATSD_PORT") }() + + // Check that DD_AGENT_PORT is ignored when DD_AGENT_HOST already contains a port + os.Setenv("DD_AGENT_HOST", "localhost:8765") + os.Setenv("DD_DOGSTATSD_PORT", "1234") + + ts, client := newClientAndTestServerCustomAddr(t, + "udp", + "", + "localhost:8765", + nil, + ) + + ts.sendAllAndAssert(t, client) + + // Check that DD_DOGSTATSD_PORT is used + os.Setenv("DD_AGENT_HOST", "localhost") + os.Setenv("DD_DOGSTATSD_PORT", "8766") + + ts, client = newClientAndTestServerCustomAddr(t, + "udp", + "", + "localhost:8766", + nil, + ) + + ts.sendAllAndAssert(t, client) +} + +func TestEnvDogstatsddHost(t *testing.T) { + defer func() { os.Unsetenv("DD_DOGSTATSD_HOST") }() + + os.Setenv("DD_DOGSTATSD_HOST", "localhost:8765") + + ts, client := newClientAndTestServerCustomAddr(t, + "udp", + "", + "localhost:8765", + nil, + ) + + ts.sendAllAndAssert(t, client) +} + +func TestEnvDogstatsddHostAndPort(t *testing.T) { + defer func() { os.Unsetenv("DD_DOGSTATSD_HOST") }() + defer func() { os.Unsetenv("DD_DOGSTATSD_PORT") }() + + // Check that DD_DOGSTATSD_PORT is ignored when DD_AGENT_HOST already contains a port + os.Setenv("DD_DOGSTATSD_HOST", "localhost:8765") + os.Setenv("DD_DOGSTATSD_PORT", "1234") + + ts, client := newClientAndTestServerCustomAddr(t, + "udp", + "", + "localhost:8765", + nil, + ) + + ts.sendAllAndAssert(t, client) + + // Check that DD_DOGSTATSD_PORT is used + os.Setenv("DD_DOGSTATSD_HOST", "localhost") + os.Setenv("DD_DOGSTATSD_PORT", "8766") + + ts, client = newClientAndTestServerCustomAddr(t, + "udp", + "", + "localhost:8766", + nil, + ) + + ts.sendAllAndAssert(t, client) +} diff --git a/statsd/test_helpers_test.go b/statsd/test_helpers_test.go index 82072345a..edc525b0e 100644 --- a/statsd/test_helpers_test.go +++ b/statsd/test_helpers_test.go @@ -54,7 +54,6 @@ type testServer struct { errors []string readData []string proto string - addr string stopped chan struct{} tags string namespace string @@ -66,14 +65,16 @@ type testServer struct { } func newClientAndTestServer(t *testing.T, proto string, addr string, tags []string, options ...Option) (*testServer, *Client) { + return newClientAndTestServerCustomAddr(t, proto, addr, addr, tags, options...) +} +func newClientAndTestServerCustomAddr(t *testing.T, proto string, addrClient string, addrTest string, tags []string, options ...Option) (*testServer, *Client) { opt, err := resolveOptions(options) require.NoError(t, err) ts := &testServer{ proto: proto, data: []string{}, - addr: addr, stopped: make(chan struct{}), aggregation: opt.aggregation, extendedAggregation: opt.extendedAggregation, @@ -88,14 +89,14 @@ func newClientAndTestServer(t *testing.T, proto string, addr string, tags []stri switch proto { case "udp": - udpAddr, err := net.ResolveUDPAddr("udp", addr) + udpAddr, err := net.ResolveUDPAddr("udp", addrTest) require.NoError(t, err) conn, err := net.ListenUDP("udp", udpAddr) require.NoError(t, err) ts.conn = conn case "uds": - socketPath := addr[7:] + socketPath := addrTest[7:] address, err := net.ResolveUnixAddr("unixgram", socketPath) require.NoError(t, err) conn, err := net.ListenUnixgram("unixgram", address) @@ -107,7 +108,7 @@ func newClientAndTestServer(t *testing.T, proto string, addr string, tags []stri require.FailNow(t, "unknown proto '%s'", proto) } - client, err := New(addr, options...) + client, err := New(addrClient, options...) require.NoError(t, err) go ts.start()