如何全局跟踪.net core 2.1中的所有HTTP请求?

问题描述 投票:0回答:5

我想记录 dotnet core 2.1 应用程序中的所有 HTTP 请求。日志记录应包括 HTTP 标头、正文和主机地址。我需要全局绑定我的日志记录代码而不更改现有代码。

我尝试了这个示例https://www.azurefromthetrenches.com/capturing-and-tracing-all-http-requests-in-c-and-net/,但没有 HTTP 事件到达侦听器。

有没有办法在 dotnet core 2.1 上全局监听 HTTP 事件?

c# .net-core dotnet-httpclient system.diagnostics
5个回答
13
投票

这是一篇很好的博客文章,由 Steve Gordon 撰写,关于 HttpClient 登录 .Net Core 2.1。

本质上,您需要将 System.Net.Http.HttpClient 的日志记录级别设置为 Trace 才能获取有关请求和响应的详细信息。

appsettings.json 中所需部分的示例如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "System.Net.Http.HttpClient": "Trace"
    }
  }

这将显示所有 HttpClient 请求和响应的所有跟踪日志记录。


4
投票

您可以在中间件中记录所有http请求信息。看看下面的例子

1.创建一个类

RequestHandlerMiddleware.cs

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.IO;
using System.Threading.Tasks;

namespace Onsolve.ONE.WebApi.Middlewares
{
    public sealed class RequestHandlerMiddleware
    {
        private readonly RequestDelegate next;
        private readonly ILogger logger;

        public RequestHandlerMiddleware(ILogger<RequestHandlerMiddleware> logger, RequestDelegate next)
        {
            this.next = next;
            this.logger = logger;
        }

        public async Task Invoke(HttpContext context)
        {
            logger.LogInformation($"Header: {JsonConvert.SerializeObject(context.Request.Headers, Formatting.Indented)}");

            context.Request.EnableBuffering();
            var body = await new StreamReader(context.Request.Body).ReadToEndAsync();
            logger.LogInformation($"Body: {body}");
            context.Request.Body.Position = 0;

            logger.LogInformation($"Host: {context.Request.Host.Host}");
            logger.LogInformation($"Client IP: {context.Connection.RemoteIpAddress}");
            await next(context);
        }

    }
}

2.在

RequestHandlerMiddleware
中的
Configure
方法中添加
Startup.cs

app.UseMiddleware<RequestHandlerMiddleware>();

或更简单

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
    app.Use(async (context, next) =>
    {
        logger.LogInformation($"Header: {JsonConvert.SerializeObject(context.Request.Headers, Formatting.Indented)}");

        context.Request.EnableBuffering();
        var body = await new StreamReader(context.Request.Body).ReadToEndAsync();
        logger.LogInformation($"Body: {body}");
        context.Request.Body.Position = 0;

        logger.LogInformation($"Host: {context.Request.Host.Host}");
        logger.LogInformation($"Client IP: {context.Connection.RemoteIpAddress}");
        await next.Invoke();
    });
}

参考:

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.2

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-2.2


1
投票

需要使用Observer设计模式以及.NET提供的hook来观察所有的http请求。

  • 诊断来源
  • 事件来源

这是一篇很好的博客文章


0
投票

由于这个问题的其他答案要么不适合我,要么看起来太复杂而无法使用,我将发布我的 ASP.NET Core 8 WebAPI 解决方案,该解决方案记录所有 REST 请求。

首先,

AddHttpLogging
必须配置要记录的 HTTP 字段,然后按
UseHttpLogging
启用配置的设置:

public class Program
{
    public static void Main(string[] args)
    {
        WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        builder.Services.AddControllers();
        
        // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();

        // Add HTTP logging, log all HTTP fields.
        builder.Services.AddHttpLogging(logging =>
        { 
            logging.LoggingFields = HttpLoggingFields.All;
        });

        var app = builder.Build();

        app.UseHttpLogging();

        // Configure the HTTP request pipeline.
        if(app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseHttpsRedirection();
        app.UseAuthorization();

        app.MapControllers();

        // Use the configured HTTP logging.
        app.UseHttpLogging();

        app.Run();
    }
}

接下来appsettings.json(或appsettings.development.json)必须配置日志记录级别以捕获:

{
  "Logging": {
    "LogLevel": {
        "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Trace"
    }
  }
}

这篇 Microsoft 开发博客文章更详细地解释了该主题。


-1
投票

尝试了下面更简单的解决方案,该解决方案在不篡改最终响应流程的情况下工作

创建中间件类来拦截所有请求和响应。在startup.cs中启用中间件类关联

app.UseMiddleware<HttpRequestResponseLogger>();

实现一个中间件类来拦截请求和响应。您可以选择将这些日志存储在数据库中。我忽略了秘密和不必要的标头值

 public class HttpRequestResponseLogger
{
    RequestDelegate next;

    public HttpRequestResponseLogger(RequestDelegate next)
    {
        this.next = next;
    }
    //can not inject as a constructor parameter in Middleware because only Singleton services can be resolved
    //by constructor injection in Middleware. Moved the dependency to the Invoke method
    public async Task InvokeAsync(HttpContext context, IHttpLogRepository repoLogs)
    {
        HttpLog logEntry = new HttpLog();
        await RequestLogger(context, logEntry);
        
        await next.Invoke(context);

        await ResponseLogger(context, logEntry);

        //store log to database repository
        repoLogs.SaveLog(logEntry);
    }

    // Handle web request values
    public async Task RequestLogger(HttpContext context, HttpLog log)
    {
        string requestHeaders = string.Empty;

        log.RequestedOn = DateTime.Now;
        log.Method = context.Request.Method;
        log.Path = context.Request.Path;
        log.QueryString = context.Request.QueryString.ToString();
        log.ContentType = context.Request.ContentType;

        foreach (var headerDictionary in context.Request.Headers)
        {
            //ignore secrets and unnecessary header values
            if (headerDictionary.Key != "Authorization" && headerDictionary.Key != "Connection" &&
                headerDictionary.Key != "User-Agent" && headerDictionary.Key != "Postman-Token" &&
                headerDictionary.Key != "Accept-Encoding")
            {
                requestHeaders += headerDictionary.Key + "=" + headerDictionary.Value + ", ";
            }
        }

        if (requestHeaders != string.Empty)
            log.Headers = requestHeaders;

        //Request handling. Check if the Request is a POST call 
        if (context.Request.Method == "POST")
        {
            context.Request.EnableBuffering();
            var body = await new StreamReader(context.Request.Body).ReadToEndAsync();
            context.Request.Body.Position = 0;
            log.Payload = body;
        }
    }

    //handle response values
    public async Task ResponseLogger(HttpContext context, HttpLog log)
    {
        using (Stream originalRequest = context.Response.Body)
        {
            try
            {
                using (var memStream = new MemoryStream())
                {
                    context.Response.Body = memStream;
                    // All the Request processing as described above 
                    // happens from here.
                    // Response handling starts from here
                    // set the pointer to the beginning of the 
                    // memory stream to read
                    memStream.Position = 0;
                    // read the memory stream till the end
                    var response = await new StreamReader(memStream)
                        .ReadToEndAsync();
                    // write the response to the log object
                    log.Response = response;
                    log.ResponseCode = context.Response.StatusCode.ToString();
                    log.IsSuccessStatusCode = (
                        context.Response.StatusCode == 200 ||
                        context.Response.StatusCode == 201);
                    log.RespondedOn = DateTime.Now;

                    // since we have read till the end of the stream, 
                    // reset it onto the first position
                    memStream.Position = 0;

                    // now copy the content of the temporary memory 
                    // stream we have passed to the actual response body 
                    // which will carry the response out.
                    await memStream.CopyToAsync(originalRequest);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                // assign the response body to the actual context
                context.Response.Body = originalRequest;
            }
        }

    }
© www.soinside.com 2019 - 2024. All rights reserved.