Last active
October 31, 2024 18:43
-
-
Save dimitrispaxinos/3ad68e6bf3bf35edf47b to your computer and use it in GitHub Desktop.
HttpClient Wrapper with logging functionality using Serilog
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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