Skip to content

Instantly share code, notes, and snippets.

@dimitrispaxinos
Last active April 1, 2023 17:06
Show Gist options
  • Save dimitrispaxinos/3ad68e6bf3bf35edf47b to your computer and use it in GitHub Desktop.
Save dimitrispaxinos/3ad68e6bf3bf35edf47b to your computer and use it in GitHub Desktop.
HttpClient Wrapper with logging functionality using Serilog
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Serilog.Context;
namespace Serilog.RestCallMonitoring
{
public class SerilogHttpClientWrapper : HttpClient
{
private static string _templateString =
"Rest Call: {RestAction} called {RequestUri}. HttpStatus: {StatusCode}.";
private readonly ILogger _logger;
private readonly HttpClient _httpClient;
/// <summary>
/// Limit Access to default constructor.
/// </summary>
protected SerilogHttpClientWrapper()
{
}
/// <summary>
/// Instantiate the class by passing the existing HttpClient Implementation
/// </summary>
/// <param name="httpClient"></param>
/// <param name="logger"></param>
public SerilogHttpClientWrapper(HttpClient httpClient, ILogger logger)
{
_httpClient = httpClient;
_logger = logger;
}
#region Overrides
// Use of the "new" keyword in order to be able to override non virtual methods
public async new Task<HttpResponseMessage> GetAsync(Uri requestUri)
{
var res = await _httpClient.GetAsync(requestUri);
LogResponseMessage(requestUri, res, "GET");
return res;
}
public new async Task<HttpResponseMessage> PostAsync(Uri requestUri, HttpContent content)
{
var res = await _httpClient.PostAsync(requestUri, content);
LogResponseMessage(requestUri, res, "POST", content);
return res;
}
public async new Task<HttpResponseMessage> PutAsync(Uri requestUri, HttpContent content)
{
var res = await _httpClient.PutAsync(requestUri, content);
LogResponseMessage(requestUri, res, "PUT", content);
return res;
}
public async new Task<HttpResponseMessage> DeleteAsync(Uri requestUri)
{
var res = await _httpClient.DeleteAsync(requestUri);
LogResponseMessage(requestUri, res, "DELETE");
return res;
}
#endregion
/// <summary>
/// Implements the log logic of the Wrapper
/// </summary>
/// <param name="requestUri">Uri of the REST call</param>
/// <param name="responseMessage">Response Message</param>
/// <param name="restAction">Rest Action Name (GET,PUT,POST,DELETE)</param>
/// <param name="sentHttpContent">Sent HttpContent</param>
protected virtual void LogResponseMessage(Uri requestUri, HttpResponseMessage responseMessage, string restAction, HttpContent sentHttpContent = null)
{
using (LogContext.PushProperty("Request", sentHttpContent))
using (LogContext.PushProperty("Response", responseMessage.Content.ReadAsStringAsync().Result))
{
if (responseMessage.IsSuccessStatusCode)
{
_logger.Information(
_templateString, restAction,
CombineAddress(requestUri),
responseMessage.StatusCode);
}
else
_logger.Error(
_templateString, restAction,
CombineAddress(requestUri),
responseMessage.StatusCode);
}
}
/// <summary>
/// Combine relative with the base Uri of the HttpClient. Used for logging purposes
/// </summary>
/// <param name="uri"> input uri</param>
/// <returns> Complete Uri string including the base address</returns>
private string CombineAddress(Uri uri)
{
if (uri.IsAbsoluteUri)
return uri.AbsoluteUri;
if (_httpClient == null || _httpClient.BaseAddress == null) return uri.AbsoluteUri;
return $"{_httpClient.BaseAddress.AbsoluteUri}{uri}";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment