Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .java-version

This file was deleted.

84 changes: 78 additions & 6 deletions mustache-templates/csharp/ApiClient.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -260,6 +261,46 @@ namespace {{packageName}}.Client
return other;
}

/// <summary>
/// Starts a stopwatch when debug timing is enabled.
/// </summary>
/// <param name="debugModeEnabled">Whether debug timing is enabled for the current request.</param>
/// <returns>A started <see cref="Stopwatch"/> when enabled; otherwise <c>null</c>.</returns>
private static Stopwatch StartTiming(bool debugModeEnabled = false)
{
return debugModeEnabled ? Stopwatch.StartNew() : null;
}

/// <summary>
/// Stops timing and writes a debug log entry for a request stage.
/// </summary>
/// <param name="debugModeEnabled">Whether debug timing is enabled for the current request.</param>
/// <param name="stopwatch">The stopwatch instance started for the stage.</param>
/// <param name="stage">The request stage label (for example: construction or execution).</param>
/// <param name="method">HTTP method name.</param>
/// <param name="resource">Request resource path.</param>
/// <param name="response">Optional response used to enrich debug metadata.</param>
private static void StopTiming(bool debugModeEnabled, Stopwatch stopwatch, string stage, string method, string resource, RestResponse response = null)
{
if (!debugModeEnabled || stopwatch == null)
{
return;
}

stopwatch.Stop();
double elapsedMilliseconds = stopwatch.Elapsed.TotalMilliseconds;

string responseMeta = string.Empty;
if (response != null)
{
int payloadSize = response.RawBytes?.Length ?? 0;

responseMeta = $" status={(int)response.StatusCode} response body size={payloadSize}B";
}

Console.WriteLine($"[Voucherify SDK][DEBUG][{DateTimeOffset.UtcNow:yyyy-MM-dd HH:mm:ss.fff} UTC] {stage} {method} {resource}{responseMeta} took {elapsedMilliseconds:F2}ms");
}

/// <summary>
/// Provides all logic for constructing a new RestSharp <see cref="RestRequest"/>.
/// At this point, all information for querying the service is known.
Expand All @@ -282,6 +323,9 @@ namespace {{packageName}}.Client
if (options == null) throw new ArgumentNullException("options");
if (configuration == null) throw new ArgumentNullException("configuration");

bool debugModeEnabled = configuration.DebugModeEnabled;
Stopwatch stopwatch = StartTiming(debugModeEnabled);

RestRequest request = new RestRequest(path, Method(method));

if (options.PathParameters != null)
Expand Down Expand Up @@ -392,6 +436,8 @@ namespace {{packageName}}.Client
}
}

StopTiming(debugModeEnabled, stopwatch, "Request construction", method.ToString(), path);

return request;
}

Expand Down Expand Up @@ -558,11 +604,17 @@ namespace {{packageName}}.Client
}
}

private async Task<RestResponse<T>> DeserializeRestResponseFromPolicyAsync<T>(RestClient client, RestRequest request, PolicyResult<RestResponse> policyResult, CancellationToken cancellationToken = default)
private async Task<RestResponse<T>> DeserializeRestResponseFromPolicyAsync<T>(RestClient client, RestRequest request, PolicyResult<RestResponse> policyResult, bool debugModeEnabled = false, CancellationToken cancellationToken = default)
{
if (policyResult.Outcome == OutcomeType.Successful)
{
return await client.Deserialize<T>(policyResult.Result, cancellationToken);
Stopwatch watch = StartTiming(debugModeEnabled);

var deserializeResult = await client.Deserialize<T>(policyResult.Result, cancellationToken);

StopTiming(debugModeEnabled, watch, "Response parse", request.Method.ToString(), request.Resource, deserializeResult);

return deserializeResult;
}
else
{
Expand Down Expand Up @@ -594,12 +646,23 @@ namespace {{packageName}}.Client
if (RetryConfiguration.RetryPolicy != null)
{
var policy = RetryConfiguration.RetryPolicy;

bool debugModeEnabled = configuration?.DebugModeEnabled ?? false;
Stopwatch watch = StartTiming(debugModeEnabled);
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
return DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult);
StopTiming(debugModeEnabled, watch, "HTTP send", request.Method.ToString(), request.Resource, policyResult.Result);
return DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, debugModeEnabled);
}
else
{
return Task.FromResult(client.Execute<T>(request));
bool debugModeEnabled = configuration.DebugModeEnabled;
Stopwatch watch = StartTiming(debugModeEnabled);

var executeResult = client.Execute<T>(request);

StopTiming(debugModeEnabled, watch, "HTTP end-to-end (send + parse)", request.Method.ToString(), request.Resource, executeResult);

return Task.FromResult(executeResult);
}
};

Expand All @@ -616,17 +679,26 @@ namespace {{packageName}}.Client

Func<RestClient, Task<RestResponse<T>>> getResponse = async (client) =>
{
bool debugEnabled = configuration.DebugModeEnabled;

{{#supportsRetry}}
if (RetryConfiguration.AsyncRetryPolicy != null)
{
var policy = RetryConfiguration.AsyncRetryPolicy;
Stopwatch networkStopwatch = StartTiming(debugEnabled);
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
return await DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, cancellationToken);
StopTiming(debugEnabled, networkStopwatch, "HTTP send", request.Method.ToString(), request.Resource, policyResult.Result);

return await DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, debugEnabled, cancellationToken);
}
else
{
{{/supportsRetry}}
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
Stopwatch networkStopwatch = StartTiming(debugEnabled);
var rawResponse = await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
StopTiming(debugEnabled, networkStopwatch, "HTTP end-to-end (send + parse)", request.Method.ToString(), request.Resource, rawResponse);

return rawResponse;
{{#supportsRetry}}
}
{{/supportsRetry}}
Expand Down
84 changes: 78 additions & 6 deletions mustache-templates/csharp/ApiClient.v790.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -260,6 +261,46 @@ namespace {{packageName}}.Client
return other;
}

/// <summary>
/// Starts a stopwatch when debug timing is enabled.
/// </summary>
/// <param name="debugModeEnabled">Whether debug timing is enabled for the current request.</param>
/// <returns>A started <see cref="Stopwatch"/> when enabled; otherwise <c>null</c>.</returns>
private static Stopwatch StartTiming(bool debugModeEnabled = false)
{
return debugModeEnabled ? Stopwatch.StartNew() : null;
}

/// <summary>
/// Stops timing and writes a debug log entry for a request stage.
/// </summary>
/// <param name="debugModeEnabled">Whether debug timing is enabled for the current request.</param>
/// <param name="stopwatch">The stopwatch instance started for the stage.</param>
/// <param name="stage">The request stage label (for example: construction or execution).</param>
/// <param name="method">HTTP method name.</param>
/// <param name="resource">Request resource path.</param>
/// <param name="response">Optional response used to enrich debug metadata.</param>
private static void StopTiming(bool debugModeEnabled, Stopwatch stopwatch, string stage, string method, string resource, RestResponse response = null)
{
if (!debugModeEnabled || stopwatch == null)
{
return;
}

stopwatch.Stop();
double elapsedMilliseconds = stopwatch.Elapsed.TotalMilliseconds;

string responseMeta = string.Empty;
if (response != null)
{
int payloadSize = response.RawBytes?.Length ?? 0;

responseMeta = $" status={(int)response.StatusCode} response body size={payloadSize}B";
}

Console.WriteLine($"[Voucherify SDK][DEBUG][{DateTimeOffset.UtcNow:yyyy-MM-dd HH:mm:ss.fff} UTC] {stage} {method} {resource}{responseMeta} took {elapsedMilliseconds:F2}ms");
}

/// <summary>
/// Provides all logic for constructing a new RestSharp <see cref="RestRequest"/>.
/// At this point, all information for querying the service is known.
Expand All @@ -282,6 +323,9 @@ namespace {{packageName}}.Client
if (options == null) throw new ArgumentNullException("options");
if (configuration == null) throw new ArgumentNullException("configuration");

bool debugModeEnabled = configuration.DebugModeEnabled;
Stopwatch stopwatch = StartTiming(debugModeEnabled);

RestRequest request = new RestRequest(path, Method(method));

if (options.PathParameters != null)
Expand Down Expand Up @@ -384,6 +428,8 @@ namespace {{packageName}}.Client
}
}

StopTiming(debugModeEnabled, stopwatch, "Request construction", method.ToString(), path);

return request;
}

Expand Down Expand Up @@ -550,11 +596,17 @@ namespace {{packageName}}.Client
}
}

private async Task<RestResponse<T>> DeserializeRestResponseFromPolicyAsync<T>(RestClient client, RestRequest request, PolicyResult<RestResponse> policyResult, CancellationToken cancellationToken = default)
private async Task<RestResponse<T>> DeserializeRestResponseFromPolicyAsync<T>(RestClient client, RestRequest request, PolicyResult<RestResponse> policyResult, bool debugModeEnabled = false, CancellationToken cancellationToken = default)
{
if (policyResult.Outcome == OutcomeType.Successful)
{
return await client.Deserialize<T>(policyResult.Result, cancellationToken);
Stopwatch watch = StartTiming(debugModeEnabled);

var deserializeResult = await client.Deserialize<T>(policyResult.Result, cancellationToken);

StopTiming(debugModeEnabled, watch, "Response parse", request.Method.ToString(), request.Resource, deserializeResult);

return deserializeResult;
}
else
{
Expand Down Expand Up @@ -586,12 +638,23 @@ namespace {{packageName}}.Client
if (RetryConfiguration.RetryPolicy != null)
{
var policy = RetryConfiguration.RetryPolicy;

bool debugModeEnabled = configuration?.DebugModeEnabled ?? false;
Stopwatch watch = StartTiming(debugModeEnabled);
var policyResult = policy.ExecuteAndCapture(() => client.Execute(request));
return DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult);
StopTiming(debugModeEnabled, watch, "HTTP send", request.Method.ToString(), request.Resource, policyResult.Result);
return DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, debugModeEnabled);
}
else
{
return Task.FromResult(client.Execute<T>(request));
bool debugModeEnabled = configuration.DebugModeEnabled;
Stopwatch watch = StartTiming(debugModeEnabled);

var executeResult = client.Execute<T>(request);

StopTiming(debugModeEnabled, watch, "HTTP end-to-end (send + parse)", request.Method.ToString(), request.Resource, executeResult);

return Task.FromResult(executeResult);
}
};

Expand All @@ -608,17 +671,26 @@ namespace {{packageName}}.Client

Func<RestClient, Task<RestResponse<T>>> getResponse = async (client) =>
{
bool debugEnabled = configuration.DebugModeEnabled;

{{#supportsRetry}}
if (RetryConfiguration.AsyncRetryPolicy != null)
{
var policy = RetryConfiguration.AsyncRetryPolicy;
Stopwatch networkStopwatch = StartTiming(debugEnabled);
var policyResult = await policy.ExecuteAndCaptureAsync((ct) => client.ExecuteAsync(request, ct), cancellationToken).ConfigureAwait(false);
return await DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, cancellationToken);
StopTiming(debugEnabled, networkStopwatch, "HTTP send", request.Method.ToString(), request.Resource, policyResult.Result);

return await DeserializeRestResponseFromPolicyAsync<T>(client, request, policyResult, debugEnabled, cancellationToken);
}
else
{
{{/supportsRetry}}
return await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
Stopwatch networkStopwatch = StartTiming(debugEnabled);
var rawResponse = await client.ExecuteAsync<T>(request, cancellationToken).ConfigureAwait(false);
StopTiming(debugEnabled, networkStopwatch, "HTTP end-to-end (send + parse)", request.Method.ToString(), request.Resource, rawResponse);

return rawResponse;
{{#supportsRetry}}
}
{{/supportsRetry}}
Expand Down
18 changes: 18 additions & 0 deletions mustache-templates/csharp/Configuration.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ namespace {{packageName}}.Client
{{/apiInfo}}
};

DebugModeEnabled = IsDebugModeEnabledInEnvironment();

// Setting Timeout has side effects (forces ApiClient creation).
Timeout = TimeSpan.FromSeconds(100);
}
Expand Down Expand Up @@ -264,6 +266,11 @@ namespace {{packageName}}.Client
set { _useDefaultCredentials = value; }
}

/// <summary>
/// Determines whether request timing diagnostics are enabled.
/// </summary>
public virtual bool DebugModeEnabled { get; set; }

/// <summary>
/// Gets or sets the default header.
/// </summary>
Expand Down Expand Up @@ -679,6 +686,16 @@ namespace {{packageName}}.Client
ApiKeyPrefix[key] = value;
}

/// <summary>
/// Checks whether debug mode is enabled via the DEBUG environment variable.
/// </summary>
/// <returns><c>true</c> when DEBUG equals "true" (case-insensitive); otherwise, <c>false</c>.</returns>
private static bool IsDebugModeEnabledInEnvironment()
{
string debugValue = Environment.GetEnvironmentVariable("DEBUG");
return string.Equals(debugValue, "true", StringComparison.OrdinalIgnoreCase);
}

#endregion Methods

#region Static Members
Expand Down Expand Up @@ -728,6 +745,7 @@ namespace {{packageName}}.Client
DateTimeFormat = second.DateTimeFormat ?? first.DateTimeFormat,
ClientCertificates = second.ClientCertificates ?? first.ClientCertificates,
UseDefaultCredentials = second.UseDefaultCredentials,
DebugModeEnabled = second.DebugModeEnabled || first.DebugModeEnabled,
RemoteCertificateValidationCallback = second.RemoteCertificateValidationCallback ?? first.RemoteCertificateValidationCallback,
};
return config;
Expand Down
18 changes: 18 additions & 0 deletions mustache-templates/csharp/Configuration.v790.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ namespace {{packageName}}.Client
{{/apiInfo}}
};

DebugModeEnabled = IsDebugModeEnabledInEnvironment();

// Setting Timeout has side effects (forces ApiClient creation).
Timeout = 100000;
}
Expand Down Expand Up @@ -264,6 +266,11 @@ namespace {{packageName}}.Client
set { _useDefaultCredentials = value; }
}

/// <summary>
/// Determines whether request timing diagnostics are enabled.
/// </summary>
public virtual bool DebugModeEnabled { get; set; }

/// <summary>
/// Gets or sets the default header.
/// </summary>
Expand Down Expand Up @@ -679,6 +686,16 @@ namespace {{packageName}}.Client
ApiKeyPrefix[key] = value;
}

/// <summary>
/// Checks whether debug mode is enabled via the DEBUG environment variable.
/// </summary>
/// <returns><c>true</c> when DEBUG equals "true" (case-insensitive); otherwise, <c>false</c>.</returns>
private static bool IsDebugModeEnabledInEnvironment()
{
string debugValue = Environment.GetEnvironmentVariable("DEBUG");
return string.Equals(debugValue, "true", StringComparison.OrdinalIgnoreCase);
}

#endregion Methods

#region Static Members
Expand Down Expand Up @@ -728,6 +745,7 @@ namespace {{packageName}}.Client
DateTimeFormat = second.DateTimeFormat ?? first.DateTimeFormat,
ClientCertificates = second.ClientCertificates ?? first.ClientCertificates,
UseDefaultCredentials = second.UseDefaultCredentials,
DebugModeEnabled = second.DebugModeEnabled || first.DebugModeEnabled,
RemoteCertificateValidationCallback = second.RemoteCertificateValidationCallback ?? first.RemoteCertificateValidationCallback,
};
return config;
Expand Down
Loading