![]() |
VOOZH | about |
You can add Datadog Feature Flags to an application that uses OpenTelemetry (OTel) for tracing. Datadog supports two integration options. In both cases, feature flags evaluate correctly and your existing OpenTelemetry API instrumentation code remains the same.
Choose an integration option based on whether you can change your tracing provider initialization:
If you can change your tracing provider initialization, Option A is recommended. If you cannot change your tracing provider, use Option B to adopt feature flags without changing your OTel trace pipeline.
Follow the Datadog Server-Side Feature Flags installation guide for your language.
In this option, the Datadog SDK replaces the OTel SDK as the TracerProvider. Your existing OpenTelemetry API instrumentation code — spans, attributes, events, and context propagation — stays the same.
.env
DD_TRACE_OTEL_ENABLED=true
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>Program.cs
using OpenFeature;
using Datadog.FeatureFlags.OpenFeature;
// Register the Datadog OpenFeature provider
var ffProvider = new DatadogProvider();
await Api.Instance.SetProviderAsync(ffProvider);
var client = Api.Instance.GetClient("my-service");
// Your existing OpenTelemetry API calls continue to work unchangedFor more detail, see OpenTelemetry API Support for .NET.
.env
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>main.go
import("log"ddotel"github.com/DataDog/dd-trace-go/v2/ddtrace/opentelemetry""github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"ddopenfeature"github.com/DataDog/dd-trace-go/v2/openfeature""github.com/open-feature/go-sdk/openfeature""go.opentelemetry.io/otel")funcmain(){tracer.Start()defertracer.Stop()// Register the Datadog SDK as the OpenTelemetry TracerProviderotelProvider:=ddotel.NewTracerProvider()deferotelProvider.Shutdown()otel.SetTracerProvider(otelProvider)// Register the Datadog OpenFeature providerflagProvider,err:=ddopenfeature.NewDatadogProvider(ddopenfeature.ProviderConfig{})iferr!=nil{log.Fatalf("Failed to create provider: %v",err)}deferflagProvider.Shutdown()iferr:=openfeature.SetProviderAndWait(flagProvider);err!=nil{log.Fatalf("Failed to set provider: %v",err)}client:=openfeature.NewClient("my-service")// Your existing OpenTelemetry API calls continue to work unchanged}For more detail, see OpenTelemetry API Support for Go.
.env
DD_TRACE_OTEL_ENABLED=true
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>
DD_VERSION=<YOUR_APP_VERSION>Main.java
importdev.openfeature.sdk.OpenFeatureAPI;importdev.openfeature.sdk.Client;importdatadog.trace.api.openfeature.Provider;// Register the Datadog OpenFeature providerOpenFeatureAPIapi=OpenFeatureAPI.getInstance();api.setProviderAndWait(newProvider());Clientclient=api.getClient("my-app");/* Your existing OpenTelemetry API calls continue to work unchanged */Note: Depend only on the OpenTelemetry API, not the OpenTelemetry SDK. For more detail, see OpenTelemetry API Support for Java.
.env
DD_TRACE_OTEL_ENABLED=true
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.js
import tracer from 'dd-trace';
import { OpenFeature } from '@openfeature/server-sdk';
import * as otel from '@opentelemetry/api';
tracer.init({
experimental: {
flaggingProvider: {
enabled: true,
},
},
});
// Register the Datadog SDK as the OpenTelemetry TracerProvider
const provider = new tracer.TracerProvider();
provider.register();
// Register the Datadog OpenFeature provider
OpenFeature.setProvider(tracer.openfeature);
// Your existing @opentelemetry/api calls continue to work unchanged:
const otelTracer = otel.trace.getTracer('my-service');
otelTracer.startActiveSpan('my-operation', (span) => { ... });For more detail, see OpenTelemetry API Support for Node.js.
.env
DD_TRACE_OTEL_ENABLED=true
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.py
from ddtrace import tracer
from openfeature import api
from ddtrace.openfeature import DataDogProvider
tracer.configure()
# Register the Datadog OpenFeature provider
provider = DataDogProvider()
api.set_provider(provider)
client = api.get_client()
# Your existing OpenTelemetry API calls continue to work unchangedFor more detail, see OpenTelemetry API Support for Python.
.env
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.rb
require 'datadog'
require 'opentelemetry/sdk'
require 'datadog/opentelemetry'
require 'open_feature/sdk'
require 'datadog/open_feature/provider'
# Enable remote configuration and OpenFeature integration
Datadog.configure do |c|
c.remote.enabled = true
c.open_feature.enabled = true
end
# Register the Datadog OpenFeature provider
OpenFeature::SDK.configure do |c|
c.set_provider_and_wait(Datadog::OpenFeature::Provider.new)
end
client = OpenFeature::SDK.build_client
# Your existing OpenTelemetry API calls continue to work unchangedFor more detail, see OpenTelemetry API Support for Ruby.
Note: The OpenFeature adapter requires PHP 8 or later.
.env
DD_TRACE_OTEL_ENABLED=true
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DDTrace\OpenFeature\DataDogProvider;
use OpenFeature\OpenFeatureAPI;
// Register the Datadog OpenFeature provider
$api = OpenFeatureAPI::getInstance();
$api->setProvider(new DataDogProvider());
$client = $api->getClient('my-service');
// Your existing OpenTelemetry API calls continue to work unchanged
For more detail, see OpenTelemetry API Support for PHP.
In this option, your existing OTel SDK remains the TracerProvider for tracing. Add the Datadog SDK only for feature flag delivery through Remote Configuration. Your OTel SDK initialization, exporters, and instrumentation stay unchanged.
.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>Program.cs
using OpenFeature;
using Datadog.FeatureFlags.OpenFeature;
// Register the Datadog OpenFeature provider
var provider = new DatadogProvider();
await Api.Instance.SetProviderAsync(provider);
var client = Api.Instance.GetClient("my-service");
// Your existing OpenTelemetry SDK initialization stays unchanged.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>main.go
import("log""github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"ddopenfeature"github.com/DataDog/dd-trace-go/v2/openfeature""github.com/open-feature/go-sdk/openfeature")funcmain(){tracer.Start()defertracer.Stop()// Register the Datadog OpenFeature providerflagProvider,err:=ddopenfeature.NewDatadogProvider(ddopenfeature.ProviderConfig{})iferr!=nil{log.Fatalf("Failed to create provider: %v",err)}deferflagProvider.Shutdown()iferr:=openfeature.SetProviderAndWait(flagProvider);err!=nil{log.Fatalf("Failed to set provider: %v",err)}client:=openfeature.NewClient("my-service")// Your existing OpenTelemetry SDK initialization stays unchanged}.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>
DD_VERSION=<YOUR_APP_VERSION>Main.java
importdev.openfeature.sdk.OpenFeatureAPI;importdev.openfeature.sdk.Client;importdatadog.trace.api.openfeature.Provider;// Register the Datadog OpenFeature providerOpenFeatureAPIapi=OpenFeatureAPI.getInstance();api.setProviderAndWait(newProvider());Clientclient=api.getClient("my-app");/* Your existing OpenTelemetry SDK initialization stays unchanged */.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.js
import tracer from 'dd-trace';
import { OpenFeature } from '@openfeature/server-sdk';
tracer.init({
plugins: false,
experimental: {
flaggingProvider: {
enabled: true,
},
},
});
// Register the Datadog OpenFeature provider
OpenFeature.setProvider(tracer.openfeature);
// Your existing OpenTelemetry SDK initialization stays unchanged
.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.py
from ddtrace import tracer
from openfeature import api
from ddtrace.openfeature import DataDogProvider
tracer.configure()
# Register the Datadog OpenFeature provider
provider = DataDogProvider()
api.set_provider(provider)
client = api.get_client()
# Your existing OpenTelemetry SDK initialization stays unchanged.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.rb
require 'datadog'
require 'open_feature/sdk'
require 'datadog/open_feature/provider'
Datadog.configure do |c|
c.remote.enabled = true
c.open_feature.enabled = true
end
# Register the Datadog OpenFeature provider
OpenFeature::SDK.configure do |c|
c.set_provider_and_wait(Datadog::OpenFeature::Provider.new)
end
client = OpenFeature::SDK.build_client
# Your existing OpenTelemetry SDK initialization stays unchangedNote: The OpenFeature adapter requires PHP 8 or later.
.env
DD_APM_TRACING_ENABLED=false
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
DD_METRICS_OTEL_ENABLED=true
DD_SERVICE=<YOUR_SERVICE_NAME>
DD_ENV=<YOUR_ENVIRONMENT>app.php
<?php
require_once __DIR__ . '/vendor/autoload.php';
use DDTrace\OpenFeature\DataDogProvider;
use OpenFeature\OpenFeatureAPI;
// Register the Datadog OpenFeature provider
$api = OpenFeatureAPI::getInstance();
$api->setProvider(new DataDogProvider());
$client = $api->getClient('my-service');
// Your existing OpenTelemetry SDK initialization stays unchanged
After you initialize the provider, evaluate flags with the OpenFeature client. Flag evaluation uses locally cached configuration, so evaluations do not make network requests.
using OpenFeature.Model;
var evalCtx = EvaluationContext.Builder()
.SetTargetingKey("user-123")
.Set("companyID", "acme-corp")
.Build();
var isEnabled = await client.GetBooleanValueAsync("my-flag", false, evalCtx);evalCtx:=openfeature.NewEvaluationContext("user-123",map[string]interface{}{"companyID":"acme-corp",},)enabled,err:=client.BooleanValue(context.Background(),"my-flag",false,evalCtx)importdev.openfeature.sdk.EvaluationContext;importdev.openfeature.sdk.MutableContext;EvaluationContextcontext=newMutableContext("user-123").add("companyID","acme-corp");booleanisEnabled=client.getBooleanValue("my-flag",false,context);import { OpenFeature } from '@openfeature/server-sdk';
const client = OpenFeature.getClient();
const evaluationContext = {
targetingKey: req.session?.userID ?? 'unknown',
companyID: req.session?.companyID,
};
const isEnabled = await client.getBooleanValue(
'my-flag',
false,
evaluationContext,
);from openfeature.evaluation_context import EvaluationContext
eval_ctx = EvaluationContext(
targeting_key="user-123",
attributes={"companyID": "acme-corp"},
)
is_enabled = client.get_boolean_value("my-flag", False, eval_ctx)context = OpenFeature::SDK::EvaluationContext.new(
targeting_key: 'user-123',
companyID: 'acme-corp',
)
is_enabled = client.fetch_boolean_value(
flag_key: 'my-flag',
default_value: false,
evaluation_context: context,
)use OpenFeature\implementation\flags\Attributes;
use OpenFeature\implementation\flags\EvaluationContext;
$context = new EvaluationContext(
'user-123',
new Attributes(['companyID' => 'acme-corp'])
);
$isEnabled = $client->getBooleanValue('my-flag', false, $context);In both integration options, feature flags evaluate the same way. Flag configurations are delivered through the same Remote Configuration channel.
For complete setup instructions, typed getters, evaluation context requirements, and testing patterns, see your language’s server-side SDK documentation.
Additional helpful documentation, links, and articles:
| |