Serilog - howto + log any httpclient request/response

Costas

Administrator
Staff member
article is for .net framework for .net core see UseSerilogRequestLogging

C#:
///////////////////////////// main project

//nuget
Install-Package Serilog
Install-Package Serilog.Sinks.File

//class
using Serilog;

namespace hi
{
    public static class LogConfig
    {
        public static void Configure()
        {
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Verbose()
                .WriteTo.File("C:\\temp\\log.txt")
                .CreateLogger();

            //share logger to a reference dll, lets continue log also there! (read below)
            DllLogConfig.Configure(Log.Logger);
        }
    }
}

//Global.asax.cs
protected void Application_Start()
{
    LogConfig.Configure();
}

protected void Application_End()
{
    Log.CloseAndFlush();
}

///////////////////////////// reference DLL

//install the Serilog nuget package

//class
using Serilog;

public static class DllLogConfig
{
    public static ILogger Logger { get; private set; }

    public static void Configure(ILogger logger)
    {
        Logger = logger;
    }
}


///////////////////////////// how to log

// main project
Log.Information("About action called.");

// in reference dll
DllLogConfig.Logger.Information("MyMethod was called.");


///////////////////////////// how to log any httpclient request/response

//LoggingHttpClientHandler.cs
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Serilog;

public class LoggingHttpClientHandler : DelegatingHandler
{
    public LoggingHttpClientHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        try
        {
            Log.Information("Sending request: {Method} {Uri}", request.Method, request.RequestUri);
            foreach (var header in request.Headers)
            {
                Log.Information("Request Header: {Header}: {Value}", header.Key, string.Join(", ", header.Value));
            }
            if (request.Content != null)
            {
                var requestBody = await request.Content.ReadAsStringAsync();
                Log.Information("Request body: {RequestBody}", requestBody);
            }

            var response = await base.SendAsync(request, cancellationToken);

            Log.Information("Received response: {StatusCode}", response.StatusCode);
            if (response.Content != null)
            {
                var responseBody = await response.Content.ReadAsStringAsync();
                Log.Information("Response body: {ResponseBody}", responseBody);
            }

            return response;
        }
        catch (Exception ex)
        {
            Log.Error(ex, "An error occurred while sending the request: {Message}", ex.Message);
            throw;
        }
    }
}




//HttpClientService.cs
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

public class HttpClientService
{

    private readonly HttpClient _httpClient;

    public HttpClientService()
    {
        var handler = new LoggingHttpClientHandler(new HttpClientHandler());
        _httpClient = new HttpClient(handler);
    }

    // Expose DefaultRequestHeaders
    public HttpRequestHeaders DefaultRequestHeaders => _httpClient.DefaultRequestHeaders;

    public async Task<HttpResponseMessage> CallApiAsync(HttpRequestMessage request)
    {
        return await _httpClient.SendAsync(request);
    }
}


//sample of use
internal static async Task<FootballProgressResponse> FootballProgress(string token, FootballProgressRequest request)
{
    Uri requestUrl = new Uri("https:/e.com/FootballProgress");

    var httpClientService = new HttpClientService();

    httpClientService.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
    httpClientService.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    httpClientService.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest");
    //httpClientService.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Content-Type", "application/x-www-form-urlencoded");

    var payload = JsonConvert.SerializeObject(request);

    var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUrl)
    {
        Content = new StringContent(payload, Encoding.UTF8, "application/json")
        //Content = new FormUrlEncodedContent(postValues); //postValues is KeyValuePair<string, string>
    };

    HttpResponseMessage response = await httpClientService.CallApiAsync(requestMessage);

    string result = await response.Content.ReadAsStringAsync();

    if (String.IsNullOrWhiteSpace(result))
        return null;

    var FootballProgressResponse = JsonConvert.DeserializeObject<FootballProgressResponse>(result);

    FootballProgressResponse.StatusCode = response.StatusCode;
    return FootballProgressResponse;
}



Enriching specific log events
additional contextual information to log events, enhancing the detail of the logs generated

https://peterdaugaardrasmussen.com/...log-how-to-enrich-log-events-with-properties/
https://github.com/serilog/serilog/wiki/Enrichment
 
Top