Skip to content

Commit 7f2d4f6

Browse files
add go docs for openfeature implementation (#33234)
* add go docs for openfeature implementation * add docs for blocking init, custom timeout, non blocking * no agent version
1 parent 41bbb91 commit 7f2d4f6

File tree

1 file changed

+256
-2
lines changed
  • content/en/feature_flags/server

1 file changed

+256
-2
lines changed

content/en/feature_flags/server/go.md

Lines changed: 256 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,263 @@ Feature Flags are in Preview. Complete the form to request access.
1616

1717
## Overview
1818

19-
This page describes how to instrument your Go application with the Datadog Feature Flags SDK.
19+
This page describes how to instrument your Go application with the Datadog Feature Flags SDK. The Go SDK integrates with [OpenFeature][1], an open standard for feature flag management, and uses the Datadog tracer's Remote Configuration to receive flag updates in real time.
2020

21-
Documentation coming soon.
21+
This guide explains how to install and enable the SDK, create an OpenFeature client, and evaluate feature flags in your application.
22+
23+
## Prerequisites
24+
25+
Before setting up the Go Feature Flags SDK, ensure you have:
26+
27+
- **Datadog Agent** with [Remote Configuration][2] enabled
28+
- **Datadog Go tracer** `dd-trace-go` version 2.4.0 or later
29+
30+
Set the following environment variables:
31+
32+
{{< code-block lang="bash" >}}
33+
# Required: Enable the feature flags provider
34+
DD_EXPERIMENTAL_FLAGGING_PROVIDER_ENABLED=true
35+
36+
# Required: Service identification
37+
DD_SERVICE=<YOUR_SERVICE_NAME>
38+
DD_ENV=<YOUR_ENVIRONMENT>
39+
{{< /code-block >}}
40+
41+
## Installation
42+
43+
Install the Datadog OpenFeature provider package:
44+
45+
{{< code-block lang="bash" >}}
46+
go get github.com/DataDog/dd-trace-go/v2/openfeature
47+
{{< /code-block >}}
48+
49+
You also need the OpenFeature Go SDK:
50+
51+
{{< code-block lang="bash" >}}
52+
go get github.com/open-feature/go-sdk/openfeature
53+
{{< /code-block >}}
54+
55+
## Initialize the SDK
56+
57+
Start the Datadog tracer and register the Datadog OpenFeature provider. The tracer must be started first because it enables Remote Configuration, which delivers flag configurations to your application.
58+
59+
### Blocking initialization
60+
61+
Use `SetProviderAndWait` to block until the initial flag configuration is received. This ensures flags are ready before your application starts handling requests.
62+
63+
{{< code-block lang="go" >}}
64+
package main
65+
66+
import (
67+
"log"
68+
69+
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
70+
ddopenfeature "github.com/DataDog/dd-trace-go/v2/openfeature"
71+
"github.com/open-feature/go-sdk/openfeature"
72+
)
73+
74+
func main() {
75+
// Start the Datadog tracer (enables Remote Config)
76+
tracer.Start()
77+
defer tracer.Stop()
78+
79+
// Create the Datadog OpenFeature provider
80+
provider, err := ddopenfeature.NewDatadogProvider(ddopenfeature.ProviderConfig{})
81+
if err != nil {
82+
log.Fatalf("Failed to create provider: %v", err)
83+
}
84+
defer provider.Shutdown()
85+
86+
// Register the provider and wait for initialization (default 30s timeout)
87+
if err := openfeature.SetProviderAndWait(provider); err != nil {
88+
log.Fatalf("Failed to set provider: %v", err)
89+
}
90+
91+
// Create the OpenFeature client
92+
client := openfeature.NewClient("my-service")
93+
94+
// Your application code here
95+
}
96+
{{< /code-block >}}
97+
98+
To specify a custom timeout, use `SetProviderAndWaitWithContext`:
99+
100+
{{< code-block lang="go" >}}
101+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
102+
defer cancel()
103+
104+
if err := openfeature.SetProviderAndWaitWithContext(ctx, provider); err != nil {
105+
log.Fatalf("Failed to set provider: %v", err)
106+
}
107+
{{< /code-block >}}
108+
109+
### Non-blocking initialization
110+
111+
Use `SetProvider` to register the provider without waiting. Flag evaluations return default values until the configuration is received.
112+
113+
{{< code-block lang="go" >}}
114+
package main
115+
116+
import (
117+
"log"
118+
119+
"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
120+
ddopenfeature "github.com/DataDog/dd-trace-go/v2/openfeature"
121+
"github.com/open-feature/go-sdk/openfeature"
122+
)
123+
124+
func main() {
125+
// Start the Datadog tracer (enables Remote Config)
126+
tracer.Start()
127+
defer tracer.Stop()
128+
129+
// Create the Datadog OpenFeature provider
130+
provider, err := ddopenfeature.NewDatadogProvider(ddopenfeature.ProviderConfig{})
131+
if err != nil {
132+
log.Fatalf("Failed to create provider: %v", err)
133+
}
134+
defer provider.Shutdown()
135+
136+
// Register the provider without waiting
137+
openfeature.SetProvider(provider)
138+
139+
// Create the OpenFeature client
140+
client := openfeature.NewClient("my-service")
141+
142+
// Your application code here
143+
// Flag evaluations return defaults until configuration is received
144+
}
145+
{{< /code-block >}}
146+
147+
## Create a client
148+
149+
Create an OpenFeature client to evaluate flags. You can create multiple clients with different names for different parts of your application:
150+
151+
{{< code-block lang="go" >}}
152+
// Create a client for your application
153+
client := openfeature.NewClient("my-service")
154+
{{< /code-block >}}
155+
156+
## Set the evaluation context
157+
158+
Define an evaluation context that identifies the user or entity for flag targeting. The evaluation context includes attributes used to determine which flag variations should be returned:
159+
160+
{{< code-block lang="go" >}}
161+
evalCtx := openfeature.NewEvaluationContext(
162+
"user-123", // Targeting key (typically user ID)
163+
map[string]interface{}{
164+
"email": "[email protected]",
165+
"country": "US",
166+
"tier": "premium",
167+
"age": 25,
168+
},
169+
)
170+
{{< /code-block >}}
171+
172+
The targeting key is used for consistent traffic distribution (percentage rollouts). Additional attributes enable targeting rules such as "enable for users in the US" or "enable for premium tier users."
173+
174+
## Evaluate flags
175+
176+
After setting up the provider and creating a client, you can evaluate flags throughout your application. Flag evaluation is local and fast—the SDK uses locally cached configuration data, so no network requests occur during evaluation.
177+
178+
Each flag is identified by a key (a unique string) and can be evaluated with a typed method that returns a value of the expected type. If the flag doesn't exist or cannot be evaluated, the SDK returns the provided default value.
179+
180+
### Boolean flags
181+
182+
Use `BooleanValue` for flags that represent on/off or true/false conditions:
183+
184+
{{< code-block lang="go" >}}
185+
ctx := context.Background()
186+
187+
enabled, err := client.BooleanValue(ctx, "new-checkout-flow", false, evalCtx)
188+
if err != nil {
189+
log.Printf("Error evaluating flag: %v", err)
190+
}
191+
192+
if enabled {
193+
showNewCheckout()
194+
} else {
195+
showLegacyCheckout()
196+
}
197+
{{< /code-block >}}
198+
199+
### String flags
200+
201+
Use `StringValue` for flags that select between multiple variants or configuration strings:
202+
203+
{{< code-block lang="go" >}}
204+
theme, err := client.StringValue(ctx, "ui-theme", "light", evalCtx)
205+
if err != nil {
206+
log.Printf("Error evaluating flag: %v", err)
207+
}
208+
209+
switch theme {
210+
case "dark":
211+
setDarkTheme()
212+
case "light":
213+
setLightTheme()
214+
default:
215+
setLightTheme()
216+
}
217+
{{< /code-block >}}
218+
219+
### Numeric flags
220+
221+
For numeric flags, use `IntValue` or `FloatValue`. These are appropriate when a feature depends on a numeric parameter such as a limit, percentage, or multiplier:
222+
223+
{{< code-block lang="go" >}}
224+
maxItems, err := client.IntValue(ctx, "cart-max-items", 20, evalCtx)
225+
if err != nil {
226+
log.Printf("Error evaluating flag: %v", err)
227+
}
228+
229+
discountRate, err := client.FloatValue(ctx, "discount-rate", 0.0, evalCtx)
230+
if err != nil {
231+
log.Printf("Error evaluating flag: %v", err)
232+
}
233+
{{< /code-block >}}
234+
235+
### Object flags
236+
237+
For structured data, use `ObjectValue`. This returns a value that can be type-asserted to maps or other complex types:
238+
239+
{{< code-block lang="go" >}}
240+
config, err := client.ObjectValue(ctx, "feature-config", map[string]interface{}{
241+
"maxRetries": 3,
242+
"timeout": 30,
243+
}, evalCtx)
244+
if err != nil {
245+
log.Printf("Error evaluating flag: %v", err)
246+
}
247+
248+
// Type assert to access the configuration
249+
if configMap, ok := config.(map[string]interface{}); ok {
250+
maxRetries := configMap["maxRetries"]
251+
timeout := configMap["timeout"]
252+
// Use configuration values
253+
}
254+
{{< /code-block >}}
255+
256+
### Flag evaluation details
257+
258+
When you need more than just the flag value, use the `*ValueDetails` methods. These return both the evaluated value and metadata explaining the evaluation:
259+
260+
{{< code-block lang="go" >}}
261+
details, err := client.BooleanValueDetails(ctx, "new-feature", false, evalCtx)
262+
if err != nil {
263+
log.Printf("Error evaluating flag: %v", err)
264+
}
265+
266+
fmt.Printf("Value: %v\n", details.Value)
267+
fmt.Printf("Variant: %s\n", details.Variant)
268+
fmt.Printf("Reason: %s\n", details.Reason)
269+
fmt.Printf("Error: %v\n", details.Error())
270+
{{< /code-block >}}
271+
272+
Flag details help you debug evaluation behavior and understand why a user received a given value.
273+
274+
[1]: https://openfeature.dev/
275+
[2]: /agent/remote_config/
22276

23277
## Further reading
24278

0 commit comments

Comments
 (0)