1

How do you log the HTTP Requests that the Kentico Kontent .NET delivery API here: https://github.com/Kentico/kontent-delivery-sdk-net

Specifically what I am looking for is how to log the HTTP Get requests to delivery.kentico.ai (the end point that you retrieve your content JSON from).

Matt
  • 425
  • 3
  • 13

3 Answers3

3

You can enrich and inject an HttpClient to the DeliveryClient.

Enrich:

    public class LoggingHandler : DelegatingHandler
    {
        public LoggingHandler(HttpMessageHandler innerHandler, Microsoft.Extensions.Logging.ILogger logger)
            : base(innerHandler)
        {
            Logger = logger;
        }

        public Microsoft.Extensions.Logging.ILogger Logger { get; }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Logger.LogInformation(request.Method + " " + request.RequestUri);

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

            Logger.LogInformation(response.StatusCode + " " + response.Content.Headers);
            return response;
        }
    }

Use e.g. Serilog

        services.AddLogging(builder =>
        {
            // Add Serilog
            builder.AddSerilog(new LoggerConfiguration()
                    .MinimumLevel.Information()
                    .WriteTo.File("logs\\log.log", rollingInterval: RollingInterval.Day)
                    .CreateLogger());
        });

        var serviceProvider = services.BuildServiceProvider();
        var logger = serviceProvider.GetRequiredService<ILogger<Startup>>();

        HttpClient httpClient = new HttpClient(new LoggingHandler(new HttpClientHandler(), logger));

        var deliveryOptions = new DeliveryOptions();
        Configuration.GetSection(nameof(DeliveryOptions)).Bind(deliveryOptions);

Inject:

        var deliveryClient = DeliveryClientBuilder
            .WithOptions(_ => deliveryOptions)
            .WithHttpClient(httpClient)
            .Build();

Additional resources:

rocky
  • 7,506
  • 3
  • 33
  • 48
  • I finally got around to trying this, but there appears to be one issue with this. The following line: var serviceProvider = services.BuildServiceProvider(); You get this: 1>Startup.cs(82,35,82,66): warning ASP0000: Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'. – Matt Feb 28 '20 at 23:44
  • Good point, it's not a good practice anymore. Check out an alternative approach using the `HttpClientFactory`: https://stackoverflow.com/questions/59038293/how-to-log-httpclient-requests-in-kentico-kontent-net-delivery-client/60490678#60490678 – rocky Mar 02 '20 at 14:14
1

Alternative approach using HttpClientFactory:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddLogging(builder =>
            {
                // Add Serilog
                builder.AddSerilog(new LoggerConfiguration()
                        .MinimumLevel.Information()
                        .WriteTo.File("logs\\log.log", rollingInterval: RollingInterval.Day)
                        .CreateLogger());
            });
            services.AddTransient<LoggingHandler>();

            services.AddHttpClient("FactoryClient", c => { /* Do whatever else you wish here... */ })
                    .AddHttpMessageHandler<LoggingHandler>()
                    .AddTypedClient(c => DeliveryClientBuilder.WithOptions(...).WithHttpClient(c).Build());
            services.AddControllersWithViews();
        }

LoggingHandler.cs

public class LoggingHandler : DelegatingHandler
    {
        public Microsoft.Extensions.Logging.ILogger Logger { get; }

        public LoggingHandler(ILoggerFactory loggerFactory) : base()
        {
            Logger = loggerFactory.CreateLogger<LoggingHandler>();
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            Logger.LogInformation(request.Method + " " + request.RequestUri);

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

            Logger.LogInformation(response.StatusCode + " " + response.Content.Headers);
            return response;
        }
    }
rocky
  • 7,506
  • 3
  • 33
  • 48
1

Yet another approach is to use the Serilog.AspNetCore NuGet package: https://github.com/serilog/serilog-aspnetcore

Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            .UseSerilog(); // <-- Add this line;
}

Startup.cs

public void Configure(IApplicationBuilder app)
{
  app.UseSerilogRequestLogging();
}

Example code: https://github.com/Kentico/kontent-sample-app-net/commit/44f1a0e6b245b7ad0be2f0e48a1085adbf80584a

rocky
  • 7,506
  • 3
  • 33
  • 48