Skip to content

Commit

Permalink
feat: improvements to OpenTelemetry metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
evansims committed Jul 23, 2024
1 parent b1e03e5 commit f0617f3
Show file tree
Hide file tree
Showing 8 changed files with 293 additions and 101 deletions.
215 changes: 182 additions & 33 deletions src/main/java/dev/openfga/sdk/api/OpenFgaApi.java

Large diffs are not rendered by default.

11 changes: 8 additions & 3 deletions src/main/java/dev/openfga/sdk/api/auth/OAuth2Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

package dev.openfga.sdk.api.auth;

import static dev.openfga.sdk.util.StringUtil.isNullOrWhitespace;

import dev.openfga.sdk.api.client.ApiClient;
import dev.openfga.sdk.api.client.ApiResponse;
import dev.openfga.sdk.api.client.HttpRequestAttempt;
Expand Down Expand Up @@ -71,9 +73,12 @@ public CompletableFuture<String> getAccessToken() throws FgaInvalidParameterExce
Map<Attribute, String> attributesMap = new HashMap<>();

try {
attributesMap.put(
dev.openfga.sdk.telemetry.Attributes.REQUEST_CLIENT_ID,
config.getCredentials().getClientCredentials().getClientId());
if (!isNullOrWhitespace(
config.getCredentials().getClientCredentials().getClientId())) {
attributesMap.put(
dev.openfga.sdk.telemetry.Attributes.FGA_CLIENT_REQUEST_CLIENT_ID,
config.getCredentials().getClientCredentials().getClientId());
}
} catch (Exception e) {
}

Expand Down
40 changes: 26 additions & 14 deletions src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,19 @@ public CompletableFuture<ApiResponse<T>> attemptHttpRequest() throws ApiExceptio
requestBodyPublisher.subscribe(new BodyLogger(System.err, "request")));
}

addTelemetryAttribute(Attributes.HTTP_HOST, configuration.getApiUrl());
addTelemetryAttribute(Attributes.HTTP_METHOD, request.method());
addTelemetryAttribute(Attributes.HTTP_HOST, request.uri().getHost());
addTelemetryAttribute(Attributes.URL_SCHEME, request.uri().getScheme());
addTelemetryAttribute(Attributes.URL_FULL, request.uri().toString());
addTelemetryAttribute(Attributes.HTTP_REQUEST_METHOD, request.method());
addTelemetryAttribute(Attributes.USER_AGENT, configuration.getUserAgent());

try {
addTelemetryAttribute(
Attributes.REQUEST_CLIENT_ID,
configuration.getCredentials().getClientCredentials().getClientId());
if (!isNullOrWhitespace(
configuration.getCredentials().getClientCredentials().getClientId())) {
addTelemetryAttribute(
Attributes.FGA_CLIENT_REQUEST_CLIENT_ID,
configuration.getCredentials().getClientCredentials().getClientId());
}
} catch (Exception e) {
}

Expand Down Expand Up @@ -119,20 +125,26 @@ private CompletableFuture<ApiResponse<T>> attemptHttpRequest(
}

addTelemetryAttributes(Attributes.fromHttpResponse(response, this.configuration.getCredentials()));
addTelemetryAttribute(Attributes.REQUEST_RETRIES, String.valueOf(retryNumber));
addTelemetryAttribute(Attributes.HTTP_REQUEST_RESEND_COUNT, String.valueOf(retryNumber + 1));

if (response.headers().firstValue("fga-query-duration-ms").isPresent()) {
double queryDuration = Double.parseDouble(response.headers()
String queryDuration = response.headers()
.firstValue("fga-query-duration-ms")
.get());
telemetry.metrics().queryDuration(queryDuration, this.getTelemetryAttributes());
.orElse(null);

if (!isNullOrWhitespace(queryDuration)) {
addTelemetryAttribute(Attributes.HTTP_SERVER_REQUEST_DURATION, queryDuration);

double queryDurationDouble = Double.parseDouble(queryDuration);
telemetry.metrics().queryDuration(queryDurationDouble, this.getTelemetryAttributes());
}
}

telemetry
.metrics()
.requestDuration(
(double) (System.currentTimeMillis() - this.requestStarted),
this.getTelemetryAttributes());
Double requestDuration = (double) (System.currentTimeMillis() - requestStarted);

telemetry.metrics().requestDuration(requestDuration, this.getTelemetryAttributes());

addTelemetryAttribute(Attributes.HTTP_CLIENT_REQUEST_DURATION, String.valueOf(requestDuration));

return deserializeResponse(response)
.thenApply(modeledResponse -> new ApiResponse<>(
Expand Down
90 changes: 63 additions & 27 deletions src/main/java/dev/openfga/sdk/telemetry/Attributes.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dev.openfga.sdk.telemetry;

import static dev.openfga.sdk.util.StringUtil.isNullOrWhitespace;

import dev.openfga.sdk.api.client.ApiResponse;
import dev.openfga.sdk.api.configuration.Credentials;
import dev.openfga.sdk.api.configuration.CredentialsMethod;
Expand All @@ -13,55 +15,81 @@
* This class represents a collection of attributes used for telemetry purposes.
*/
public class Attributes {

/**
* Attribute representing the model ID of a request.
* The client ID associated with a request, if applicable.
*/
public static final Attribute REQUEST_MODEL_ID = new Attribute("fga-client.request.model_id");
public static final Attribute FGA_CLIENT_REQUEST_CLIENT_ID = new Attribute("fga-client.request.client_id");

/**
* Attribute representing the method of a request.
* The FGA method/action that is being performed in a request, in camelCase. For example, "check" or "listObjects".
*/
public static final Attribute REQUEST_METHOD = new Attribute("fga-client.request.method");
public static final Attribute FGA_CLIENT_REQUEST_METHOD = new Attribute("fga-client.request.method");

/**
* Attribute representing the store ID of a request.
* The authorization model ID sent as part of a request, if applicable.
*/
public static final Attribute REQUEST_STORE_ID = new Attribute("fga-client.request.store_id");
public static final Attribute FGA_CLIENT_REQUEST_MODEL_ID = new Attribute("fga-client.request.model_id");

/**
* Attribute representing the client ID of a request.
* The store ID sent as part of a request.
*/
public static final Attribute REQUEST_CLIENT_ID = new Attribute("fga-client.request.client_id");
public static final Attribute FGA_CLIENT_REQUEST_STORE_ID = new Attribute("fga-client.request.store_id");

/**
* Attribute representing the number of retries for a request.
* The authorization model ID the server used when evaluating a request, if applicable.
*/
public static final Attribute REQUEST_RETRIES = new Attribute("fga-client.request.retries");
public static final Attribute FGA_CLIENT_RESPONSE_MODEL_ID = new Attribute("fga-client.response.model_id");

/**
* Attribute representing the model ID of a response.
* The user that is associated with the action of a request for check and listObjects.
*/
public static final Attribute RESPONSE_MODEL_ID = new Attribute("fga-client.response.model_id");
public static final Attribute FGA_CLIENT_USER = new Attribute("fga-client.user");

/**
* Attribute representing the user of a client.
* The total request time for a request.
*/
public static final Attribute CLIENT_USER = new Attribute("fga-client.user");
public static final Attribute HTTP_CLIENT_REQUEST_DURATION = new Attribute("http.client.request.duration");

/**
* Attribute representing the host of an HTTP request.
* The host identifier of the origin a request was sent to.
*/
public static final Attribute HTTP_HOST = new Attribute("http.host");

/**
* Attribute representing the method of an HTTP request.
* The HTTP method in a request.
*/
public static final Attribute HTTP_REQUEST_METHOD = new Attribute("http.request.method");

/**
* The number of retries attempted (starting from 1, for the original request.)
*/
public static final Attribute HTTP_METHOD = new Attribute("http.method");
public static final Attribute HTTP_REQUEST_RESEND_COUNT = new Attribute("http.request.resend_count");

/**
* Attribute representing the status code of an HTTP response.
* The status code returned by the server in response to a request.
*/
public static final Attribute HTTP_STATUS_CODE = new Attribute("http.status_code");
public static final Attribute HTTP_RESPONSE_STATUS_CODE = new Attribute("http.response.status_code");

/**
* How long it took the server to internally process and evaluate a request.
*/
public static final Attribute HTTP_SERVER_REQUEST_DURATION = new Attribute("http.server.request.duration");

/**
* The scheme used in a request.
*/
public static final Attribute URL_SCHEME = new Attribute("url.scheme");

/**
* The the complete URL used in a request.
*/
public static final Attribute URL_FULL = new Attribute("url.full");

/**
* The user agent of a request.
*/
public static final Attribute USER_AGENT = new Attribute("user_agent.original");

/**
* Prepares the attributes for OpenTelemetry publishing by converting them into the expected format.
Expand Down Expand Up @@ -92,19 +120,23 @@ public static Map<Attribute, String> fromHttpResponse(HttpResponse<?> response,
Map<Attribute, String> attributes = new HashMap<>();

if (response != null) {
attributes.put(HTTP_STATUS_CODE, String.valueOf(response.statusCode()));
attributes.put(HTTP_RESPONSE_STATUS_CODE, String.valueOf(response.statusCode()));

String responseModelId = response.headers()
.firstValue("openfga-authorization-model-id")
.orElse(null);

if (responseModelId != null) {
attributes.put(RESPONSE_MODEL_ID, responseModelId);
if (!isNullOrWhitespace(responseModelId)) {
attributes.put(FGA_CLIENT_RESPONSE_MODEL_ID, responseModelId);
}
}

if (credentials != null && credentials.getCredentialsMethod() == CredentialsMethod.CLIENT_CREDENTIALS) {
attributes.put(REQUEST_CLIENT_ID, credentials.getClientCredentials().getClientId());
if (!isNullOrWhitespace(credentials.getClientCredentials().getClientId())) {
attributes.put(
FGA_CLIENT_REQUEST_CLIENT_ID,
credentials.getClientCredentials().getClientId());
}
}

return attributes;
Expand All @@ -122,19 +154,23 @@ public static Map<Attribute, String> fromApiResponse(ApiResponse<?> response, Cr
Map<Attribute, String> attributes = new HashMap<>();

if (response != null) {
attributes.put(HTTP_STATUS_CODE, String.valueOf(response.getStatusCode()));
attributes.put(HTTP_RESPONSE_STATUS_CODE, String.valueOf(response.getStatusCode()));

List<String> responseModelIdList =
response.getHeaders().getOrDefault("openfga-authorization-model-id", null);
String responseModelId = responseModelIdList != null ? responseModelIdList.get(0) : null;

if (responseModelId != null) {
attributes.put(RESPONSE_MODEL_ID, responseModelId);
if (!isNullOrWhitespace(responseModelId)) {
attributes.put(FGA_CLIENT_RESPONSE_MODEL_ID, responseModelId);
}
}

if (credentials != null && credentials.getCredentialsMethod() == CredentialsMethod.CLIENT_CREDENTIALS) {
attributes.put(REQUEST_CLIENT_ID, credentials.getClientCredentials().getClientId());
if (!isNullOrWhitespace(credentials.getClientCredentials().getClientId())) {
attributes.put(
FGA_CLIENT_REQUEST_CLIENT_ID,
credentials.getClientCredentials().getClientId());
}
}

return attributes;
Expand Down
14 changes: 1 addition & 13 deletions src/main/java/dev/openfga/sdk/telemetry/Counter.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,16 @@
*/
public class Counter {
private final String name;
private final String unit;
private final String description;

/**
* Constructs a new Counter with the specified name, unit, and description.
*
* @param name the name of the counter
* @param unit the unit of measurement for the counter
* @param description the description of the counter
*/
public Counter(String name, String unit, String description) {
public Counter(String name, String description) {
this.name = name;
this.unit = unit;
this.description = description;
}

Expand All @@ -30,15 +27,6 @@ public String getName() {
return name;
}

/**
* Returns the unit of measurement for the counter.
*
* @return the unit of measurement for the counter
*/
public String getUnit() {
return unit;
}

/**
* Returns the description of the counter.
*
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/dev/openfga/sdk/telemetry/Counters.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ public class Counters {
* The CREDENTIALS_REQUEST counter represents the number of times an access token is requested.
*/
public static final Counter CREDENTIALS_REQUEST = new Counter(
"fga-client.credentials.request", "milliseconds", "The number of times an access token is requested.");
"fga-client.credentials.request",
"The total number of times new access tokens have been requested using ClientCredentials.");
}
14 changes: 8 additions & 6 deletions src/main/java/dev/openfga/sdk/telemetry/Histograms.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
*/
public class Histograms {
/**
* A histogram for measuring the duration of a request.
* A histogram for measuring the total roundtrip time it took to process a request, including the time it took to send the request and receive the response.
*/
public static final Histogram REQUEST_DURATION = new Histogram(
"fga-client.request.duration", "milliseconds", "How long it took for a request to be fulfilled.");
public static final Histogram REQUEST_DURATION =
new Histogram("fga-client.request.duration", "milliseconds", "Total roundtrip time for a request.");

/**
* A histogram for measuring the duration of a query request.
* A histogram for measuring how long the FGA server took to process and evaluate a request.
*/
public static final Histogram QUERY_DURATION =
new Histogram("fga-client.query.duration", "milliseconds", "How long it took to perform a query request.");
public static final Histogram QUERY_DURATION = new Histogram(
"fga-client.query.duration",
"milliseconds",
"How long the FGA server took to process and evaluate a request.");
}
7 changes: 3 additions & 4 deletions src/main/java/dev/openfga/sdk/telemetry/Metrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public LongCounter getCounter(Counter counter, Long value, Map<Attribute, String
counter.getName(),
meter.counterBuilder(counter.getName())
.setDescription(counter.getDescription())
.setUnit(counter.getUnit())
.build());
}

Expand Down Expand Up @@ -86,7 +85,7 @@ public DoubleHistogram getHistogram(Histogram histogram, Double value, Map<Attri
}

/**
* Returns a LongCounter metric instance, for publishing the number of times an access token is requested.
* Returns a LongCounter counter for tracking the number of times an access token is requested through ClientCredentials.
*
* @param value The value to be added to the counter.
* @param attributes A map of attributes associated with the metric.
Expand All @@ -98,7 +97,7 @@ public LongCounter credentialsRequest(Long value, Map<Attribute, String> attribu
}

/**
* Returns a DoubleHistogram metric instance, for publishing the duration of requests.
* Returns a DoubleHistogram histogram for measuring the total roundtrip time it took to process a request, including the time it took to send the request and receive the response.
*
* @param value The value to be recorded in the histogram.
* @param attributes A map of attributes associated with the metric.
Expand All @@ -108,7 +107,7 @@ public DoubleHistogram requestDuration(Double value, Map<Attribute, String> attr
}

/**
* Returns a DoubleHistogram metric instance, for publishing the duration of queries.
* Returns a DoubleHistogram for measuring how long the FGA server took to process and evaluate a request.
*
* @param value The value to be recorded in the histogram.
* @param attributes A map of attributes associated with the metric.
Expand Down

0 comments on commit f0617f3

Please sign in to comment.