diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 7995e9f..ed94e55 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -588,6 +588,11 @@ Uri + + + internal request id for tracing + + Set byte content @@ -628,12 +633,13 @@ - + Configure the requests created by this factory Request timeout to use Proxy settings to use + Should generate unique id for requests @@ -2024,12 +2030,13 @@ Request object - + Create request object for web request + if true, should assign unique id for request @@ -2043,6 +2050,9 @@ + + + @@ -2060,7 +2070,7 @@ WebRequest factory - + diff --git a/CryptoExchange.Net/Interfaces/IRequest.cs b/CryptoExchange.Net/Interfaces/IRequest.cs index 9e819cb..9d02651 100644 --- a/CryptoExchange.Net/Interfaces/IRequest.cs +++ b/CryptoExchange.Net/Interfaces/IRequest.cs @@ -27,6 +27,10 @@ namespace CryptoExchange.Net.Interfaces /// Uri Uri { get; } /// + /// internal request id for tracing + /// + string? RequestId { get; } + /// /// Set byte content /// /// diff --git a/CryptoExchange.Net/Interfaces/IRequestFactory.cs b/CryptoExchange.Net/Interfaces/IRequestFactory.cs index ceb7f8c..d519fe9 100644 --- a/CryptoExchange.Net/Interfaces/IRequestFactory.cs +++ b/CryptoExchange.Net/Interfaces/IRequestFactory.cs @@ -22,6 +22,7 @@ namespace CryptoExchange.Net.Interfaces /// /// Request timeout to use /// Proxy settings to use - void Configure(TimeSpan requestTimeout, ApiProxy? proxy); + /// Should generate unique id for requests + void Configure(TimeSpan requestTimeout, ApiProxy? proxy, bool isTracingEnabled=false); } } diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs index 75bca6c..edaa423 100644 --- a/CryptoExchange.Net/Objects/Options.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -126,7 +126,7 @@ namespace CryptoExchange.Net.Objects /// The time the server has to respond to a request before timing out /// public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30); - + public bool IsRequestsTracingEnabled { get; set; } = false; /// /// ctor /// diff --git a/CryptoExchange.Net/Requests/Request.cs b/CryptoExchange.Net/Requests/Request.cs index 5c4530c..0afa03e 100644 --- a/CryptoExchange.Net/Requests/Request.cs +++ b/CryptoExchange.Net/Requests/Request.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Text; @@ -21,10 +22,15 @@ namespace CryptoExchange.Net.Requests /// /// /// - public Request(HttpRequestMessage request, HttpClient client) + /// if true, should assign unique id for request + public Request(HttpRequestMessage request, HttpClient client, bool isTracingEnabled=false) { httpClient = client; this.request = request; + if (isTracingEnabled) + { + RequestId = Path.GetRandomFileName(); + } } /// @@ -45,6 +51,8 @@ namespace CryptoExchange.Net.Requests /// public Uri Uri => request.RequestUri; + /// + public string? RequestId { get; } /// public void SetContent(string data, string contentType) diff --git a/CryptoExchange.Net/Requests/RequestFactory.cs b/CryptoExchange.Net/Requests/RequestFactory.cs index 2434ca1..dd5d861 100644 --- a/CryptoExchange.Net/Requests/RequestFactory.cs +++ b/CryptoExchange.Net/Requests/RequestFactory.cs @@ -12,10 +12,11 @@ namespace CryptoExchange.Net.Requests public class RequestFactory : IRequestFactory { private HttpClient? httpClient; - + private bool isTracingEnabled; /// - public void Configure(TimeSpan requestTimeout, ApiProxy? proxy) + public void Configure(TimeSpan requestTimeout, ApiProxy? proxy, bool isTracingEnabled = false) { + this.isTracingEnabled = isTracingEnabled; HttpMessageHandler handler = new HttpClientHandler() { Proxy = proxy == null ? null : new WebProxy @@ -25,7 +26,7 @@ namespace CryptoExchange.Net.Requests } }; - httpClient = new HttpClient(handler) {Timeout = requestTimeout}; + httpClient = new HttpClient(handler) { Timeout = requestTimeout }; } /// @@ -34,7 +35,7 @@ namespace CryptoExchange.Net.Requests if (httpClient == null) throw new InvalidOperationException("Cant create request before configuring http client"); - return new Request(new HttpRequestMessage(method, uri), httpClient); + return new Request(new HttpRequestMessage(method, uri), httpClient, isTracingEnabled); } } } diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index d3a0f55..1072ca8 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -83,7 +83,7 @@ namespace CryptoExchange.Net throw new ArgumentNullException(nameof(exchangeOptions)); RequestTimeout = exchangeOptions.RequestTimeout; - RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy); + RequestFactory.Configure(exchangeOptions.RequestTimeout, exchangeOptions.Proxy,exchangeOptions.IsRequestsTracingEnabled); RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour; var rateLimiters = new List(); foreach (var rateLimiter in exchangeOptions.RateLimiters) @@ -190,14 +190,14 @@ namespace CryptoExchange.Net } if (limitResult.Data > 0) - log.Write(LogVerbosity.Debug, $"Request {uri.AbsolutePath} was limited by {limitResult.Data}ms by {limiter.GetType().Name}"); + log.Write(LogVerbosity.Debug, $"Request {request.RequestId} {uri.AbsolutePath} was limited by {limitResult.Data}ms by {limiter.GetType().Name}"); } string? paramString = null; if (method == HttpMethod.Post) paramString = " with request body " + request.Content; - log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null? "": $" via proxy {apiProxy.Host}")}"); + log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null? "": $" via proxy {apiProxy.Host}")} {(request.RequestId==null?"":$" with id {request.RequestId}")}"); return await GetResponse(request, cancellationToken).ConfigureAwait(false); } @@ -224,7 +224,7 @@ namespace CryptoExchange.Net var data = await reader.ReadToEndAsync().ConfigureAwait(false); responseStream.Close(); response.Close(); - log.Write(LogVerbosity.Debug, $"Data received: {data}"); + log.Write(LogVerbosity.Debug, $"Data {(request.RequestId==null?"":$"for request {request.RequestId} ")}received: {data}"); var parseResult = ValidateJson(data); if (!parseResult.Success) @@ -249,7 +249,7 @@ namespace CryptoExchange.Net { using var reader = new StreamReader(responseStream); var data = await reader.ReadToEndAsync().ConfigureAwait(false); - log.Write(LogVerbosity.Debug, $"Error received: {data}"); + log.Write(LogVerbosity.Debug, $"Error {(request.RequestId == null ? "" : $"for request {request.RequestId} ")}received: {data}"); responseStream.Close(); response.Close(); var parseResult = ValidateJson(data); @@ -258,7 +258,7 @@ namespace CryptoExchange.Net } catch (HttpRequestException requestException) { - log.Write(LogVerbosity.Warning, "Request exception: " + requestException.Message); + log.Write(LogVerbosity.Warning, $"Request {request.RequestId} exception: " + requestException.Message); return new WebCallResult(null, null, default, new ServerError(requestException.Message)); } catch (TaskCanceledException canceledException) @@ -266,14 +266,14 @@ namespace CryptoExchange.Net if(canceledException.CancellationToken == cancellationToken) { // Cancellation token cancelled - log.Write(LogVerbosity.Warning, "Request cancel requested"); + log.Write(LogVerbosity.Warning, $"Request {request.RequestId} cancel requested"); return new WebCallResult(null, null, default, new CancellationRequestedError()); } else { // Request timed out - log.Write(LogVerbosity.Warning, "Request timed out"); - return new WebCallResult(null, null, default, new WebError("Request timed out")); + log.Write(LogVerbosity.Warning, $"Request {request.RequestId} timed out"); + return new WebCallResult(null, null, default, new WebError($"Request {request.RequestId} timed out")); } } }