Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8f6c18f
feat: add package to filter env var usage
genesor Jul 3, 2025
62a8e72
ci: add forbidigo to golangci-lint
genesor Jul 4, 2025
b8004e8
chore: migrate os calls to new package
genesor Jul 10, 2025
ca152a7
ci: add gitlab CI jobs for config inversion
genesor Jul 10, 2025
3ceb6c0
chore: migrate env calls to new package
genesor Jul 10, 2025
1afe4a5
chore: add supported env vars to supported configurations
genesor Jul 15, 2025
ea265eb
ci: fix continue-on-error for config inversion checks
genesor Jul 15, 2025
74ff37b
chore: add env var to supported configurations
genesor Jul 16, 2025
3baed7a
fix: remove %v in internal/env package
genesor Jul 16, 2025
c9fce2b
ci: add config inversion gitlab jobs
genesor Jul 17, 2025
e2be82a
chore: fix os.Getenv call
genesor Aug 1, 2025
d4d9802
chore: fix_modules
genesor Aug 1, 2025
d2031ff
ci: refactor config inversion check for reusability
genesor Aug 1, 2025
f9c2805
chore: add missing env var to supported configurations
genesor Aug 1, 2025
0f2c54e
chore: add missing appsec configuration keys
genesor Aug 4, 2025
486c05b
chore: add test over request-mirror config
genesor Aug 5, 2025
90e735a
chore: add missing supported_configurations for AAP/Envoy
genesor Aug 5, 2025
6d1684e
chore: update one-pipeline URL
genesor Aug 5, 2025
b16ea14
chore: run fix_modules.sh
genesor Sep 5, 2025
85c035c
chore(instrumentation): add test over all contribs on AnalyticsRate e…
genesor Aug 6, 2025
b025ee7
ci: add config inversion check for appsec
genesor Aug 6, 2025
77497b9
chore: update configinverter README and logs
genesor Aug 6, 2025
26e6e80
docs: add config inversion documentation
genesor Aug 8, 2025
cc847c4
feat(internal/env): add alias handling for env vars
genesor Aug 11, 2025
787a0db
chore: add new supported configuration
genesor Aug 11, 2025
d2e055c
fix: remove duplicate stage in gitlab
genesor Aug 12, 2025
ab715f1
ci: rename config inversion to configuration validation
genesor Aug 20, 2025
89b3bfe
chore: rename to env.Lookup env.Get
genesor Sep 1, 2025
b4dc9e9
doc: update CONTRIBUTING.md
genesor Sep 1, 2025
ebc6b77
chore: add testing for unknown configuration keys being correctly add…
genesor Sep 1, 2025
e3fdd88
chore: migrate os calls to env in appsec config
genesor Sep 2, 2025
7d4f9f8
fix: fix wrong func call
genesor Sep 2, 2025
ccefe39
ci: fix gitlab path for configuration central validation
genesor Sep 2, 2025
f81dcce
fix: remove unwanted env usage in test file
genesor Sep 2, 2025
523140a
chore: add missing appsec keys
genesor Sep 2, 2025
0cdca0d
ci: fix action cfg check import for orchestrion
genesor Sep 4, 2025
d5e5a71
chore: add quantize orchestrion env var
genesor Sep 4, 2025
d3d98c0
Merge branch 'main' into ben.db/APMAPI-1450-wrap-os-env-calls
genesor Sep 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/actions/supported_configurations_validation/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name: 'Supported Configurations Diff Check'
description: 'Check for changes in supported_configurations.json file in order to detect unknown configurations'
runs:
using: "composite"
steps:
- name: Supported Configurations Diff Check
if: always()
shell: bash
run: |-
git diff internal/env/supported_configurations.json
go run ./scripts/configinverter/main.go check
11 changes: 11 additions & 0 deletions .github/workflows/appsec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ jobs:
done
done

# Check for changes in the supported configurations
- name: Supported Configurations Diff Check
if: always()
uses: ./.github/actions/supported_configurations_validation

# Same tests but on the official golang container for linux
golang-linux-container:
name: ${{ matrix.platform }} golang:${{ matrix.go-version }}-${{ matrix.distribution }}
Expand Down Expand Up @@ -331,6 +336,12 @@ jobs:
fi
done

# Check for changes in the supported_configurations.json file
- name: Supported Configurations Diff Check
if: always()
run: |
sudo docker exec -i test.runner bash -c "go run ./scripts/configinverter/main.go check"

- name: Clean up
if: always()
run: sudo docker rm --force test.runner || echo "Could not remove container"
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/orchestrion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,14 @@ jobs:
# To enable sharing the reported JUnit XML, we need to save it into the temporary, shared directory by GHA.
XML_PATH: ${{ runner.temp }}${{ matrix.runs-on == 'windows' && '\' || '/' }}${{ env.REPORT }}

# Check for changes in the supported_configurations.json file
- name: Run Config Inverter Check
if: always()
run: |
git diff internal/env/supported_configurations.json
cd scripts/configinverter && go run main.go -input ../../internal/env/supported_configurations.json check
working-directory: ${{ github.workspace }}/dd-trace-go

# If in workflow_call, we collected coverage data we need to upload
- name: Consolidate coverage report
if: inputs.collect-coverage
Expand Down Expand Up @@ -297,7 +305,6 @@ jobs:
dd-api-key: ${{ secrets.DD_CI_API_KEY }}
path: ${{ runner.temp }}${{ matrix.runs-on == 'windows' && '\' || '/' }}
tags: go:${{ steps.setup-go.outputs.go-version }},arch:${{ runner.arch }},os:${{ runner.os }},distribution:${{ runner.distribution }}

# This is a simple join point to make it easy to set up branch protection rules in GitHub.
integration-test-done:
name: Orchestrion Integration Tests
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/smoke-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ jobs:
ref: ${{ inputs.ref || github.ref }}
repository: DataDog/dd-trace-go
- run: go test $PACKAGES
# Check for changes in the supported_configurations.json file
- name: Supported Configurations Diff Check
if: always()
uses: ./.github/actions/supported_configurations_validation

check-gen-files:
name: Check generated files and go mod files are up-to-date.
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/unit-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,11 @@ jobs:
shell: bash
run: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }}

# Check for changes in the supported_configurations.json file
- name: Supported Configurations Diff Check
if: always()
uses: ./.github/actions/supported_configurations_validation

Comment thread
darccio marked this conversation as resolved.
test-contrib:
needs:
- test-contrib-matrix
Expand Down Expand Up @@ -320,6 +325,11 @@ jobs:
shell: bash
run: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }}

# Check for changes in the supported_configurations.json file
- name: Supported Configurations Diff Check
if: always()
uses: ./.github/actions/supported_configurations_validation

upload-test-results:
needs:
- test-contrib
Expand Down
24 changes: 23 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ stages:
- benchmarks
- macrobenchmarks
- gates
- config-validation
- test-apps

variables:
Expand Down Expand Up @@ -45,7 +46,7 @@ check-big-regressions:
needs:
- job: trigger_child_pipeline
when: on_success
tags:
tags:
- "arch:amd64"
image: $BASE_CI_IMAGE
script:
Expand All @@ -65,7 +66,28 @@ check-big-regressions:
- reports/
expire_in: "30 days"

validate_supported_configurations_local_file:
stage: config-validation
image: registry.ddbuild.io/ci/libdatadog-build/packaging:68067123
tags: ["runner:apm-k8s-tweaked-metal"]
rules:
- when: on_success
extends: .validate_supported_configurations_local_file
variables:
LOCAL_JSON_PATH: "internal/env/supported_configurations.json"

update_central_configurations_version_range:
stage: config-validation
image: registry.ddbuild.io/ci/libdatadog-build/packaging:68067123
tags: ["runner:apm-k8s-tweaked-metal"]
extends: .update_central_configurations_version_range
variables:
LOCAL_REPO_NAME: "dd-trace-go"
LOCAL_JSON_PATH: "internal/env/supported_configurations.json"
LANGUAGE_NAME: "golang"

include:
- local: ".gitlab/macrobenchmarks.yml"
- local: ".gitlab/test-apps.yml"
- local: ".gitlab/docker-images-reliability-env.yml"
- local: ".gitlab/configuration-central-validation.yml"
43 changes: 43 additions & 0 deletions .gitlab/configuration-central-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This CI jobs are copied from libdatadog-build one-pipeline.yml gitlab template.
# This URL is available in the dd-gitlab/publish-content-addresable-templates job whenever
# a change is made on the one-pipeline template.
variables:
SCRIPTS_BASE_URL: https://gitlab-templates.ddbuild.io/libdatadog/one-pipeline/ca/50d49f6898ce86e93326856210e8ab6526895273cb6341ac2d7d0e6c1c14e31e/scripts

.download-scripts-from-template: &download-scripts-from-template
- mkdir -p scripts
- |
for script_file in "config-inversion-local-validation.sh" "config-inversion-update-supported-range.sh"
do
curl --location --fail --show-error --output "scripts/${script_file}" "${SCRIPTS_BASE_URL}/${script_file}"
if [[ $script_file == *sh ]]
then
chmod +x scripts/$script_file
fi
done

.validate_supported_configurations_local_file:
allow_failure: false
rules:
- when: on_success
variables:
LOCAL_JSON_PATH: ""
before_script:
- *download-scripts-from-template
script:
- scripts/config-inversion-local-validation.sh "$LOCAL_JSON_PATH"

.update_central_configurations_version_range:
allow_failure: false
rules:
- if: '$CI_COMMIT_TAG =~ /^v?[0-9]+\.[0-9]+\.[0-9]+$/'
when: on_success
variables:
LOCAL_JSON_PATH: ""
LANGUAGE_NAME: ""
MULTIPLE_RELEASE_LINES: "false" # expect "true" or "false" as a value to determine if a new "branch" identifier is needed to differentiate between multiple release lines
before_script:
- *download-scripts-from-template
- export FP_API_KEY=$(aws ssm get-parameter --region us-east-1 --name ci.$CI_PROJECT_NAME.FP_API_KEY --with-decryption --query "Parameter.Value" --out text)
script:
- scripts/config-inversion-update-supported-range.sh "$LOCAL_JSON_PATH" "$LANGUAGE_NAME" "$MULTIPLE_RELEASE_LINES"
16 changes: 16 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ linters:
- bodyclose
- depguard
- gocritic
- forbidigo
- govet
- revive
# - errorlint # TODO: Enable this once we've fixed all the errorlint issues.
Expand All @@ -28,7 +29,22 @@ linters:
- third_party$
- builtin$
- examples$
rules:
- path: "internal/(env|log)/"
linters:
- forbidigo
- path: "_test\\.go$"
linters:
- forbidigo
settings:
forbidigo:
forbid:
- pattern: "^os\\.Getenv$"
msg: "use internal/env.Get instead of os.Getenv"
- pattern: "^os\\.LookupEnv$"
msg: "use internal/env.Lookup instead of os.LookupEnv"
exclude_godoc_examples: true
analyze_types: true
govet:
enable-all: true
disable:
Expand Down
48 changes: 48 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,54 @@ Sample PR: <https://github.com/DataDog/dd-trace-go/pull/3365>

Please view our contrib [README.md](contrib/README.md) for information on integrations. If you need support for a new integration, please file an issue to discuss before opening a PR.

### Working with environment variables

When working with environment variables, direct use of `os.Getenv` and `os.LookupEnv` is not permitted. Instead, all environment variables must be validated against an [allowed list](./internal/env/supported_configurations.gen.go) using `env.Get` and `env.Lookup` from the [`internal/env`](./internal/env.go) package (or [`instrumentation/env`](./instrumentation/env/env.go) when working on contrib packages). This validation system helps us automatically detect newly introduced variables and ensures they are properly documented and tracked.

Once a new environment variable is added to the codebase, Datadog maintainers will also add it to Datadog's internal configuration registry for tracking and documentation purposes.

Upon each tracer release, new configuration keys are automatically tagged by our [CI pipeline](./.gitlab/config-validation.yml) to track when they were introduced.

#### Adding new environment variables using configinverter

The `configinverter` tool provides a command to add new environment variable keys to the `supported_configurations.json` file and regenerate the corresponding Go code.

```sh
go run ./scripts/configinverter/main.go add DD_MY_NEW_KEY
```
Comment on lines +308 to +314

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I want to add a new environment variable, I only have to run this command, and that's it? Or, are there additional steps?

Would be nice to see an explicit play by play, if it's anything more than this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the other step needed when adding env var. This should be complete to have a play by play of what needs to be done.


After adding it to the codebase the key also needs to be added to the [registry](https://feature-parity.us1.prod.dog/#/configurations?viewType=configurations) by an **internal contributor**.
If the key already exists in the registry because another language already registred it this step can be skipped.
Not adding the key to the registry will fail the CI step in charge of checking the local file against the registry.

#### Auto-detection via tests

All environment variables should be read at least once by a test. When this happens, a helper automatically detects the usage and adds the variable to the [JSON configuration file](./internal/env/supported_configurations.json). Since the variable isn't yet present in the generated code, it won't read any actual environment values initially, but it will be recorded for code generation.

Note that CI jobs will fail if new keys are detected but not properly generated into the code.

You can check for keys that have been added to the JSON file but not yet generated into code:

```sh
go run ./scripts/configinverter/main.go check
```

After the first test run that detects your new environment variable, regenerate the code:

```sh
go run ./scripts/configinverter/main.go generate
```

After adding it to the codebase the key also needs to be added to the [registry](https://feature-parity.us1.prod.dog/#/configurations?viewType=configurations) by an **internal contributor**.
If the key already exists in the registry because another language already registred it this step can be skipped.
Not adding the key to the registry will fail the CI step in charge of checking the local file against the registry.

#### Handling related CI failures

The GitLab `validate_supported_configurations_local_file` job validates the JSON file content against Datadog's [configuration registry](https://feature-parity.us1.prod.dog/#/configurations?viewType=configurations) to ensure every configuration key is properly registered and documented. If keys are missing from the registry, the job will fail and display the list of missing keys in the output. These keys must be added to the internal registry by Datadog maintainers for the check to pass, the key will need to be documented before merging the PR onto main.

Additionally, multiple CI jobs include a [step](./.github/actions/supported_configurations_validation/action.yml) that checks for newly discovered environment variables during test execution and will fail if keys are missing from the generated list. To resolve this failure, use one of the two methods described above to add the key to the generated list.

### Adding Go Modules

When adding a new dependency, especially for `contrib/` packages, prefer the minimum secure versions of any modules rather than the latest versions. This is to avoid forcing upgrades on downstream users for modules such as `google.golang.org/grpc` which often introduce breaking changes within minor versions.
Expand Down
6 changes: 3 additions & 3 deletions contrib/database/sql/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ package sql
import (
"database/sql/driver"
"math"
"os"
"reflect"
"strings"

"github.com/DataDog/dd-trace-go/v2/ddtrace/ext"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
"github.com/DataDog/dd-trace-go/v2/instrumentation"
"github.com/DataDog/dd-trace-go/v2/instrumentation/env"
)

type config struct {
Expand Down Expand Up @@ -139,9 +139,9 @@ type registerConfig = config

func defaults(cfg *config, driverName string, rc *registerConfig) {
cfg.analyticsRate = instr.AnalyticsRate(false)
mode := os.Getenv("DD_DBM_PROPAGATION_MODE")
mode := env.Get("DD_DBM_PROPAGATION_MODE")
if mode == "" {
mode = os.Getenv("DD_TRACE_SQL_COMMENT_INJECTION_MODE")
mode = env.Get("DD_TRACE_SQL_COMMENT_INJECTION_MODE")
}
cfg.dbmPropagationMode = tracer.DBMPropagationMode(mode)
cfg.serviceName = defaultServiceName(driverName, rc)
Expand Down
4 changes: 2 additions & 2 deletions contrib/database/sql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import (
"context"
"database/sql"
"database/sql/driver"
"os"
"reflect"
"sync"
"sync/atomic"
"time"

sqlinternal "github.com/DataDog/dd-trace-go/contrib/database/sql/v2/internal"
"github.com/DataDog/dd-trace-go/v2/instrumentation"
"github.com/DataDog/dd-trace-go/v2/instrumentation/env"
)

const componentName = instrumentation.PackageDatabaseSQL
Expand Down Expand Up @@ -123,7 +123,7 @@ func Register(driverName string, driver driver.Driver, opts ...Option) {
panic("sqltrace: Register driver is nil")
}
testModeInitOnce.Do(func() {
_, ok := os.LookupEnv("__DD_TRACE_SQL_TEST")
_, ok := env.Lookup("__DD_TRACE_SQL_TEST")
testMode.Store(ok)
})
testModeEnabled := testMode.Load()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ package main

import (
"net"
"os"
"strconv"

"github.com/DataDog/dd-trace-go/v2/instrumentation/env"
)

// IntEnv returns the parsed int value of an environment variable, or
// def otherwise.
func intEnv(key string, def int) int {
vv, ok := os.LookupEnv(key)
vv, ok := env.Lookup(key)
if !ok {
return def
}
Expand All @@ -28,7 +29,7 @@ func intEnv(key string, def int) int {

// IpEnv returns the valid IP value of an environment variable, or def otherwise.
func ipEnv(key string, def net.IP) net.IP {
vv, ok := os.LookupEnv(key)
vv, ok := env.Lookup(key)
if !ok {
return def
}
Expand All @@ -45,7 +46,7 @@ func ipEnv(key string, def net.IP) net.IP {
// BoolEnv returns the parsed boolean value of an environment variable, or
// def otherwise.
func boolEnv(key string, def bool) bool {
vv, ok := os.LookupEnv(key)
vv, ok := env.Lookup(key)
if !ok {
return def
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
gocontrolplane "github.com/DataDog/dd-trace-go/contrib/envoyproxy/go-control-plane/v2"
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
"github.com/DataDog/dd-trace-go/v2/instrumentation"
"github.com/DataDog/dd-trace-go/v2/instrumentation/env"

extproc "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3"
"google.golang.org/grpc"
Expand Down Expand Up @@ -56,7 +57,7 @@ func getDefaultEnvVars() map[string]string {
// initializeEnvironment sets up required environment variables with their defaults
func initializeEnvironment() {
for k, v := range getDefaultEnvVars() {
if os.Getenv(k) == "" {
if env.Get(k) == "" {
if err := os.Setenv(k, v); err != nil {
log.Error("service_extension: failed to set %s environment variable: %s\n", k, err.Error())
}
Expand Down Expand Up @@ -101,6 +102,7 @@ func loadConfig() serviceExtensionConfig {

func main() {
initializeEnvironment()

config := loadConfig()

if err := configureObservabilityMode(config.observabilityMode); err != nil {
Expand Down
Loading
Loading