Skip to content

Commit

Permalink
chore(dotnet-sdk): sync latest telemetry work back
Browse files Browse the repository at this point in the history
  • Loading branch information
ewanharris committed Nov 15, 2024
1 parent 295d116 commit cc8413d
Show file tree
Hide file tree
Showing 20 changed files with 800 additions and 288 deletions.
2 changes: 1 addition & 1 deletion config/clients/dotnet/CHANGELOG.md.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## v0.5.1

### [0.5.1](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v0.4.0...v0.4.1) (2024-09-10)
### [0.5.1](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/compare/v0.5.0...v0.5.1) (2024-09-09)
- feat: export OpenTelemetry metrics. Refer to the [https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/blob/main/OpenTelemetry.md](documentation) for more.

## v0.5.0
Expand Down
8 changes: 8 additions & 0 deletions config/clients/dotnet/config.overrides.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@
"destinationFilename": "src/OpenFga.Sdk/Telemetry/Histograms.cs",
"templateType": "SupportingFiles"
},
"Telemetry/Meters.cs.mustache": {
"destinationFilename": "src/OpenFga.Sdk/Telemetry/Meters.cs",
"templateType": "SupportingFiles"
},
"Telemetry/Metrics.cs.mustache": {
"destinationFilename": "src/OpenFga.Sdk/Telemetry/Metrics.cs",
"templateType": "SupportingFiles"
Expand All @@ -247,6 +251,10 @@
"destinationFilename": "src/OpenFga.Sdk/Configuration/Configuration.cs",
"templateType": "SupportingFiles"
},
"Configuration_TelemetryConfig.mustache": {
"destinationFilename": "src/OpenFga.Sdk/Configuration/TelemetryConfig.cs",
"templateType": "SupportingFiles"
},
"Exceptions_Parsers_ApiErrorParser.mustache": {
"destinationFilename": "src/OpenFga.Sdk/Exceptions/Parsers/ApiErrorParser.cs",
"templateType": "SupportingFiles"
Expand Down
2 changes: 1 addition & 1 deletion config/clients/dotnet/template/Client/Client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class {{appShortName}}Client : IDisposable {
ClientConfiguration configuration,
HttpClient? httpClient = null
) {
configuration.IsValid();
configuration.EnsureValid();
_configuration = configuration;
api = new {{appShortName}}Api(_configuration, httpClient);
}
Expand Down
48 changes: 37 additions & 11 deletions config/clients/dotnet/template/Client/ClientConfiguration.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,76 @@ using {{packageName}}.Exceptions;

namespace {{packageName}}.Client;

/// <summary>
/// Class for managing telemetry settings.
/// </summary>
public class Telemetry {
}

/// <summary>
/// Configuration class for the {{packageName}} client.
/// </summary>
public class ClientConfiguration : Configuration.Configuration {
/// <summary>
/// Initializes a new instance of the <see cref="ClientConfiguration"/> class with the specified configuration.
/// </summary>
/// <param name="config">The base configuration to copy settings from.</param>
public ClientConfiguration(Configuration.Configuration config) {
ApiScheme = config.ApiScheme;
ApiHost = config.ApiHost;
ApiUrl = config.ApiUrl;
UserAgent = config.UserAgent;
Credentials = config.Credentials;
DefaultHeaders = config.DefaultHeaders;
Telemetry = config.Telemetry;
RetryParams = new RetryParams {MaxRetry = config.MaxRetry, MinWaitInMs = config.MinWaitInMs};
}

/// <summary>
/// Initializes a new instance of the <see cref="ClientConfiguration"/> class.
/// </summary>
public ClientConfiguration() { }

/// <summary>
/// Gets or sets the Store ID.
/// Gets or sets the Store ID.
/// </summary>
/// <value>Store ID.</value>
/// <value>The Store ID.</value>
public string? StoreId { get; set; }

/// <summary>
/// Gets or sets the Authorization Model ID.
/// Gets or sets the Authorization Model ID.
/// </summary>
/// <value>Authorization Model ID.</value>
/// <value>The Authorization Model ID.</value>
public string? AuthorizationModelId { get; set; }

/// <summary>
/// Gets or sets the retry parameters.
/// </summary>
/// <value>The retry parameters.</value>
public RetryParams? RetryParams { get; set; } = new();

public new void IsValid() {
base.IsValid();
/// <summary>
/// Ensures the configuration is valid, otherwise throws an error.
/// </summary>
/// <exception cref="FgaValidationError">Thrown when the Store ID or Authorization Model ID is not in a valid ULID format.</exception>
public new void EnsureValid() {
base.EnsureValid();
if (StoreId != null && !IsWellFormedUlidString(StoreId)) {
throw new FgaValidationError("StoreId is not in a valid ulid format");
}

if (AuthorizationModelId != null && AuthorizationModelId != "" && !IsWellFormedUlidString(AuthorizationModelId)) {
throw new FgaValidationError("AuthorizationModelId is not in a valid ulid format");
if (!string.IsNullOrEmpty(AuthorizationModelId) &&
!IsWellFormedUlidString(AuthorizationModelId)) {
throw new FgaValidationError("AuthorizationModelId is not in a valid ulid format");
}
}

/// <summary>
/// Ensures that a string is in valid [ULID](https://github.com/ulid/spec) format
/// Ensures that a string is in valid [ULID](https://github.com/ulid/spec) format.
/// </summary>
/// <param name="ulid"></param>
/// <returns></returns>
/// <param name="ulid">The string to validate as a ULID.</param>
/// <returns>True if the string is a valid ULID, otherwise false.</returns>
public static bool IsWellFormedUlidString(string ulid) {
var regex = new Regex("^[0-7][0-9A-HJKMNP-TV-Z]{25}$");
return regex.IsMatch(ulid);
Expand Down
16 changes: 10 additions & 6 deletions config/clients/dotnet/template/Client_ApiClient.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ public class ApiClient : IDisposable {
private readonly BaseClient _baseClient;
private readonly Configuration.Configuration _configuration;
private readonly OAuth2Client? _oauth2Client;
private readonly Metrics metrics = new();
private readonly Metrics metrics;
/// <summary>
/// Initializes a new instance of the <see cref="ApiClient" /> class.
/// </summary>
/// <param name="configuration">Client Configuration</param>
/// <param name="userHttpClient">User Http Client - Allows Http Client reuse</param>
public ApiClient(Configuration.Configuration configuration, HttpClient? userHttpClient = null) {
configuration.IsValid();
configuration.EnsureValid();
_configuration = configuration;
_baseClient = new BaseClient(configuration, userHttpClient);
metrics = new Metrics(_configuration);
if (_configuration.Credentials == null) {
return;
}
Expand All @@ -39,7 +41,8 @@ public class ApiClient : IDisposable {
break;
case CredentialsMethod.ClientCredentials:
_oauth2Client = new OAuth2Client(_configuration.Credentials, _baseClient,
new RetryParams { MaxRetry = _configuration.MaxRetry, MinWaitInMs = _configuration.MinWaitInMs });
new RetryParams { MaxRetry = _configuration.MaxRetry, MinWaitInMs = _configuration.MinWaitInMs },
metrics);
break;
case CredentialsMethod.None:
default:
Expand Down Expand Up @@ -81,7 +84,7 @@ public class ApiClient : IDisposable {
cancellationToken));

sw.Stop();
metrics.buildForResponse(apiName, response.rawResponse, requestBuilder, _configuration.Credentials, sw,
metrics.BuildForResponse(apiName, response.rawResponse, requestBuilder, sw,
response.retryCount);

return response.responseContent;
Expand Down Expand Up @@ -118,7 +121,7 @@ public class ApiClient : IDisposable {
cancellationToken));

sw.Stop();
metrics.buildForResponse(apiName, response.rawResponse, requestBuilder, _configuration.Credentials, sw,
metrics.BuildForResponse(apiName, response.rawResponse, requestBuilder, sw,
response.retryCount);
}

Expand All @@ -130,7 +133,8 @@ public class ApiClient : IDisposable {
var response = await retryable();
response.retryCount = requestCount - 1; // OTEL spec specifies that the original request is not included in the count
response.retryCount =
requestCount - 1; // OTEL spec specifies that the original request is not included in the count
return response;
}
Expand Down
24 changes: 18 additions & 6 deletions config/clients/dotnet/template/Client_OAuth2Client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class OAuth2Client {
TOKEN_EXPIRY_JITTER_IN_SEC = 300; // We add some jitter so that token refreshes are less likely to collide
private static readonly Random _random = new();
private readonly Metrics metrics = new();
private readonly Metrics metrics;
/// <summary>
/// Credentials Flow Response
Expand Down Expand Up @@ -65,7 +65,6 @@ public class OAuth2Client {
private IDictionary<string, string> _authRequest { get; }
private string _apiTokenIssuer { get; }
private readonly RetryParams _retryParams;
private readonly Credentials _credentialsConfig;

#endregion

Expand All @@ -77,7 +76,12 @@ public class OAuth2Client {
/// <param name="credentialsConfig"></param>
/// <param name="httpClient"></param>
/// <exception cref="NullReferenceException"></exception>
public OAuth2Client(Credentials credentialsConfig, BaseClient httpClient, RetryParams retryParams) {
public OAuth2Client(Credentials credentialsConfig, BaseClient httpClient, RetryParams retryParams,
Metrics metrics) {
if (credentialsConfig == null) {
throw new Exception("Credentials are required for OAuth2Client");
}

if (string.IsNullOrWhiteSpace(credentialsConfig.Config!.ClientId)) {
throw new FgaRequiredParamError("OAuth2Client", "config.ClientId");
}
Expand All @@ -86,17 +90,24 @@ public class OAuth2Client {
throw new FgaRequiredParamError("OAuth2Client", "config.ClientSecret");
}

_credentialsConfig = credentialsConfig;
if (string.IsNullOrWhiteSpace(credentialsConfig.Config.ApiTokenIssuer)) {
throw new FgaRequiredParamError("OAuth2Client", "config.ApiTokenIssuer");
}

_httpClient = httpClient;
_apiTokenIssuer = credentialsConfig.Config.ApiTokenIssuer;
_authRequest = new Dictionary<string, string> {
{ "client_id", credentialsConfig.Config.ClientId },
{ "client_secret", credentialsConfig.Config.ClientSecret },
{ "audience", credentialsConfig.Config.ApiAudience },
{ "grant_type", "client_credentials" }
};

if (credentialsConfig.Config.ApiAudience != null) {
_authRequest["audience"] = credentialsConfig.Config.ApiAudience;
}

_retryParams = retryParams;
this.metrics = metrics;
}

/// <summary>
Expand All @@ -122,7 +133,8 @@ public class OAuth2Client {
cancellationToken));

sw.Stop();
metrics.buildForClientCredentialsResponse(accessTokenResponse.rawResponse, requestBuilder, _credentialsConfig,

metrics.BuildForClientCredentialsResponse(accessTokenResponse.rawResponse, requestBuilder,
sw, accessTokenResponse.retryCount);

_authToken = new AuthToken { AccessToken = accessTokenResponse.responseContent?.AccessToken };
Expand Down
60 changes: 33 additions & 27 deletions config/clients/dotnet/template/Configuration_Configuration.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,38 @@ using {{packageName}}.Exceptions;
namespace {{packageName}}.Configuration;

/// <summary>
/// Setup {{appName}} Configuration
/// Setup {{packageName}} Configuration
/// </summary>
public class Configuration {
#region Methods
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class
/// </summary>
/// <exception cref="FgaRequiredParamError"></exception>
public Configuration() {
DefaultHeaders ??= new Dictionary<string, string>();
private static bool IsWellFormedUriString(string uri) {
return Uri.TryCreate(uri, UriKind.Absolute, out var uriResult) &&
((uriResult.ToString().Equals(uri) || uriResult.ToString().Equals($"{uri}/")) &&
(uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps));
if (!DefaultHeaders.ContainsKey("User-Agent")) {
DefaultHeaders.Add("User-Agent", DefaultUserAgent);
}
}

#endregion Constructors

#region Methods

private static bool IsWellFormedUriString(string uri) =>
Uri.TryCreate(uri, UriKind.Absolute, out var uriResult) &&
(uriResult.ToString().Equals(uri) || uriResult.ToString().Equals($"{uri}/")) &&
(uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps);

/// <summary>
/// Checks if the configuration is valid
/// Ensures that the configuration is valid otherwise throws an error
/// </summary>
/// <exception cref="FgaRequiredParamError"></exception>
public void IsValid() {
/// <exception cref="FgaValidationError"></exception>
public void EnsureValid() {
if (BasePath == null || BasePath == "") {
throw new FgaRequiredParamError("Configuration", "ApiUrl");
}
Expand All @@ -34,10 +50,11 @@ public class Configuration {
throw new FgaValidationError("Configuration.MaxRetry exceeds maximum allowed limit of {{retryMaxAllowedNumber}}");
}

Credentials?.IsValid();
Credentials?.EnsureValid();
Telemetry?.EnsureValid();
}

#endregion
#endregion Methods

#region Constants

Expand All @@ -51,23 +68,7 @@ public class Configuration {

#endregion Constants

#region Constructors

/// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class
/// </summary>
/// <exception cref="FgaRequiredParamError"></exception>
public Configuration() {
DefaultHeaders ??= new Dictionary<string, string>();
if (!DefaultHeaders.ContainsKey("User-Agent")) {
DefaultHeaders.Add("User-Agent", DefaultUserAgent);
}
}

#endregion Constructors



#region Properties

/// <summary>
Expand Down Expand Up @@ -144,5 +145,10 @@ public class Configuration {
/// <value>MinWaitInMs</value>
public int MinWaitInMs { get; set; } = {{defaultMinWaitInMs}};

/// <summary>
/// Gets or sets the telemetry configuration.
/// </summary>
public TelemetryConfig? Telemetry { get; set; }

#endregion Properties
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,11 @@ public class Credentials: IAuthCredentialsConfig {
}

/// <summary>
/// Checks if the credentials configuration is valid
/// Ensures the credentials configuration is valid otherwise throws an error
/// </summary>
/// <exception cref="FgaRequiredParamError"></exception>
public void IsValid() {
/// <exception cref="FgaValidationError"></exception>
public void EnsureValid() {
switch (Method) {
case CredentialsMethod.ApiToken:
if (string.IsNullOrWhiteSpace(Config?.ApiToken)) {
Expand Down Expand Up @@ -141,7 +142,7 @@ public class Credentials: IAuthCredentialsConfig {
/// </summary>
/// <exception cref="FgaRequiredParamError"></exception>
public Credentials() {
this.IsValid();
this.EnsureValid();
}

static Credentials Init(IAuthCredentialsConfig config) {
Expand Down
Loading

0 comments on commit cc8413d

Please sign in to comment.