简体   繁体   中英

add header request and header response to the serilog midlleware logging

I added serilog logging to my .net core web api, but I want to extend my current middleware for displaying also a header request. here is my middleware class:

internal class SerilogRequestLoggerMiddleware
{
    readonly RequestDelegate _next;

    public SerilogRequestLoggerMiddleware(RequestDelegate next)
    {
        if (next == null) throw new ArgumentNullException(nameof(next));
        _next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));

        // Push the user name into the log context so that it is included in all log entries
        LogContext.PushProperty("UserName", httpContext.User.Identity.Name);

        // Getting the request body is a little tricky because it's a stream
        // So, we need to read the stream and then rewind it back to the beginning
        string requestBody = "";
        HttpRequestRewindExtensions.EnableBuffering(httpContext.Request);
        Stream body = httpContext.Request.Body;
        byte[] buffer = new byte[Convert.ToInt32(httpContext.Request.ContentLength)];
        await httpContext.Request.Body.ReadAsync(buffer, 0, buffer.Length);
        requestBody = Encoding.UTF8.GetString(buffer);
        body.Seek(0, SeekOrigin.Begin);
           


        httpContext.Request.Body = body;

        Log.ForContext("RequestHeaders", httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()), destructureObjects: true)
            .ForContext("RequestBody", requestBody)
            .Debug("Request information {RequestMethod} {RequestPath} information", httpContext.Request.Method, httpContext.Request.Path);
        Log.Information(string.Format("Request Header: {0} ", requestBody));
        Log.Information(string.Format("Request Body: {0} ", requestBody));
        // The reponse body is also a stream so we need to:
        // - hold a reference to the original response body stream
        // - re-point the response body to a new memory stream
        // - read the response body after the request is handled into our memory stream
        // - copy the response in the memory stream out to the original response stream
        using (var responseBodyMemoryStream = new MemoryStream())
        {
            var originalResponseBodyReference = httpContext.Response.Body;
            httpContext.Response.Body = responseBodyMemoryStream;

            //await _next(httpContext);

            try
            {
                await _next(httpContext);
            }
            catch (Exception exception)
            {
                Guid errorId = Guid.NewGuid();
                Log.ForContext("Type", "Error")
                    .ForContext("Exception", exception, destructureObjects: true)
                    .Error(exception, exception.Message + ". {@errorId}", errorId);

                var result = JsonConvert.SerializeObject(new { error = exception.Message, errorId = errorId });
                httpContext.Response.ContentType = "application/json";
                httpContext.Response.StatusCode = 500;
                await httpContext.Response.WriteAsync(result);
            }

            httpContext.Response.Body.Seek(0, SeekOrigin.Begin);
            var responseBody = await new StreamReader(httpContext.Response.Body).ReadToEndAsync();
            httpContext.Response.Body.Seek(0, SeekOrigin.Begin);

            Log.ForContext("RequestBody", requestBody)
                .ForContext("ResponseBody", responseBody)
                .Debug("Response information {RequestMethod} {RequestPath} {statusCode}", httpContext.Request.Method, httpContext.Request.Path, httpContext.Response.StatusCode);

            await responseBodyMemoryStream.CopyToAsync(originalResponseBodyReference);
        }
    }
}

I tried something like this

    //byte[] bufferHeader = new byte[Convert.ToInt32(httpContext.Request.Headers.ContentLength)];
    var header1 = httpContext.Request.Headers;
    var bn = header1 .Values.ToList();

and I got it some 20 different objects that are not presented in my initial api call (cors, localhost address, gz, something unfamiliar to me..)

Can someone bring up the light here, what is the proper way to log header request/response for an api methods, preferably through middleware?

I believe you know the header key(s) that you want to log, right?

If so, you may use:

  • .TryGetValue(TKey key, out TValue value) - This returns true if the request has such header, with the value being set to the out variable. Example below:
bool headerExists = httpContext.Request.Headers.TryGetValue("header-key", out var headerValue);
  • .this[string key] - This gets the header value if the dictionary has the key. However, it throws an exception if the key does not exist. Example below:
var headerValue = HttpContext.Request.Headers["header-key"];

On the other hand, if you have a list of headers that you do not want to log, then I think you have to get all the headers and exclude those ones.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM