中间件_监控调用接口记录日志

1、监控中间件
public class OuterApiMonitorMiddleware : IMiddleware
{
    //private readonly ILogger<OuterApiMonitorMiddleware> _logger;
    private readonly IOuterApiLogger _apiLog;
    public OuterApiMonitorMiddleware(/*ILogger<OuterApiMonitorMiddleware> logger,*/ IOuterApiLogger apiLog)
    {
        //_logger = logger;
        _apiLog = apiLog;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var path = context.Request.Path.Value ?? string.Empty;

        //注意:这里重点,对访问地址是/PRO/INTEGRATION开头的自动记录log
        if (!path.StartsWith("/PRO/INTEGRATION", StringComparison.OrdinalIgnoreCase))
        {
            await next.Invoke(context);
            return;
        }

        await Monitor(context, next, path);
    }

    /// <summary>
    /// 监控接口调用
    /// </summary>
    private async Task Monitor(HttpContext context, RequestDelegate next, string path)
    {
        var stopWatch = Stopwatch.StartNew();

        var start = DateTime.Now;
        DateTime end;
        Exception exception = null;
        var requestBody = string.Empty;
        var responseBody = string.Empty;

        try
        {
            requestBody = await new StreamReader(context.Request.Body).ReadToEndAsync();
            context.Request.Body.Position = 0;

            var originalResponseBody = context.Response.Body;
            try
            {
                using var swapStream = new MemoryStream();
                context.Response.Body = swapStream;

                await next(context);

                context.Response.Body.Seek(0, SeekOrigin.Begin);

                using var s= new StreamReader(context.Response.Body);
                responseBody = await s.ReadToEndAsync();

                context.Response.Body.Seek(0, SeekOrigin.Begin);
                await swapStream.CopyToAsync(originalResponseBody);
            }
            finally
            {
                context.Response.Body = originalResponseBody;
            }
        }
        catch (Exception e)
        {
            exception = e;
        }

        stopWatch.Stop();
        end = DateTime.Now;

        await Logger(context, requestBody, responseBody, (long)stopWatch.ElapsedMilliseconds, start, end, exception);
    }

    /// <summary>
    /// 记录日志
    /// </summary>
    private async Task Logger(HttpContext context, string requestBody, string responseBody, long elapsed, DateTime start, DateTime end, Exception exception)
    {
        var entry = new ProOuterApiLog
        {
            Level = Microsoft.Extensions.Logging.LogLevel.Information,
            TimeStamp = DateTime.Now,
            Ip = context.Request.HttpContext.GetClientUserIp(),
            Header = $"{{Authorization:{context.Request.Headers["Authorization"]},Last_Working_Object_Id:{context.Request.Headers["Last_Working_Object_Id"]}}}",
            Host = context.Request.Host.ToString(),
            Url = context.Request.Path,
            QueryString = context.Request.QueryString.ToString(),
            RequestBody = requestBody,
            ResponseBody = responseBody,
            StartTime = start,
            EndTime = end,
            ElapsedTime = elapsed,
            Message = "",
            Exception = exception?.ToString() ?? "",
            RequestId = context.Request.HttpContext.TraceIdentifier
        };

        await _apiLog.HttpRequest(entry);
    }
}
2、记录日志
public class OuterApiLogger : IOuterApiLogger
{
    private readonly ILogger<OuterApiLogger> _logger;
    private readonly IWebHostEnvironment _environment;
    private readonly IProOuterApiLogDAL _dal;//这个是DAL层,方便写sql
    private readonly IHttpContextAccessor _httpContextAccessor;

    public OuterApiLogger(ILogger<OuterApiLogger> logger, IWebHostEnvironment environment, IProOuterApiLogDAL dal, IHttpContextAccessor httpContextAccessor)
    {
        _logger = logger;
        _environment = environment;
        _dal = dal;
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task HttpRequest(ProOuterApiLog entry)
    {
        await Insert(entry);
    }

    public async Task Information(string message)
    {
        await Insert(new ProOuterApiLog
        {
            Level = LogLevel.Information,
            Message = message,
        });
    }

    public async Task Warning(string message)
    {
        await Insert(new ProOuterApiLog
        {
            Level = LogLevel.Warning,
            Message = message,
        });
    }

    public async Task Error(string message, Exception exception = null)
    {
        await Insert(new ProOuterApiLog
        {
            Level = LogLevel.Error,
            Message = message,
            Exception = exception?.ToString()
        });
    }

    public async Task Critical(string message)
    {
        await Insert(new ProOuterApiLog
        {
            Level = LogLevel.Critical,
            Message = message,
        });
    }

    private async Task Insert(ProOuterApiLog entry)
    {

        var request = _httpContextAccessor.HttpContext?.Request;

        var parameters = new List<SugarParameter>
        {
            new SugarParameter("@level",entry.Level),
            new SugarParameter("@timestamp",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff")),
            new SugarParameter("@ip",entry.Ip ?? request.HttpContext.GetClientUserIp() ?? string.Empty),
            new SugarParameter("@header",entry.Header ?? string.Empty),
            new SugarParameter("@host",entry.Host ?? request.Host.ToString()?? string.Empty),
            new SugarParameter("@url",entry.Url ?? request?.Path?? string.Empty),
            new SugarParameter("@querystring",entry.QueryString ?? request?.QueryString.ToString() ?? string.Empty),
            new SugarParameter("@requestbody",entry.RequestBody ?? string.Empty),
            new SugarParameter("@responsebody",entry.ResponseBody ?? string.Empty),
            new SugarParameter("@starttime",entry.StartTime.ToString("yyyy-MM-dd HH:mm:ss.fffffff")),
            new SugarParameter("@endtime",entry.EndTime.ToString("yyyy-MM-dd HH:mm:ss.fffffff")),
            new SugarParameter("@elapsedtime",entry.ElapsedTime),
            new SugarParameter("@message",entry.Message ?? string.Empty),
            new SugarParameter("@exception",entry.Exception?.ToString() ?? string.Empty),
            new SugarParameter("@requestid",_httpContextAccessor.HttpContext.TraceIdentifier ?? string.Empty)
        };

        try
        {   
            await _dal.ExecuteBySql("INSERT INTO pro_outer_api_log (level,timestamp,ip,header,host,url,querystring,requestbody,responsebody,starttime,endtime,elapsedtime,message,exception,requestid) VALUES(@level,CAST(@timestamp AS timestamp(6)),@ip,@header,@host,@url,@querystring,@requestbody,@responsebody,CAST(@starttime AS timestamp(6)),CAST(@endtime AS timestamp(6)),@elapsedtime,@message,@exception,@requestid)", parameters.ToArray());
        }
        catch (Exception e)
        {
            _logger.LogError(e, "记录日志异常");
        }
    }
}
3、日志表
public class ProOuterApiLog : BaseEntity
{
    /// <summary>
    ///     日志等级
    /// </summary>
    [Column(Description = "日志等级", DataType = PGDataType.VARCHAR)]
    public LogLevel Level { get; set; }
    /// <summary>
    ///     记录时间
    /// </summary>
    [Column(Description = "记录时间")]
    public DateTime TimeStamp { get; set; }
    /// <summary>
    ///     请求IP地址
    /// </summary>
    [Column(Description = "请求IP地址")]
    public string Ip { get; set; }
    /// <summary>
    ///     请求头
    /// </summary>
    [Column(Description = "请求头")]
    public string Header { get; set; }
    /// <summary>
    ///     请求主机
    /// </summary>
    [Column(Description = "请求主机")]
    public string Host { get; set; }
    /// <summary>
    ///     请求地址
    /// </summary>
    [Column(Description = "请求地址")]
    public string Url { get; set; }
    /// <summary>
    ///     查询参数
    /// </summary>
    [Column(Description = "查询参数")]
    public string QueryString { get; set; }
    /// <summary>
    ///     请求主体
    /// </summary>
    [Column(Description = "请求主体")]
    public string RequestBody { get; set; }
    /// <summary>
    ///     响应主体
    /// </summary>
    [Column(Description = "响应主体")]
    public string ResponseBody { get; set; }
    /// <summary>
    ///     开始时间
    /// </summary>
    [Column(Description = "开始时间")]
    public DateTime StartTime { get; set; }
    /// <summary>
    ///     结束时间
    /// </summary>
    [Column(Description = "结束时间")]
    public DateTime EndTime { get; set; }
    /// <summary>
    ///     请求消耗时间,单位:毫秒
    /// </summary>
    [Column(Description = "请求消耗时间,单位:毫秒")]
    public long ElapsedTime { get; set; }
    /// <summary>
    ///     消息
    /// </summary>
    [Column(Description = "消息")]
    public string Message { get; set; }
    /// <summary>
    ///     异常
    /// </summary>
    [Column(Description = "异常")]
    public string Exception { get; set; }
    /// <summary>
    ///     请求ID
    /// </summary>
    [Column(Description = "请求ID")]
    public string RequestId { get; set; }
}


/// <summary>
/// 实体基类
/// </summary>
public class BaseEntity
{
    #region 构造函数
    /// <summary>
    /// 构造函数
    /// </summary>
    public BaseEntity()
    {
    }
    #endregion

    #region 属性
    /// <summary>
    /// ID
    /// </summary>
    [Column(IsIdentity = true, Description = "主键Id", Sort = -100)]
    public string Id { get; set; }
    /// <summary>
    /// 创建人ID
    /// </summary>
    [Column(Description = "创建人ID", Sort = 100)]
    [SugarColumn(IsOnlyIgnoreUpdate = true)]
    public string Create_UserId { get; set; }
    /// <summary>
    /// 修改人ID
    /// </summary>
    [Column(Description = "修改人ID", Sort = 101)]
    [SugarColumn(IsOnlyIgnoreInsert = true)]
    public string Modify_UserId { get; set; }
    /// <summary>
    /// 创建人
    /// </summary>
    [Column(Description = "创建人", Sort = 102)]
    [SugarColumn(IsOnlyIgnoreUpdate = true)]
    public string Create_UserName { get; set; }
    /// <summary>
    /// 修改人
    /// </summary>
    [Column(Description = "修改人", Sort = 103)]
    [SugarColumn(IsOnlyIgnoreInsert = true)]
    public string Modify_UserName { get; set; }
    /// <summary>
    /// 创建日期
    /// </summary>
    [Column(Description = "创建日期", IsNullable = true, Sort = 104)]
    [SugarColumn(IsOnlyIgnoreUpdate = true)]
    public DateTime? Create_Date { get; set; }
    /// <summary>
    /// 修改日期
    /// </summary>
    [Column(Description = "修改日期", IsNullable = true, Sort = 105)]
    [SugarColumn(IsOnlyIgnoreInsert = true)]
    public DateTime? Modify_Date { get; set; }
    /// <summary>
    /// 是否删除
    /// </summary>
    [Column(Description = "是否删除", Sort = 106)]
    public bool Is_Deleted { get; set; } = false;
    /// <summary>
    /// 自增ID,排序使用
    /// </summary>
    [Column(Description = "自增ID,排序使用", Sort = 107, DataType = PGDataType.SERIAL)]
    public long AutoIncrm_Id { get; set; }
    #endregion
}
posted on 2023-05-22 17:19  Jeffrey~~  阅读(101)  评论(0)    收藏  举报