Skip to content

feat: report a per http call metric#173

Merged
SoulPancake merged 3 commits intomainfrom
feat/http-req-metric
Feb 15, 2026
Merged

feat: report a per http call metric#173
SoulPancake merged 3 commits intomainfrom
feat/http-req-metric

Conversation

@SoulPancake
Copy link
Copy Markdown
Member

@SoulPancake SoulPancake commented Jan 20, 2026

Description

solves #79

What problem is being solved?

How is it being solved?

What changes are made to solve it?

References

Review Checklist

  • I have clicked on "allow edits by maintainers".
  • I have added documentation for new/changed functionality in this PR or in a PR to openfga.dev [Provide a link to any relevant PRs in the references section above]
  • The correct base branch is being used, if not main
  • I have added tests to validate that the change in functionality is working as expected

Summary by CodeRabbit

  • New Features
    • Enhanced telemetry observability with HTTP request duration metrics. The SDK now automatically tracks and records HTTP request durations with comprehensive contextual attributes including HTTP status, user agent, request method, client ID, store ID, model ID, and retry count for improved performance monitoring.

✏️ Tip: You can customize this high-level summary in your review settings.

@SoulPancake SoulPancake requested a review from a team as a code owner January 20, 2026 14:30
Copilot AI review requested due to automatic review settings January 20, 2026 14:30
@dosubot
Copy link
Copy Markdown

dosubot Bot commented Jan 20, 2026

Related Documentation

Checked 8 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

@SoulPancake SoulPancake linked an issue Jan 20, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 20, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Introduces HTTP request duration telemetry tracking across the OpenFga SDK. A new HttpRequestDuration metric is added to telemetry configuration and histogram recording. BaseClient constructor is updated to accept a Metrics parameter, integrating request duration measurement into the HTTP request flow.

Changes

Cohort / File(s) Summary
Telemetry Metrics Definitions
src/OpenFga.Sdk/Telemetry/Meters.cs, src/OpenFga.Sdk/Telemetry/Histograms.cs, src/OpenFga.Sdk/Telemetry/Metrics.cs
Added new HttpRequestDuration meter constant, histogram property, and recording method BuildForHttpRequest<T>() to track HTTP request duration with attributes like HttpStatus, UserAgent, and RequestMethod.
Telemetry Configuration
src/OpenFga.Sdk/Configuration/TelemetryConfig.cs
Added default metric configuration entry for TelemetryMeter.HttpRequestDuration with standard attributes.
HTTP Client Integration
src/OpenFga.Sdk/ApiClient/BaseClient.cs
Updated constructor signature to accept optional Metrics parameter; added request duration measurement logic, additional header handling, and improved error handling with EnsureSuccessStatusCode() and null-safe deserialization.
HTTP Client Instantiation
src/OpenFga.Sdk/ApiClient/ApiClient.cs
Reordered initialization to create metrics before BaseClient; updated BaseClient instantiation to pass metrics instance.
Documentation & Examples
OpenTelemetry.md, example/OpenTelemetryExample/OpenTelemetryExample.cs
Updated metric naming from TelemetryMeters.* to TelemetryMeter.*; added HttpRequestDuration to example telemetry configuration with consistent attribute set.

Sequence Diagram

sequenceDiagram
    actor Client
    participant ApiClient
    participant BaseClient
    participant HttpClient
    participant Metrics
    participant Histogram

    Client->>ApiClient: Make API Request
    ApiClient->>ApiClient: Create/Initialize Metrics
    ApiClient->>BaseClient: new BaseClient(..., metrics)
    Client->>ApiClient: SendRequest()
    ApiClient->>BaseClient: SendRequestAsync<TRes>()
    BaseClient->>BaseClient: Start Stopwatch
    BaseClient->>HttpClient: SendAsync(request)
    HttpClient-->>BaseClient: HttpResponseMessage
    BaseClient->>BaseClient: EnsureSuccessStatusCode()
    BaseClient->>BaseClient: Deserialize Response
    alt Metrics Enabled
        BaseClient->>Metrics: BuildForHttpRequest()
        Metrics->>Metrics: Compute Attributes
        Metrics->>Histogram: RecordHttpRequestDuration()
        Histogram->>Histogram: Record Duration in Histogram
    end
    BaseClient-->>ApiClient: TRes response
    ApiClient-->>Client: Response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: report a per http call metric' accurately describes the primary change—adding HTTP request duration metrics to the SDK.
Docstring Coverage ✅ Passed Docstring coverage is 90.91% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/http-req-metric

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread src/OpenFga.Sdk/Telemetry/Metrics.cs Fixed
Comment thread src/OpenFga.Sdk/ApiClient/BaseClient.cs Fixed
Comment thread src/OpenFga.Sdk/ApiClient/BaseClient.cs Fixed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@OpenTelemetry.md`:
- Line 16: Fix the typo in the metric description for
`fga-client.query.duration`: change "internally process nd evaluate the request"
to "internally process and evaluate the request" so the description reads
correctly.
- Line 18: The code span in OpenTelemetry.md for the metric name is written with
a leading space ("` fga-client.credentials.request`") which breaks rendering;
edit that table cell to remove the leading space so it reads
"`fga-client.credentials.request`" (update the exact token
fga-client.credentials.request in the table row to ensure correct code span
formatting).

In `@src/OpenFga.Sdk/ApiClient/BaseClient.cs`:
- Around line 84-91: Update SendRequestAsync to accept an int retryCount
parameter (default 0 for backward compatibility) and propagate that value into
the metrics call instead of the hardcoded 0; specifically, change the
SendRequestAsync signature to include retryCount, update the call site in
ApiClient.Retry to pass the current attempt count, and replace the literal 0 in
the _metrics.BuildForHttpRequest(...) invocation with the retryCount value so
http.request.resend_count reflects the actual attempt number.
🧹 Nitpick comments (2)
src/OpenFga.Sdk/Configuration/TelemetryConfig.cs (1)

73-78: Avoid sharing the same attribute set across default metrics.

All MetricConfig entries reference the same HashSet instance, so mutating one metric’s Attributes mutates the others. Consider cloning per metric to avoid cross-contamination.

♻️ Suggested update
-        return new Dictionary<string, MetricConfig> {
-            { TelemetryMeter.TokenExchangeCount, new MetricConfig { Attributes = defaultAttributes } },
-            { TelemetryMeter.RequestDuration, new MetricConfig { Attributes = defaultAttributes } },
-            { TelemetryMeter.QueryDuration, new MetricConfig { Attributes = defaultAttributes } },
-            { TelemetryMeter.HttpRequestDuration, new MetricConfig { Attributes = defaultAttributes } },
-            // { TelemetryMeters.RequestCount, new MetricConfig { Attributes = defaultAttributes } }
-        };
+        return new Dictionary<string, MetricConfig> {
+            { TelemetryMeter.TokenExchangeCount, new MetricConfig { Attributes = new HashSet<string>(defaultAttributes) } },
+            { TelemetryMeter.RequestDuration, new MetricConfig { Attributes = new HashSet<string>(defaultAttributes) } },
+            { TelemetryMeter.QueryDuration, new MetricConfig { Attributes = new HashSet<string>(defaultAttributes) } },
+            { TelemetryMeter.HttpRequestDuration, new MetricConfig { Attributes = new HashSet<string>(defaultAttributes) } },
+            // { TelemetryMeters.RequestCount, new MetricConfig { Attributes = new HashSet<string>(defaultAttributes) } }
+        };
src/OpenFga.Sdk/Telemetry/Metrics.cs (1)

104-131: Reduce per-request attribute computation for HttpRequestDuration.

BuildForHttpRequest only emits one metric, so computing attributes for all enabled metrics is extra work on a hot path. Consider building attributes only for httpRequestDurationConfig.Attributes.

♻️ Suggested update
-        // Compute all enabled attributes once
-        var attributes = Attributes.BuildAttributesForResponse(
-            _allEnabledAttributes, _credentialsConfig, apiName, response, requestBuilder, httpRequestDuration, retryCount);
+        // Compute only the attributes needed for this metric
+        var enabledAttributes = httpRequestDurationConfig?.Attributes ?? new HashSet<string>();
+        var attributes = Attributes.BuildAttributesForResponse(
+            enabledAttributes, _credentialsConfig, apiName, response, requestBuilder, httpRequestDuration, retryCount);

Comment thread OpenTelemetry.md Outdated
Comment thread OpenTelemetry.md Outdated
Comment thread src/OpenFga.Sdk/ApiClient/BaseClient.cs
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new telemetry metric fga-client.http_request.duration to track the duration of individual HTTP requests made by the SDK. This complements the existing fga-client.request.duration metric which tracks the total request time including retries and token exchanges.

Changes:

  • Added new HttpRequestDuration histogram metric that records individual HTTP call durations
  • Modified BaseClient.SendRequestAsync to record HTTP request metrics before retrying
  • Updated telemetry configuration to enable the new metric by default
  • Updated documentation and examples to include the new metric

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/OpenFga.Sdk/Telemetry/Meters.cs Added HttpRequestDuration constant for the new metric name
src/OpenFga.Sdk/Telemetry/Histograms.cs Added HttpRequestDurationHistogram and RecordHttpRequestDuration method
src/OpenFga.Sdk/Telemetry/Metrics.cs Added BuildForHttpRequest method to record HTTP request metrics
src/OpenFga.Sdk/Configuration/TelemetryConfig.cs Added default configuration for HttpRequestDuration metric
src/OpenFga.Sdk/ApiClient/BaseClient.cs Modified to accept Metrics instance and record HTTP request duration; refactored SendRequestAsync to include metric recording
src/OpenFga.Sdk/ApiClient/ApiClient.cs Updated to pass Metrics instance to BaseClient constructor
example/OpenTelemetryExample/OpenTelemetryExample.cs Added example configuration for the new metric
OpenTelemetry.md Updated documentation to include new metric and fixed typos in example code

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/OpenFga.Sdk/ApiClient/BaseClient.cs
Comment thread src/OpenFga.Sdk/ApiClient/BaseClient.cs Outdated
Comment thread OpenTelemetry.md Outdated
Comment thread OpenTelemetry.md Outdated
Comment thread src/OpenFga.Sdk/ApiClient/BaseClient.cs Outdated
Comment thread src/OpenFga.Sdk/Telemetry/Metrics.cs Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread OpenTelemetry.md
@linux-foundation-easycla
Copy link
Copy Markdown

linux-foundation-easycla Bot commented Jan 22, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

  • ✅ login: SoulPancake / name: Anurag Bandyopadhyay (2f6bf52, 80588db)

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src/OpenFga.Sdk/ApiClient/OAuth2Client.cs:198

  • The Retry method in OAuth2Client does not set the retryCount field on the returned ResponseWrapper<AccessTokenResponse>. This means that when BuildForClientCredentialsResponse is called at line 154-155, accessTokenResponse.retryCount will always be 0, even if retries occurred.

This is inconsistent with the ApiClient.Retry implementation which correctly sets response.retryCount = requestCount - 1 at lines 178-179 of ApiClient.cs. The OAuth2Client should follow the same pattern to ensure accurate retry count metrics for token exchange requests.

    private async Task<TResult> Retry<TResult>(Func<int, Task<TResult>> retryable, CancellationToken cancellationToken = default) {
        var attemptCount = 0; // 0 = initial request, 1+ = retry attempts

        while (true) {
            try {
                return await retryable(attemptCount).ConfigureAwait(false);
            }
            catch (FgaApiError err) when (err is FgaApiRateLimitExceededError || err.ShouldRetry) {
                // Check if we should retry based on status code and attempt count
                if (!_retryHandler.ShouldRetry(err.StatusCode, attemptCount)) {
                    err.RetryAttempt = attemptCount;

                    if (err.ResponseHeaders != null) {
                        var info = _retryHandler.ExtractRetryAfterInfoFromHeaders(err.ResponseHeaders);
                        err.RetryAfter = info.retryAfterSeconds;
                        err.RetryAfterRaw = info.retryAfterRaw;
                    }

                    throw;
                }

                // Calculate delay using Retry-After header or exponential backoff
                var delay = _retryHandler.CalculateDelayFromHeaders(err.ResponseHeaders, attemptCount);

                await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
                attemptCount++;
            }
            catch (Exception ex) when (_retryHandler.IsTransientError(ex, attemptCount)) {
                // Network error - retry with exponential backoff (no headers available)
                var delay = _retryHandler.CalculateDelayFromHeaders(null, attemptCount);
                await Task.Delay(delay, cancellationToken).ConfigureAwait(false);
                attemptCount++;
            }
        }
    }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/OpenFga.Sdk/Telemetry/Metrics.cs
Copy link
Copy Markdown
Member

@rhamzeh rhamzeh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SoulPancake I think we've made a mistake in openfga/js-sdk#303

This is not the metric we wanted, and the .NET SDK already had that - the fga-client.request.count - it's that that we need copied over to the rest.

Now that we added duration, we can keep it, but can we make sure that it is disabled by default? In general let's not add more by default and give users the opportunity to enable it if they need to.

But now we need to add tickets for JS and the other SDKs to replace the tickets that were closed.

Side-note: for this PR, it is good so long as we mark it as disabled by default.

Also - can you make sure to update the CHANGELOG?

@SoulPancake
Copy link
Copy Markdown
Member Author

SoulPancake commented Feb 14, 2026

Thanks for the context @rhamzeh

Looking back at issue #418 and the equivalent tickets across the other SDKs, the description pointed toward fga-client.http_request.duration as the solution. Now I can understand the actual intent was to propagate fga-client.request.count from the .NET SDK to the rest, it makes total sense.

SoulPancake

This comment was marked as resolved.

@SoulPancake SoulPancake added this pull request to the merge queue Feb 15, 2026
Merged via the queue into main with commit 66b8d2f Feb 15, 2026
22 checks passed
@SoulPancake SoulPancake deleted the feat/http-req-metric branch February 15, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Report a per-http call metric

5 participants