Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement origin detection #3124

Merged
merged 7 commits into from
Feb 5, 2025
3 changes: 3 additions & 0 deletions ddtrace/tracer/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ func newHTTPTransport(url string, client *http.Client) *httpTransport {
if eid := internal.EntityID(); eid != "" {
defaultHeaders["Datadog-Entity-ID"] = eid
}
if extEnv := internal.ExternalEnvironment(); extEnv != "" {
defaultHeaders["Datadog-External-Env"] = extEnv
}
return &httpTransport{
traceURL: fmt.Sprintf("%s/v0.4/traces", url),
statsURL: fmt.Sprintf("%s/v0.6/stats", url),
Expand Down
27 changes: 27 additions & 0 deletions ddtrace/tracer/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,3 +396,30 @@ func TestWithUDS(t *testing.T) {
assert.Len(rt.reqs, 1)
assert.Equal(hits, 2)
}

func TestExternalEnvironment(t *testing.T) {
t.Setenv("DD_EXTERNAL_ENV", "it-false,cn-nginx-webserver,pu-75a2b6d5-3949-4afb-ad0d-92ff0674e759")
assert := assert.New(t)
found := false
srv := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) {
extEnv := r.Header.Get("Datadog-External-Env")
if extEnv == "" {
return
}
assert.Equal("it-false,cn-nginx-webserver,pu-75a2b6d5-3949-4afb-ad0d-92ff0674e759", extEnv)
found = true
}))
defer srv.Close()

u, err := url.Parse(srv.URL)
assert.NoError(err)
c := &http.Client{}
trc := newTracer(WithAgentTimeout(2), WithAgentAddr(u.Host), WithHTTPClient(c))
defer trc.Stop()

p, err := encode(getTestTrace(1, 1))
assert.NoError(err)
_, err = trc.config.transport.send(p)
assert.NoError(err)
assert.True(found)
}
6 changes: 3 additions & 3 deletions internal/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ var (
// containerID is the containerID read at init from /proc/self/cgroup
containerID string

// entityID is the entityID to use for the container. It is the `cid-<containerID>` if the container id available,
// entityID is the entityID to use for the container. It is the `ci-<containerID>` if the container id available,
// otherwise the cgroup node controller's inode prefixed with `in-` or an empty string on incompatible OS.
// We use the memory controller on cgroupv1 and the root cgroup on cgroupv2.
entityID string
Expand Down Expand Up @@ -151,7 +151,7 @@ func readEntityID(mountPath, cgroupPath string, isHostCgroupNamespace bool) stri
// First try to emit the containerID if available. It will be retrieved if the container is
// running in the host cgroup namespace, independently of the cgroup version.
if containerID != "" {
return "cid-" + containerID
return "ci-" + containerID
}
// Rely on the inode if we're not running in the host cgroup namespace.
if isHostCgroupNamespace {
Expand All @@ -161,7 +161,7 @@ func readEntityID(mountPath, cgroupPath string, isHostCgroupNamespace bool) stri
}

// EntityID attempts to return the container ID or the cgroup node controller's inode if the container ID
// is not available. The cid is prefixed with `cid-` and the inode with `in-`.
// is not available. The cid is prefixed with `ci-` and the inode with `in-`.
func EntityID() string {
return entityID
}
Expand Down
2 changes: 1 addition & 1 deletion internal/container_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func TestReadEntityIDPrioritizeCID(t *testing.T) {

containerID = "fakeContainerID"
eid := readEntityID("", "", true)
assert.Equal(t, "cid-fakeContainerID", eid)
assert.Equal(t, "ci-fakeContainerID", eid)
}

func TestReadEntityIDFallbackOnInode(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion internal/container_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func ContainerID() string {
}

// EntityID attempts to return the container ID or the cgroup v2 node inode if the container ID is not available.
// The cid is prefixed with `cid-` and the inode with `in-`.
// The cid is prefixed with `ci-` and the inode with `in-`.
func EntityID() string {
return ""
}
5 changes: 5 additions & 0 deletions internal/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,8 @@ func BoolVal(val string, def bool) bool {
}
return v
}

// ExternalEnvironment returns the value of the DD_EXTERNAL_ENV environment variable.
func ExternalEnvironment() string {
return os.Getenv("DD_EXTERNAL_ENV")
}
9 changes: 9 additions & 0 deletions internal/telemetry/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"runtime"
"sort"
"sync"
"testing"
"time"

"github.com/stretchr/testify/assert"

"gopkg.in/DataDog/dd-trace-go.v1/internal"
logging "gopkg.in/DataDog/dd-trace-go.v1/internal/log"
)

Expand Down Expand Up @@ -439,11 +441,18 @@ func Test_heartbeatInterval(t *testing.T) {
}

func TestNoEmptyHeaders(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skip("skipping test on non-linux OS")
}
if internal.EntityID() == "" || internal.ContainerID() == "" {
t.Skip("skipping test when entity ID and container ID are not available")
}
c := &client{}
req := c.newRequest(RequestTypeAppStarted)
assertNotEmpty := func(header string) {
headers := *req.Header
vals := headers[header]
assert.Greater(t, len(vals), 0, "header %s should not be empty", header)
for _, v := range vals {
assert.NotEmpty(t, v, "%s header should not be empty", header)
}
Expand Down
Loading