首页 > 解决方案 > 请求和响应日志的自然链接 .NET Core 应用

问题描述

我正在尝试通过 GUID 链接我的请求和响应日志。要么我为每个请求和响应获得相同的 GUID,要么我为每个请求和响应获得一个完全不同的 GUID。我需要的是链接的请求和响应具有相同的 GUID,但与所有其他请求和响应不同。甚至可以用我目前的结构做到这一点吗?

public class RequestResponseLoggingMiddleware
    {
        
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;
        private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;

        public RequestResponseLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.CreateLogger<RequestResponseLoggingMiddleware>();
            _recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
        }

        public async Task Invoke(HttpContext context)
        {
            await LogRequest(context);
            await LogResponse(context);

        }

        private async Task LogRequest(HttpContext context)
        {
            context.Request.EnableBuffering();

            await using var requestStream = _recyclableMemoryStreamManager.GetStream();
            await context.Request.Body.CopyToAsync(requestStream);


            var Request = new Dictionary<string, string>(){
                {"Http Request Information", $"{DateTime.UtcNow}"},
                {"ID", Guid.NewGuid().ToString()},
                {"IP", $"{context.Request.HttpContext.Connection.RemoteIpAddress}" },
                {"Schema", context.Request.Scheme},
                {"Path", context.Request.Path},
                {"QueryString", $"{context.Request.QueryString}"},
                {"Request Body", ReadStreamInChunks(requestStream)}
            };

            var requestJson = JsonConvert.SerializeObject(Request, Formatting.None);

            _logger.LogInformation(requestJson);

            context.Request.Body.Position = 0;
        }


        private async Task LogResponse(HttpContext context)
        {
            var originalBodyStream = context.Response.Body;

            await using var responseBody = _recyclableMemoryStreamManager.GetStream();
            context.Response.Body = responseBody;

            await _next(context);

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

            var Response = new Dictionary<string, string>(){
                {"Http Response Information", $"{DateTime.UtcNow}"},
                {"ID", Guid.NewGuid().ToString()},
                {"IP", $"{context.Request.HttpContext.Connection.RemoteIpAddress}" },
                {"Schema", context.Request.Scheme},
                {"Path", context.Request.Path },
                {"QueryString", $"{context.Request.QueryString}"},
                {"Response Body", text}
            };

            var responseJson = JsonConvert.SerializeObject(Response, Formatting.None);

            _logger.LogInformation(responseJson);

            await responseBody.CopyToAsync(originalBodyStream);
        }

        private static string ReadStreamInChunks(Stream stream)
        {
            const int readChunkBufferLength = 4096;

            stream.Seek(0, SeekOrigin.Begin);

            using var textWriter = new StringWriter();
            using var reader = new StreamReader(stream);

            var readChunk = new char[readChunkBufferLength];
            int readChunkLength;

            do
            {
                readChunkLength = reader.ReadBlock(readChunk, 0, readChunkBufferLength);
                textWriter.Write(readChunk, 0, readChunkLength);
            } while (readChunkLength > 0);

            return textWriter.ToString();
        }

标签: c#.net-core

解决方案


我会扩展请求和响应 json 对象并在那里添加一些 ID 字段并使用相同的 Guid 填充:

public class RequestResponseLoggingMiddleware
    {
        
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;
        private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;

        public RequestResponseLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.CreateLogger<RequestResponseLoggingMiddleware>();
            _recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
        }

        public async Task Invoke(HttpContext context)
        {
            var guid = Guid.NewGuid();
            await LogRequest(context, guid);
            await LogResponse(context, guid);

        }

        private async Task LogRequest(HttpContext context, Guid guid)
        {
            context.Request.EnableBuffering();

            await using var requestStream = _recyclableMemoryStreamManager.GetStream();
            await context.Request.Body.CopyToAsync(requestStream);


            var Request = new Dictionary<string, string>(){
                {"Request ID", guid.ToString()}
                {"Http Request Information", $"{DateTime.UtcNow}"},
                {"ID", Guid.NewGuid().ToString()},
                {"IP", $"{context.Request.HttpContext.Connection.RemoteIpAddress}" },
                {"Schema", context.Request.Scheme},
                {"Path", context.Request.Path},
                {"QueryString", $"{context.Request.QueryString}"},
                {"Request Body", ReadStreamInChunks(requestStream)}
            };

            var requestJson = JsonConvert.SerializeObject(Request, Formatting.None);

            _logger.LogInformation(requestJson);

            context.Request.Body.Position = 0;
        }


        private async Task LogResponse(HttpContext context, Guid guid)
        {
            var originalBodyStream = context.Response.Body;

            await using var responseBody = _recyclableMemoryStreamManager.GetStream();
            context.Response.Body = responseBody;

            await _next(context);

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

            var Response = new Dictionary<string, string>(){
                {"Request ID", guid.ToString()}
                {"Http Response Information", $"{DateTime.UtcNow}"},
                {"ID", Guid.NewGuid().ToString()},
                {"IP", $"{context.Request.HttpContext.Connection.RemoteIpAddress}" },
                {"Schema", context.Request.Scheme},
                {"Path", context.Request.Path },
                {"QueryString", $"{context.Request.QueryString}"},
                {"Response Body", text}
            };

            var responseJson = JsonConvert.SerializeObject(Response, Formatting.None);

            _logger.LogInformation(responseJson);

            await responseBody.CopyToAsync(originalBodyStream);
        }

        private static string ReadStreamInChunks(Stream stream)
        {
            const int readChunkBufferLength = 4096;

            stream.Seek(0, SeekOrigin.Begin);

            using var textWriter = new StringWriter();
            using var reader = new StreamReader(stream);

            var readChunk = new char[readChunkBufferLength];
            int readChunkLength;

            do
            {
                readChunkLength = reader.ReadBlock(readChunk, 0, readChunkBufferLength);
                textWriter.Write(readChunk, 0, readChunkLength);
            } while (readChunkLength > 0);

            return textWriter.ToString();
        }

推荐阅读