<commit_before>﻿using System.Diagnostics;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Cimpress.Extensions.Http.MessageHandlers
{
    /// <summary>
    /// Observes a service call and logs invocation time and outcome.
    /// </summary>
    public class MeasurementHandler : DelegatingHandler
    {
        public ILogger Logger { get; }

        public MeasurementHandler(ILogger logger) : base(new HttpClientHandler())
        {
            Logger = logger;
        }

        /// <summary>
        /// Measures invocation time of the underlying service call and logs it.
        /// </summary>
        /// <returns></returns>
        /// <remarks>This method logs failed HTTP calls, but does not perform any exception handling
        /// - it's up to the calling client to handle erroneous code.</remarks>
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var sw = Stopwatch.StartNew();
            HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

            sw.Stop();
            var method = response.RequestMessage.Method.Method;
            var uri = response.RequestMessage.RequestUri;
            var status = response.StatusCode;
            bool isSuccess = response.IsSuccessStatusCode;

            //generates log entry like: "HTTP GET at http://localhost/foo.bar failed with status NotFound in 19ms."

            string result = isSuccess ? "completed successfully" : "failed";
            var message = "HTTP {HttpMethod} at {ServiceUri} {HttpResult} with status {HttpStatus} in {ElapsedMilliseconds}ms.";
            Logger.LogInformation(message, method, uri, result, status, sw.ElapsedMilliseconds);

            return response;
        }
    }
}<commit_msg>Perform logging in a different thread than the main thread. Closes #10<commit_after>﻿using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace Cimpress.Extensions.Http.MessageHandlers
{
    /// <summary>
    /// Observes a service call and logs invocation time and outcome.
    /// </summary>
    public class MeasurementHandler : DelegatingHandler
    {
        public ILogger Logger { get; }

        public MeasurementHandler(ILogger logger) : base(new HttpClientHandler())
        {
            Logger = logger;
        }
        
        /// <summary>
        /// Measures invocation time of the underlying service call and logs it.
        /// </summary>
        /// <returns></returns>
        /// <remarks>This method logs failed HTTP calls, but does not perform any exception handling
        /// - it's up to the calling client to handle erroneous code.</remarks>
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var sw = Stopwatch.StartNew();
            var sendTask = base.SendAsync(request, cancellationToken);

            // schedule the continuation without ever awaiting it
            sendTask.ContinueWith(t =>
            {
                sw.Stop();
                var r = t.Result;
                var method = request.Method.Method;
                var uri = request.RequestUri;

                HttpStatusCode status = 0;
                string result = null;
                if (t.IsCompleted)
                {
                    status = r.StatusCode;
                    result = r.IsSuccessStatusCode ? "completed successfully" : "failed";
                }
                else if (t.IsCanceled)
                {
                    result = "canceled";
                }
                else if (t.IsFaulted)
                {
                    result = "faulted";
                }

                //generates log entry like: "HTTP GET at http://localhost/foo.bar failed with status NotFound in 19ms."
                var message = "HTTP {HttpMethod} at {ServiceUri} {HttpResult} with status {HttpStatus} in {ElapsedMilliseconds}ms.";
                Logger.LogInformation(message, method, uri, result, status, sw.ElapsedMilliseconds);
            }, cancellationToken);

            return sendTask;
        }
    }
}
{'fraction_non_alphanumeric': 0.08905677655677656, 'fraction_numerical': 0.0016025641025641025, 'mean_word_length': 2.0298196948682388, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2143378', 'n_tokens_mistral': 1075, 'n_tokens_neox': 1033, 'n_words': 326}