diff --git a/CHANGELOG.md b/CHANGELOG.md index f4ea6b45..9c5e59af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased](https://github.com/openfga/java-sdk/compare/v0.9.7...HEAD) +### Added +- Add `fga-client.request.count` counter metric to track the total number of HTTP requests made to the FGA server. This metric is **disabled by default** and must be explicitly enabled via `TelemetryConfiguration`. + ## v0.9.7 ### [0.9.7](https://github.com/openfga/java-sdk/compare/v0.9.6...v0.9.7) (2026-03-17) diff --git a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java index 88f33f52..88744917 100644 --- a/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java +++ b/src/main/java/dev/openfga/sdk/api/client/HttpRequestAttempt.java @@ -219,6 +219,7 @@ private CompletableFuture> processHttpResponse( Double requestDuration = (double) (System.currentTimeMillis() - requestStarted); telemetry.metrics().requestDuration(requestDuration, this.getTelemetryAttributes()); + telemetry.metrics().requestCount(1L, this.getTelemetryAttributes()); return deserializeResponse(response) .thenApply(modeledResponse -> new ApiResponse<>( diff --git a/src/main/java/dev/openfga/sdk/telemetry/Counters.java b/src/main/java/dev/openfga/sdk/telemetry/Counters.java index c755fb61..4089e496 100644 --- a/src/main/java/dev/openfga/sdk/telemetry/Counters.java +++ b/src/main/java/dev/openfga/sdk/telemetry/Counters.java @@ -11,5 +11,13 @@ public class Counters { "fga-client.credentials.request", "The total number of times new access tokens have been requested using ClientCredentials."); + /** + * The REQUEST_COUNT counter represents the total number of HTTP requests made by the SDK. + * This counter is emitted once per underlying HTTP request. + * Note: This counter is disabled by default and must be explicitly enabled in TelemetryConfiguration. + */ + public static final Counter REQUEST_COUNT = + new Counter("fga-client.request.count", "The total number of HTTP requests made to the FGA server."); + private Counters() {} // Instantiation prevented. } diff --git a/src/main/java/dev/openfga/sdk/telemetry/Metrics.java b/src/main/java/dev/openfga/sdk/telemetry/Metrics.java index 88483262..817a331d 100644 --- a/src/main/java/dev/openfga/sdk/telemetry/Metrics.java +++ b/src/main/java/dev/openfga/sdk/telemetry/Metrics.java @@ -106,6 +106,20 @@ public LongCounter credentialsRequest(Long value, Map attribu return getCounter(Counters.CREDENTIALS_REQUEST, value, attributes); } + /** + * Returns a LongCounter counter for tracking the total number of HTTP requests made to the FGA server. + * This counter is emitted once per underlying HTTP request. + * Note: This counter is disabled by default and must be explicitly enabled in TelemetryConfiguration. + * + * @param value The value to be added to the counter. + * @param attributes A map of attributes associated with the metric. + * + * @return The LongCounter metric instance for request count, or null if not configured. + */ + public LongCounter requestCount(Long value, Map attributes) { + return getCounter(Counters.REQUEST_COUNT, value, attributes); + } + /** * 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. * diff --git a/src/test/java/dev/openfga/sdk/api/configuration/TelemetryConfigurationTest.java b/src/test/java/dev/openfga/sdk/api/configuration/TelemetryConfigurationTest.java index 5347c539..e85baee7 100644 --- a/src/test/java/dev/openfga/sdk/api/configuration/TelemetryConfigurationTest.java +++ b/src/test/java/dev/openfga/sdk/api/configuration/TelemetryConfigurationTest.java @@ -50,6 +50,9 @@ void testDefaultMetrics() { assertTrue( metrics.containsKey(Histograms.REQUEST_DURATION), "The metrics map should contain the REQUEST_DURATION histogram."); + assertFalse( + metrics.containsKey(Counters.REQUEST_COUNT), + "The metrics map should NOT contain the REQUEST_COUNT counter by default."); Map> defaultAttributes = metrics.get(Counters.CREDENTIALS_REQUEST); assertNotNull(defaultAttributes, "The default attributes map should not be null."); @@ -132,6 +135,19 @@ void testDefaultMetrics() { "The default attribute map should not contain the FGA_CLIENT_REQUEST_BATCH_CHECK_SIZE attribute."); } + @Test + void testRequestCountCanBeExplicitlyEnabled() { + // Arrange + Map>> metrics = new HashMap<>(); + metrics.put(Counters.REQUEST_COUNT, TelemetryConfiguration.defaultAttributes()); + TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration(metrics); + + // Assert + assertTrue( + telemetryConfiguration.metrics().containsKey(Counters.REQUEST_COUNT), + "REQUEST_COUNT should be present when explicitly configured."); + } + @Test void testOverridingDefaultMetrics() { // Arrange diff --git a/src/test/java/dev/openfga/sdk/telemetry/CountersTest.java b/src/test/java/dev/openfga/sdk/telemetry/CountersTest.java index 4b69f1b3..b81b44c8 100644 --- a/src/test/java/dev/openfga/sdk/telemetry/CountersTest.java +++ b/src/test/java/dev/openfga/sdk/telemetry/CountersTest.java @@ -19,4 +19,18 @@ void shouldCreateCredentialsRequestCounter() { assertThat(counter.getName()).isEqualTo(expectedName); assertThat(counter.getDescription()).isEqualTo(expectedDescription); } + + @Test + void shouldCreateRequestCountCounter() { + // given + String expectedName = "fga-client.request.count"; + String expectedDescription = "The total number of HTTP requests made to the FGA server."; + + // when + Counter counter = Counters.REQUEST_COUNT; + + // then + assertThat(counter.getName()).isEqualTo(expectedName); + assertThat(counter.getDescription()).isEqualTo(expectedDescription); + } } diff --git a/src/test/java/dev/openfga/sdk/telemetry/MetricsTest.java b/src/test/java/dev/openfga/sdk/telemetry/MetricsTest.java index 8c47b995..ffe313ca 100644 --- a/src/test/java/dev/openfga/sdk/telemetry/MetricsTest.java +++ b/src/test/java/dev/openfga/sdk/telemetry/MetricsTest.java @@ -114,6 +114,34 @@ void shouldQueryDuration() { assertThat(doubleHistogram).isNotNull(); } + @Test + void shouldReturnNullForRequestCountWhenNotConfigured() { + // given - default configuration does not include REQUEST_COUNT + Metrics metrics = new Metrics(new Configuration()); + + // when + LongCounter counter = metrics.requestCount(1L, Map.of()); + + // then + assertThat(counter).isNull(); + } + + @Test + void shouldReturnRequestCountWhenExplicitlyEnabled() { + // given + Map> attrs = Map.of(); + Map>> configuredMetrics = Map.of(Counters.REQUEST_COUNT, attrs); + TelemetryConfiguration telemetryConfiguration = new TelemetryConfiguration(configuredMetrics); + Configuration config = new Configuration().telemetryConfiguration(telemetryConfiguration); + Metrics metrics = new Metrics(config); + + // when + LongCounter counter = metrics.requestCount(1L, Map.of()); + + // then + assertThat(counter).isNotNull(); + } + @Test void shouldNotSentMetricsIfNotConfigured() { // given @@ -173,6 +201,8 @@ void shouldDefaultMetricsEnabled() { .isNotNull(); assertThat(metrics.getHistogram(Histograms.REQUEST_DURATION, 10.0, Map.of())) .isNotNull(); + // REQUEST_COUNT is disabled by default + assertThat(metrics.getCounter(Counters.REQUEST_COUNT, 1L, Map.of())).isNull(); } @Test