简体   繁体   English

请求和响应日志的自然链接 .NET Core 应用程序

[英]Natural Linking of Request and Response logs .NET Core app

I am trying to link my request and response logs by GUID.我正在尝试通过 GUID 链接我的请求和响应日志。 Either i get the same GUID for every request and response, or i get a completely different one fore every request and response.要么我为每个请求和响应获得相同的 GUID,要么在每个请求和响应之前获得一个完全不同的 GUID。 What i need is for the linked Requests and responses to have the Same GUID, but be different to all other requests an responses.我需要的是链接的请求和响应具有相同的 GUID,但与所有其他请求和响应不同。 Is it even possible to do this with my current structure?甚至可以用我目前的结构来做到这一点吗?

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();
        }

I'd extend request and response json objects and add there some ID fields and fill the with the same Guid:我会扩展请求和响应 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();
        }

I am not sure if there's a specific principle you "link" your requests and responses, but assuming it's stock standard asp.net core app and you work within user request, I believe it is possible to inject scoped services into your middleware.我不确定您是否有特定的原则来“链接”您的请求和响应,但假设它是标准的 asp.net 核心应用程序并且您在用户请求中工作,我相信可以将范围服务注入您的中间件。 So, suppose you create a service with something these lines:因此,假设您使用以下几行创建了一个服务:

class GuidProvider {
   public string CorrelationId {get; private set;}
   public GuidProvider() {
      CorrelationId = Guid.NewGuid().ToString()
   }
}

you'd register it in Startup :你会在Startup注册它:

services.AddScoped(typeof(GuidProvider));

and inject into your middleware constructor:并注入您的中间件构造函数:

public RequestResponseLoggingMiddleware(..., GuidProvider guidProvider) 
{ 
   guidProvider.CorrelationId; // should stay the same within request 
   ... 
}```

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 ASP NET核心Serilog:请求,响应和异常日志的不同文件 - ASP NET core Serilog : Different files for Request, Response and Exception logs 如何在Azure for Net Core 2 App中启用应用程序日志? - How to enable Application Logs in Azure for Net Core 2 App? 长时间运行的任务 api 从逻辑应用程序调用以避免在.Net Core 3.0 中多次重试后超时错误请求响应 - Long running task api call from logic app to avoid timeout bad request response after many retiries in .Net Core 3.0 战略以及如何在.net core 3.0中间件中创建请求和响应管道 - Strategy and how to create Request and Response pipes in .net core 3.0 middleware .net Core 6 不会根据请求中的接受类型发送响应 - .net Core 6 doesn't send response based on Accept type in request .net 核心控制台日志和命令 - .net core console logs and commands 从 ASP.NET Core 应用程序的根返回特定响应 - Return a specific response from the root of an ASP.NET Core app 在 .net 内核中,在用户登录后立即进行一些日志记录。而不是在每个请求上 - In .net core, do some logging right after user logs in. And NOT on every request 在 ASP.NET 核心应用程序中获取 Azure 洞察遥测数据/搜索日志 - Get Azure Insights Telemetry Data / Search Logs in ASP.NET Core app 覆盖来自 ASP.NET 核心应用程序的 ElasticSearch 日志中的 fields.RequestId - Override fields.RequestId in ElasticSearch logs from ASP.NET Core app
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM