如何在asp.net核心(Kestrel)中记录http请求消息(不是正文)和响应消息(不是正文)

时间:2018-03-28 07:24:51

标签: c# .net-core asp.net-core-mvc asp.net-core-webapi

我的请求样本

GET http://localhost:5000/api/values HTTP/1.1
cache-control: no-cache
User-Agent: PostmanRuntime/6.4.1
Accept: */*
Host: localhost:5000
accept-encoding: gzip, deflate
Connection: keep-alive

和回复

HTTP/1.1 200 OK
Date: Wed, 28 Mar 2018 07:18:08 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 19

["value1","value2"]

我希望得到所有http消息的日志

我应该如何获取请求消息和响应消息

因为我可以找到任何错误的日志(如错误请求消息(自定义TCP))

2 个答案:

答案 0 :(得分:0)

一个选项是创建自定义中间件,然后您可以检查请求/响应以构建所需的日志。

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?tabs=aspnetcore2x#writing-middleware

中间件允许您在途中获取请求并在出路时获取响应。

在上下文(HttpContext)上,你应该能够得到你期望的数据 - https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpcontext?view=aspnetcore-2.0

答案 1 :(得分:0)

我编写了一个中间件,以nginx样式记录(几乎)访问日志。 您可以执行大致相同的操作,并在LogData类中添加并填充自己的字段,然后更改DefaultFormatter函数。

public class RequestLogMiddleware
{

    public class LogData {
        public IPAddress RemoteAddr {get;set;}
        public string User {get; set;}
        public int ResponseStatus {get; set;}

        public string RequestMethod {get;set;}
        public string RequestTimestamp {get;set;}
        public string RequestPath {get;set;}

        public string RequestProtocol {get;set;}
        public string UserAgent {get;set;}

        public long DurationMs {get;set;}
    }

    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public RequestLogMiddleware(RequestDelegate next, ILoggerFactory factory)
    {
        _next = next;
        _logger = factory.CreateLogger("RequestLog");

    }

    private Func<LogData, string> _logLineFormatter;
    private Func<LogData,string> logLineFormatter{
        get  {

            if (this._logLineFormatter != null) {
                return this._logLineFormatter;
            } 
            return this.DefaultFormatter();
        }
        set {
            this._logLineFormatter = value;
        }
    }

    /// <summary>
    /// Override this to set the default formatter if none was supplied
    /// </summary>
    /// <returns></returns>
    protected Func<LogData, string> DefaultFormatter() {
            return (logData => $"{logData.RemoteAddr} - {logData.User} {logData.RequestTimestamp} \"{logData.RequestMethod} {logData.RequestPath} {logData.RequestProtocol}\" {logData.ResponseStatus} \"{logData.UserAgent}\" {logData.DurationMs}ms");
    }

    /// <summary>
    /// Used to set a custom formatter for this instance
    /// </summary>
    /// <param name="formatter"></param>
    public void SetLogLineFormat(Func<LogData, string> formatter) {
        this._logLineFormatter = formatter;
    }

    public async Task Invoke(HttpContext context)
    {

        var now = DateTime.Now;
        var watch = Stopwatch.StartNew();
        await _next.Invoke(context);
        watch.Stop();

        var nowString = now.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
        var user = context.User.Identity.Name ?? "-";
        var request = context.Request.Path +  (string.IsNullOrEmpty(context.Request.QueryString.ToString()) ? "" : context.Request.QueryString.ToString());
        var responseStatus = context.Response.StatusCode;
        var userAgent = context.Request.Headers.ContainsKey("User-Agent") ? context.Request.Headers["User-Agent"].ToString() : "-";
        var protocol = context.Request.Protocol;
        var duration = watch.ElapsedMilliseconds;
        var remoteAddr = context.Connection.RemoteIpAddress;    
        var method = context.Request.Method;

        var logData = new LogData {
            RemoteAddr = remoteAddr,
            RequestMethod = method,
            RequestPath = request,
            RequestProtocol = protocol,
            RequestTimestamp = nowString,
            ResponseStatus = responseStatus,
            User = user,
            UserAgent = userAgent,
            DurationMs = duration,
        };

        _logger.LogInformation(this.logLineFormatter(logData));

    }
}

只需通过Configure中的Startup.cs方法将其连接起来即可:

app.UseMiddleware(typeof(RequestLogMiddleware));

确保它是您添加的第一个中间件。

示例输出:

info: RequestLog[0]
      ::1 - - 2018-08-10T14:23:04.183+02:00 "GET /api/ping HTTP/1.1" 200 "-" 266ms
info: RequestLog[0]
      ::1 - - 2018-08-10T14:23:04.569+02:00 "POST /api/search HTTP/1.1" 401 "-" 31ms
info: RequestLog[0]
      ::1 - - 2018-08-10T14:23:04.375+02:00 "POST /api/search HTTP/1.1" 200 "-" 3453ms
info: RequestLog[0]
      ::1 - - 2018-08-10T14:23:04.375+02:00 "POST /api/search HTTP/1.1" 200 "-" 4341ms
info: RequestLog[0]
      ::1 - - 2018-08-10T14:23:08.932+02:00 "POST /api/search HTTP/1.1" 400 "-" 16ms

可以在配置中打开/关闭记录器:

"Logging": {
    "LogLevel": {
      "Default": "Warning",
      "RequestLog": "Information"
    }
},