diff --git a/internal/gitmetadata.go b/internal/gitmetadata.go index 6dabe6a444..570138d8ad 100644 --- a/internal/gitmetadata.go +++ b/internal/gitmetadata.go @@ -43,8 +43,14 @@ var ( lock = sync.Mutex{} gitMetadataTags map[string]string + binMetadataTags map[string]string ) +func init() { + // Binary metadata is extracted only once + binMetadataTags = getTagsFromBinary(debug.ReadBuildInfo) +} + func updateTags(tags map[string]string, key string, value string) { if _, ok := tags[key]; !ok && value != "" { tags[key] = value @@ -76,11 +82,13 @@ func getTagsFromDDTags() map[string]string { } } -// getTagsFromBinary extracts git metadata from binary metadata -func getTagsFromBinary() map[string]string { +// getTagsFromBinary extracts git metadata from binary metadata. +// It assumes it's running under a locked mutex. +func getTagsFromBinary(readBuildInfo func() (*debug.BuildInfo, bool)) map[string]string { res := make(map[string]string) - info, ok := debug.ReadBuildInfo() + info, ok := readBuildInfo() if !ok { + // Initialize buildInfo to avoid multiple calls to debug.ReadBuildInfo. log.Debug("ReadBuildInfo failed, skip source code metadata extracting") return res } @@ -116,7 +124,7 @@ func GetGitMetadataTags() map[string]string { if BoolEnv(EnvGitMetadataEnabledFlag, true) { updateAllTags(gitMetadataTags, getTagsFromEnv()) updateAllTags(gitMetadataTags, getTagsFromDDTags()) - updateAllTags(gitMetadataTags, getTagsFromBinary()) + updateAllTags(gitMetadataTags, binMetadataTags) } return gitMetadataTags diff --git a/internal/gitmetadata_test.go b/internal/gitmetadata_test.go index 4577674c63..2e5efb1d12 100644 --- a/internal/gitmetadata_test.go +++ b/internal/gitmetadata_test.go @@ -6,6 +6,7 @@ package internal import ( + "runtime/debug" "testing" "github.com/stretchr/testify/assert" @@ -54,3 +55,62 @@ func TestRemoveCredentials(t *testing.T) { }) } } + +func TestGetTagsFromBinary(t *testing.T) { + testCases := []struct { + name string + in string + expected map[string]string + }{ + { + name: "empty build info", + expected: map[string]string{}, + }, + { + name: "build info with module path", + expected: map[string]string{ + TagGoPath: "github.com/DataDog/dd-trace-go", + }, + }, + { + name: "build info with module path and git repository", + expected: map[string]string{ + TagGoPath: "github.com/DataDog/dd-trace-go", + TagCommitSha: "123456", + }, + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + readBuildInfo := func() (*debug.BuildInfo, bool) { + info := &debug.BuildInfo{ + Settings: []debug.BuildSetting{ + { + Key: "vcs", + Value: "git", + }, + }, + } + if tc.expected[TagGoPath] != "" { + info.Path = tc.expected[TagGoPath] + } + if tc.expected[TagCommitSha] != "" { + info.Settings = append(info.Settings, debug.BuildSetting{ + Key: "vcs.revision", + Value: tc.expected[TagCommitSha], + }) + } + return info, true + } + tags := getTagsFromBinary(readBuildInfo) + assert.Subset(t, tags, tc.expected) + }) + } +} + +func BenchmarkGetGitMetadataTags(b *testing.B) { + b.Setenv(EnvGitMetadataEnabledFlag, "true") + for i := 0; i < b.N; i++ { + GetGitMetadataTags() + } +}