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
}
标签:调用,string,get,Column,接口,set,new,日志,public
From: https://www.cnblogs.com/eaknow/p/17421213.html