Skip to content

Commit 08c2306

Browse files
feat(go-feature-flag): Support Exporter Metadata
Signed-off-by: Thomas Poignant <[email protected]>
1 parent 969448a commit 08c2306

File tree

4 files changed

+66
-9
lines changed

4 files changed

+66
-9
lines changed

Diff for: providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderOptions.java

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import dev.openfeature.sdk.ProviderEvaluation;
55
import lombok.Builder;
66
import lombok.Getter;
7+
import java.util.Map;
78

89
/** GoFeatureFlagProviderOptions contains the options to initialise the provider. */
910
@Builder
@@ -90,4 +91,13 @@ public class GoFeatureFlagProviderOptions {
9091
* retrieved in the cache. default: false
9192
*/
9293
private boolean disableDataCollection;
94+
95+
/**
96+
* (optional) exporterMetadata is the metadata we send to the GO Feature Flag relay proxy when we report the
97+
* evaluation data usage.
98+
*
99+
* ‼️Important: If you are using a GO Feature Flag relay proxy before version v1.41.0, the information of this
100+
* field will not be added to your feature events.
101+
*/
102+
private Map<String, Object> exporterMetadata;
93103
}

Diff for: providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/controller/GoFeatureFlagController.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
import dev.openfeature.sdk.exceptions.TypeMismatchError;
3232
import java.io.IOException;
3333
import java.net.HttpURLConnection;
34+
import java.util.Arrays;
35+
import java.util.HashMap;
3436
import java.util.List;
37+
import java.util.Map;
3538
import java.util.concurrent.TimeUnit;
3639
import lombok.Builder;
3740
import lombok.extern.slf4j.Slf4j;
@@ -69,6 +72,9 @@ public class GoFeatureFlagController {
6972

7073
private final HttpUrl parsedEndpoint;
7174

75+
/** exporterMetadata contains the metadata to send to the collector API. */
76+
private Map<String, Object> exporterMetadata = new HashMap<>();
77+
7278
/**
7379
* etag contains the etag of the configuration, if null, it means that the configuration has never
7480
* been retrieved.
@@ -85,6 +91,7 @@ public class GoFeatureFlagController {
8591
@Builder
8692
private GoFeatureFlagController(final GoFeatureFlagProviderOptions options) throws InvalidOptions {
8793
this.apiKey = options.getApiKey();
94+
this.exporterMetadata = options.getExporterMetadata();
8895

8996
this.parsedEndpoint = HttpUrl.parse(options.getEndpoint());
9097
if (this.parsedEndpoint == null) {
@@ -218,7 +225,7 @@ public <T> EvaluationResponse<T> evaluateFlag(
218225
*/
219226
public void sendEventToDataCollector(List<Event> eventsList) {
220227
try {
221-
Events events = new Events(eventsList);
228+
Events events = new Events(eventsList, this.exporterMetadata);
222229
HttpUrl url = this.parsedEndpoint
223230
.newBuilder()
224231
.addEncodedPathSegment("v1")

Diff for: providers/go-feature-flag/src/main/java/dev/openfeature/contrib/providers/gofeatureflag/hook/events/Events.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,15 @@
99
/** Events data. */
1010
@Getter
1111
public class Events {
12-
private static final Map<String, String> meta = new HashMap<>();
13-
14-
static {
15-
meta.put("provider", "java");
16-
meta.put("openfeature", "true");
17-
}
18-
12+
private final Map<String, Object> meta = new HashMap<>();
1913
private final List<Event> events;
2014

21-
public Events(List<Event> events) {
15+
public Events(List<Event> events, Map<String, Object> exporterMetadata) {
2216
this.events = new ArrayList<>(events);
17+
this.meta.put("provider", "java");
18+
this.meta.put("openfeature", true);
19+
if (exporterMetadata != null) {
20+
this.meta.putAll(exporterMetadata);
21+
}
2322
}
2423
}

Diff for: providers/go-feature-flag/src/test/java/dev/openfeature/contrib/providers/gofeatureflag/GoFeatureFlagProviderTest.java

+41
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.nio.file.Paths;
2727
import java.util.ArrayList;
2828
import java.util.Arrays;
29+
import java.util.HashMap;
2930
import java.util.List;
3031
import java.util.Map;
3132
import lombok.SneakyThrows;
@@ -44,6 +45,7 @@
4445
@Slf4j
4546
class GoFeatureFlagProviderTest {
4647
private int publishEventsRequestsReceived = 0;
48+
private Map exporterMetadata;
4749
private int flagChangeCallCounter = 0;
4850
private boolean flagChanged404 = false;
4951

@@ -67,6 +69,7 @@ public MockResponse dispatch(RecordedRequest request) {
6769
String requestBody = request.getBody().readString(StandardCharsets.UTF_8);
6870
Map<String, Object> map = requestMapper.readValue(requestBody, Map.class);
6971
publishEventsRequestsReceived = ((List) map.get("events")).size();
72+
exporterMetadata = ((Map) map.get("meta"));
7073
if (requestBody.contains("fail_500") && publishEventsRequestsReceived == 1) {
7174
return new MockResponse().setResponseCode(502);
7275
}
@@ -944,6 +947,44 @@ void should_stop_calling_flag_change_if_receive_404() {
944947
assertEquals(1, this.flagChangeCallCounter);
945948
}
946949

950+
@SneakyThrows
951+
@Test
952+
void should_send_exporter_metadata() {
953+
Map<String, Object> customExporterMetadata = new HashMap<>();
954+
customExporterMetadata.put("version", "1.0.0");
955+
customExporterMetadata.put("intTest", 1234567890);
956+
customExporterMetadata.put("doubleTest", 12345.67890);
957+
GoFeatureFlagProvider g = new GoFeatureFlagProvider(GoFeatureFlagProviderOptions.builder()
958+
.endpoint(this.baseUrl.toString())
959+
.timeout(1000)
960+
.enableCache(true)
961+
.flushIntervalMs(150L)
962+
.exporterMetadata(customExporterMetadata)
963+
.build());
964+
String providerName = this.testName;
965+
OpenFeatureAPI.getInstance().setProviderAndWait(providerName, g);
966+
Client client = OpenFeatureAPI.getInstance().getClient(providerName);
967+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
968+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
969+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
970+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
971+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
972+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
973+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
974+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
975+
client.getBooleanDetails("bool_targeting_match", false, this.evaluationContext);
976+
Thread.sleep(150);
977+
978+
Map<String, Object> want = new HashMap<>();
979+
want.put("version", "1.0.0");
980+
want.put("intTest", 1234567890);
981+
want.put("doubleTest", 12345.6789);
982+
want.put("openfeature",true);
983+
want.put("provider", "java");
984+
assertEquals(want, this.exporterMetadata,
985+
"we should have the exporter metadata in the last event sent to the data collector");
986+
}
987+
947988
private String readMockResponse(String filename) throws Exception {
948989
URL url = getClass().getClassLoader().getResource("mock_responses/" + filename);
949990
assert url != null;

0 commit comments

Comments
 (0)