feat(LogExtensions): add full url and use placeholder for binary-data

This commit is contained in:
tekh 2025-08-18 13:15:31 +02:00
parent b3a27ba24f
commit 48a69f884e
3 changed files with 41 additions and 24 deletions

View File

@ -1,5 +1,6 @@
using Leanetec.EConnect.Client.Interface; using Leanetec.EConnect.Client.Interface;
using Leanetec.EConnect.Domain.Entities; using Leanetec.EConnect.Domain.Entities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Net.Http.Json; using System.Net.Http.Json;
@ -13,10 +14,13 @@ public class EConnectClient<TError> : IEConnectClient<TError> where TError : cl
private HttpClient Http => LazyHttp.Value; private HttpClient Http => LazyHttp.Value;
public EConnectClient(IOptions<ClientOptions> options, IHttpClientFactory httpFactory) private readonly ILogger<EConnectClient<TError>>? _logger;
public EConnectClient(IOptions<ClientOptions> options, IHttpClientFactory httpFactory, ILogger<EConnectClient<TError>>? logger = null)
{ {
_options = options.Value; _options = options.Value;
LazyHttp = new Lazy<HttpClient>(httpFactory.CreateEConnectClient); LazyHttp = new Lazy<HttpClient>(httpFactory.CreateEConnectClient);
_logger = logger;
} }
private string? AddQueryString(string? route = null, object? queryParams = null) private string? AddQueryString(string? route = null, object? queryParams = null)
@ -127,6 +131,8 @@ public class EConnectClient<TError> : IEConnectClient<TError> where TError : cl
var res = await Http.PostAsync(route, content, cancel); var res = await Http.PostAsync(route, content, cancel);
_logger?.LogCurlAsync(Http, HttpMethod.Post, route, content);
if (res.IsSuccessStatusCode) if (res.IsSuccessStatusCode)
{ {
return new() return new()

View File

@ -5,7 +5,7 @@ namespace Leanetec.EConnect.Infrastructure;
public static class LogExtensions public static class LogExtensions
{ {
public static async Task LogCurlAsync<TCategoryName>(this ILogger<TCategoryName> logger, HttpClient client, HttpMethod method, string url, HttpContent? content, LogLevel logLevel = LogLevel.Information) public static async Task LogCurlAsync<TCategoryName>(this ILogger<TCategoryName> logger, HttpClient client, HttpMethod method, string? route = null, HttpContent? content = null, LogLevel logLevel = LogLevel.Information)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.Append("curl"); sb.Append("curl");
@ -13,29 +13,47 @@ public static class LogExtensions
// Method // Method
sb.Append($" -X {method.Method}"); sb.Append($" -X {method.Method}");
// URL
var fullUrl = string.Empty;
if (client.BaseAddress is not null && route is not null)
fullUrl = new Uri(client.BaseAddress, route).ToString();
else if (route is not null)
fullUrl = route;
else if (client.BaseAddress is not null)
fullUrl = client.BaseAddress.ToString();
if (!string.IsNullOrWhiteSpace(fullUrl))
sb.AppendLine($" \"{fullUrl}\"");
// Headers // Headers
foreach (var header in client.DefaultRequestHeaders) foreach (var header in client.DefaultRequestHeaders)
{ {
sb.Append($" -H \"{header.Key}: {string.Join(", ", header.Value)}\""); sb.AppendLine($"\t-H \"{header.Key}: {string.Join(", ", header.Value)}\"");
} }
if (content != null) if (content != null)
{ {
foreach (var header in content.Headers) foreach (var header in content.Headers)
{ {
sb.Append($" -H \"{header.Key}: {string.Join(", ", header.Value)}\""); sb.AppendLine($"\t-H \"{header.Key}: {string.Join(", ", header.Value)}\"");
} }
var mediaType = content.Headers.ContentType?.MediaType;
if (mediaType is not null && mediaType.StartsWith("text") || mediaType!.Contains("json"))
{
var body = await content.ReadAsStringAsync(); var body = await content.ReadAsStringAsync();
if (!string.IsNullOrWhiteSpace(body)) if (!string.IsNullOrWhiteSpace(body))
{ {
// Escape double quotes // Escape double quotes
body = body.Replace("\"", "\\\""); body = body.Replace("\"", "\\\"");
sb.Append($" -d \"{body}\""); sb.AppendLine($"\t-d \"{body}\"");
} }
} }
else
// Binary content, only placeholder in log
sb.AppendLine("\t-d \"<binary data>\"");
}
sb.Append($" \"{url}\"");
logger.Log(logLevel, "{message}", sb.ToString()); logger.Log(logLevel, "{message}", sb.ToString());
} }
} }

View File

@ -20,14 +20,12 @@ public class OrderController : ControllerBase
{ {
var res = await _mediator.Send(request, cancel); var res = await _mediator.Send(request, cancel);
if(res.Ok) if(res.Ok)
{ return res.Data is null || !res.Data.Any()
return res.Data is null || !res.Data.Any() ? NotFound() : Ok(res.Data); ? NotFound()
} : Ok(res.Data);
else else
{
return StatusCode(res.StatusCodeInt, res?.Error); return StatusCode(res.StatusCodeInt, res?.Error);
} }
}
[HttpPost("document")] [HttpPost("document")]
public async Task<IActionResult> PostDocument(IFormFile file, [FromQuery] PostDocumentRequest request, CancellationToken cancel) public async Task<IActionResult> PostDocument(IFormFile file, [FromQuery] PostDocumentRequest request, CancellationToken cancel)
@ -40,13 +38,8 @@ public class OrderController : ControllerBase
var res = await _mediator.Send(request.ToUploadDocument(streamContent), cancel); var res = await _mediator.Send(request.ToUploadDocument(streamContent), cancel);
if (res.Ok) return res.Ok
{ ? StatusCode(res.StatusCodeInt)
return StatusCode(res.StatusCodeInt); : StatusCode(res.StatusCodeInt, res?.Error);
}
else
{
return StatusCode(res.StatusCodeInt, res?.Error);
}
} }
} }