Skip to content

Commit

Permalink
feat: Telemetry for Events (SDK metadata) (#109)
Browse files Browse the repository at this point in the history
Add SDK data to Events API
  • Loading branch information
fabriziodemaria authored Mar 27, 2024
1 parent 81cfcfd commit 3447e47
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 23 deletions.
9 changes: 9 additions & 0 deletions src/main/java/com/spotify/confidence/GrpcEventUploader.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.spotify.confidence.events.v1.Event;
import com.spotify.confidence.events.v1.EventsServiceGrpc;
import com.spotify.confidence.events.v1.PublishEventsRequest;
import com.spotify.confidence.events.v1.Sdk;
import com.spotify.confidence.events.v1.SdkId;
import io.grpc.ManagedChannel;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
Expand All @@ -14,6 +16,7 @@ class GrpcEventUploader implements EventUploader {

private static final String CONTEXT = "context";
private final String clientSecret;
private final Sdk sdk;
private final ManagedChannel managedChannel;
private final EventsServiceGrpc.EventsServiceFutureStub stub;
private final Clock clock;
Expand All @@ -23,6 +26,11 @@ class GrpcEventUploader implements EventUploader {
this.managedChannel = managedChannel;
this.stub = EventsServiceGrpc.newFutureStub(managedChannel);
this.clock = clock;
this.sdk =
Sdk.newBuilder()
.setId(SdkId.SDK_ID_JAVA_CONFIDENCE)
.setVersion(SdkUtils.getSdkVersion())
.build();
}

@Override
Expand All @@ -31,6 +39,7 @@ public CompletableFuture<Boolean> upload(EventBatch batch) {
PublishEventsRequest.newBuilder()
.setClientSecret(clientSecret)
.setSendTime(Timestamp.newBuilder().setSeconds(clock.currentTimeSeconds()))
.setSdk(sdk)
.addAllEvents(
batch.events().stream()
.map(
Expand Down
22 changes: 7 additions & 15 deletions src/main/java/com/spotify/confidence/GrpcFlagResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,27 @@
import com.google.protobuf.Struct;
import com.spotify.confidence.shaded.flags.resolver.v1.*;
import io.grpc.ManagedChannel;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class GrpcFlagResolver implements FlagResolver {
private final ManagedChannel managedChannel;
private final String clientSecret;
private final String SDK_VERSION;
private static final SdkId SDK_ID = SdkId.SDK_ID_JAVA_PROVIDER;
private final Sdk sdk;

private final FlagResolverServiceGrpc.FlagResolverServiceFutureStub stub;

public GrpcFlagResolver(String clientSecret, ManagedChannel managedChannel) {
if (Strings.isNullOrEmpty(clientSecret)) {
throw new IllegalArgumentException("clientSecret must be a non-empty string.");
}

this.clientSecret = clientSecret;

try {
final Properties prop = new Properties();
prop.load(this.getClass().getResourceAsStream("/version.properties"));
this.SDK_VERSION = prop.getProperty("version");
} catch (IOException e) {
throw new RuntimeException("Can't determine version of the SDK", e);
}

this.sdk =
Sdk.newBuilder()
.setId(SdkId.SDK_ID_JAVA_PROVIDER)
.setVersion(SdkUtils.getSdkVersion())
.build();
this.managedChannel = managedChannel;
this.stub = FlagResolverServiceGrpc.newFutureStub(managedChannel);
}
Expand All @@ -45,7 +37,7 @@ public CompletableFuture<ResolveFlagsResponse> resolve(String flag, Struct conte
.setClientSecret(this.clientSecret)
.addAllFlags(List.of(flag))
.setEvaluationContext(context)
.setSdk(Sdk.newBuilder().setId(SDK_ID).setVersion(SDK_VERSION).build())
.setSdk(sdk)
.setApply(true)
.build()));
}
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/com/spotify/confidence/SdkUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.spotify.confidence;

import java.io.IOException;
import java.util.Properties;

final class SdkUtils {

private SdkUtils() {}

static String getSdkVersion() {
try {
final Properties prop = new Properties();
prop.load(SdkUtils.class.getResourceAsStream("/version.properties"));
return prop.getProperty("version");
} catch (IOException e) {
throw new RuntimeException("Can't determine version of the SDK", e);
}
}
}
8 changes: 6 additions & 2 deletions src/main/proto/confidence/events/v1/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ message PublishEventsRequest {
google.protobuf.Timestamp send_time = 3 [
(google.api.field_behavior) = REQUIRED
];
}

// Information about the SDK used to initiate the request.
Sdk sdk = 4 [
(google.api.field_behavior) = OPTIONAL
];
}

message PublishEventsResponse {
repeated EventError errors = 1;
}
}
63 changes: 59 additions & 4 deletions src/main/proto/confidence/events/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,63 @@ message EventError {
string message = 3;

enum Reason {
REASON_UNSPECIFIED = 0; // unknown error
EVENT_DEFINITION_NOT_FOUND = 1; // not transient: the event definition was not found
EVENT_SCHEMA_VALIDATION_FAILED = 2; // not transient: the schema validation failed
// unknown error
REASON_UNSPECIFIED = 0;
// not transient: the event definition was not found
EVENT_DEFINITION_NOT_FOUND = 1;
// not transient: the schema validation failed
EVENT_SCHEMA_VALIDATION_FAILED = 2;
}
}
}

// (-- api-linter: core::0123::resource-annotation=disabled
// aip.dev/not-precedent: SDKs are not internal Confidence resources. --)
message Sdk {
// Identifier of the SDK used to interact with the API.
oneof sdk {
// Name of a Confidence SDKs.
SdkId id = 1;
// Custom name for non-Confidence SDKs.
string custom_id = 2;
}

// Version of the SDK.
string version = 3 [
(google.api.field_behavior) = OPTIONAL // TODO: Make REQUIRED again when we're not SDK if default
];
}

enum SdkId {
// Unspecified enum.
SDK_ID_UNSPECIFIED = 0;
// Confidence OpenFeature Java Provider.
SDK_ID_JAVA_PROVIDER = 1;
// Confidence OpenFeature Kotlin Provider.
SDK_ID_KOTLIN_PROVIDER = 2;
// Confidence OpenFeature Swift Provider.
SDK_ID_SWIFT_PROVIDER = 3;
// Confidence OpenFeature JavaScript Provider for Web (client).
SDK_ID_JS_WEB_PROVIDER = 4;
// Confidence OpenFeature JavaScript Provider for server.
SDK_ID_JS_SERVER_PROVIDER = 5;
// Confidence OpenFeature Python Provider.
SDK_ID_PYTHON_PROVIDER = 6;
// Confidence OpenFeature GO Provider.
SDK_ID_GO_PROVIDER = 7;
// Confidence OpenFeature Ruby Provider.
SDK_ID_RUBY_PROVIDER = 8;
// Confidence OpenFeature Rust Provider.
SDK_ID_RUST_PROVIDER = 9;
// Confidence Java SDK.
SDK_ID_JAVA_CONFIDENCE = 10;
// Confidence Kotlin SDK.
SDK_ID_KOTLIN_CONFIDENCE = 11;
// Confidence Swift SDK.
SDK_ID_SWIFT_CONFIDENCE = 12;
// Confidence JavaScript SDK.
SDK_ID_JS_CONFIDENCE = 13;
// Confidence Python SDK.
SDK_ID_PYTHON_CONFIDENCE = 14;
// Confidence GO SDK.
SDK_ID_GO_CONFIDENCE = 15;
}
18 changes: 17 additions & 1 deletion src/main/proto/confidence/flags/resolver/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ message Sdk {

// Version of the SDK.
string version = 3 [
(google.api.field_behavior) = REQUIRED
(google.api.field_behavior) = OPTIONAL // TODO: Make REQUIRED again when we're not SDK if default
];
}

Expand Down Expand Up @@ -60,4 +60,20 @@ enum SdkId {
SDK_ID_PYTHON_PROVIDER = 6;
// Confidence OpenFeature GO Provider.
SDK_ID_GO_PROVIDER = 7;
// Confidence OpenFeature Ruby Provider.
SDK_ID_RUBY_PROVIDER = 8;
// Confidence OpenFeature Rust Provider.
SDK_ID_RUST_PROVIDER = 9;
// Confidence Java SDK.
SDK_ID_JAVA_CONFIDENCE = 10;
// Confidence Kotlin SDK.
SDK_ID_KOTLIN_CONFIDENCE = 11;
// Confidence Swift SDK.
SDK_ID_SWIFT_CONFIDENCE = 12;
// Confidence JavaScript SDK.
SDK_ID_JS_CONFIDENCE = 13;
// Confidence Python SDK.
SDK_ID_PYTHON_CONFIDENCE = 14;
// Confidence GO SDK.
SDK_ID_GO_CONFIDENCE = 15;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import org.junit.jupiter.api.Test;

final class FeatureProviderTest {

private static Server server;
private static ManagedChannel channel;
private static final Value DEFAULT_VALUE = new Value("string-default");
Expand Down

0 comments on commit 3447e47

Please sign in to comment.