.NET Core使用log4Net日志框架

目录

 一. 日志的基本使用

1.  安装NuGet包 Microsoft.Extensions.Logging.Log4Net.AspNetCore 和 log4ne

 2.  在program.cs中开启日志

3, 添加日志配置文件log4Net.config

4.添加全局异常日志

二. 更详细的日志设计

1. 创建实体类

2. 使用EF Core生成数据表

3.实现Service层

4. 创建方法过滤器

5.全局动态添加方法过滤器 


 一. 日志的基本使用

1.  安装NuGet包 Microsoft.Extensions.Logging.Log4Net.AspNetCore 和 log4ne

 2.  在program.cs中开启日志

//开启日志
builder.Logging.AddLog4Net();

3, 添加日志配置文件log4Net.config

<?xml version="1.0" encoding="utf-8" ?>
<log4net>
	<appender name="DebugAppender" type="log4net.Appender.DebugAppender" >
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
		</layout>
	</appender>
	<!--指定日记记录方式,以滚动文件的方式(文件记录)-->
	<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
		<!--日志路径-->
		<file value="log\" />
		<!--是否是向文件中追加日志-->
		<appendToFile value="true" />
		<!--log保留天数-->
		<param name= "MaxSizeRollBackups" value= "10"/>
		<!--每个文件最大3M-->
		<param name="maximumFileSize" value="3MB" />
		<!--日志根据日期滚动-->
		<param name="RollingStyle" value="Date" />
		<!--日志文件名格式为:logs_20230431.log-->
		<param name="DatePattern" value="&quot;logs_&quot;yyyyMMdd&quot;.log&quot;" />
		<!--日志文件名是否是固定不变的-->
		<param name="StaticLogFileName" value="false" />
		<!--布局-->
		<layout type="log4net.Layout.PatternLayout">
			<conversionPattern value="%date %5level %logger.%method [%line] - MESSAGE: %message%newline %exception" />
		</layout>
	</appender>
	<root>
		<level value="ALL"/>
		<appender-ref ref="DebugAppender" />
		<appender-ref ref="RollingFile" />
	</root>
</log4net>

4.添加全局异常日志

/// <summary>
/// 异常过滤器,全局捕获异常
/// </summary>
public class ClubExceptionFilterAttribute : ExceptionFilterAttribute
{
    private readonly ILogger<ClubExceptionFilterAttribute> _logger;

    public ClubExceptionFilterAttribute(ILogger<ClubExceptionFilterAttribute> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 异常处理,存在未处理的异常时,返回500错误
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(ExceptionContext context)
    {
        // 如果异常没有被处理,则进行处理
        if (context.ExceptionHandled == false)
        {
            // 记录异常信息
            var str = $"异常: {context.HttpContext.Request.Path} {context.Exception.Message}";
            // 记录日志
            _logger.LogWarning(str);
            context.Result = new ContentResult
            {
                StatusCode = StatusCodes.Status500InternalServerError,
                Content = "服务器异常,请联系管理员"
            };
            // 标记异常已处理
            context.ExceptionHandled = true;
        }
    }
}

此时我们运行项目,简单的日志文件就生成了

二. 更详细的日志设计

        在项目中,一般为了方便维护,简单的日志是难以达到要求的,此时我们就需要更加具体的日志来完成项目的监护.我这里选择将日志信息保存到数据库

1. 创建实体类

 public class ClubLogs
 {
     public long Id { get; set; }

     /// <summary>
     /// 操作人Id
     /// </summary>
     /// <summary>
     /// 请求方式
     /// </summary>
     [Comment("接口的方法")]
     public string Method { get; set; } = string.Empty;
     /// <summary>
     /// 请求参数
     /// </summary>
     [Comment("请求参数")]
     public string Parameters { get; set; } = string.Empty;
      ....
      ....
      ....
     /// <summary>
     /// 返回值
     /// </summary>
     [Comment("返回值")]
     public string ReturnValue { get; set; } = string.Empty;
 }

2. 使用EF Core生成数据表

这个步骤就不展示了,比较简单

3.实现Service层

1. 首先添加服务接口

public interface IClubLogService
{
    /// <summary>
    /// 添加审核日志
    /// </summary>
    /// <param name="clubLogs"></param>
    /// <returns></returns>
    ClubLogs Add(ClubLogs clubLogs);
}

2. 实现接口

public class ClubLogService : BaseService, IClubLogService
{
   private readonly IBaseRepository<ClubLogs> _clubLogRepository;
   private readonly ILogger<ClubLogService> _logger;

    public ClubLogService(IBaseRepository<ClubLogs> clubLogRepository, ILogger<ClubLogService> logger)
    {
        _clubLogRepository = clubLogRepository;
        _logger = logger;
    }

    public ClubLogs Add(ClubLogs clubLogs)
    {
        try
        {
            return _clubLogRepository.Add(clubLogs);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "保存日志数据库异常,接口: {0}\r\nMethod: {1}\r\n参数: {2}\r\nIP: {3}\r\n花费时间: {4}ms",
                clubLogs.ApiUrl, clubLogs.Method, clubLogs.Parameters, clubLogs.ClientIpAddress, clubLogs.ExecutionTime);
            return clubLogs;
        }
    }
}

4. 创建方法过滤器

方法过滤器主要用于在方法执行前和方法执行后保存相关日志记录

1. 写一个方法用于获取需要保存的日志信息

public class ClubLogHelper
{
    public static ClubLogs RequestLogs(ActionContext action, UserManager<User> userManager)
    {
        ClubLogs logs = new ClubLogs();
        var httpContext = action.HttpContext;
        var request = httpContext.Request;// 请求对象

        //当前用户
        var userName = httpContext.User.Identity.Name;
        if (!string.IsNullOrEmpty(userName))
        {
            var user = userManager.FindByNameAsync(userName).Result;
            logs.CreateId = user.Id;
        }
        logs.ApiUrl = request.Path; // 请求路径
        logs.Method = request.Method; // 请求方法
        logs.AuditLogType = AuditLogType.Info; // 日志类型

        var remoteIpAddress = httpContext.Connection.RemoteIpAddress; // 获取客户端IP地址
        // 映射为IPv4地址
        logs.ClientIpAddress = remoteIpAddress == null ? string.Empty : remoteIpAddress.MapToIPv4().ToString();
        // 获取浏览器信息
        logs.BrowserInfo = request.Headers.ContainsKey("User-Agent") ? request.Headers["User-Agent"].ToString() : string.Empty;
        
        //获取参数
        if (request.Method == "GET")
        {
            logs.Parameters = request.QueryString.Value ?? string.Empty;
        }
        else
        {
            // 获取请求体
            using (StreamReader reader = new StreamReader(request.Body))
            {
                request.Body.Position = 0; //保持从头开始读取
                logs.Parameters = reader.ReadToEndAsync().Result; // 读取所以请求体内容
                request.Body.Position = 0; // 重置请求体位置
            }
        }

        return logs;
    }
}

2. 允许body被重复访问

这里有个问题是Request.Body默认是不允许重复读取的,因此我们要在program.cs中允许body重复读取.

//允许body重复用
app.Use(next => context =>
{
    context.Request.EnableBuffering();
    return next(context);
});

3. 创建方法过滤器

/// <summary>
/// 方法过滤器
/// </summary>
public class ClubLogActionFilterAttribute :  ActionFilterAttribute
{
    private ClubLogs _clubLogs;
    private readonly IClubLogService _clubLogService;
    private readonly UserManager<User> _userManager;
    private readonly ILogger<ClubLogActionFilterAttribute> _logger;

    private DateTime _executionBefore;
    private DateTime _executionAfter;

    public ClubLogActionFilterAttribute(IClubLogService clubLogService, UserManager<User> userManager, ILogger<ClubLogActionFilterAttribute> logger)
    {
        _clubLogs = new ClubLogs();
        _clubLogService = clubLogService;
        _userManager = userManager;
        _logger = logger;
    }

    /// <summary>
    /// 方法执行前
    /// </summary>
    /// <param name="context"></param>
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        _executionBefore = DateTime.Now;
        _clubLogs = ClubLogHelper.RequestLogs(context, _userManager);
    }

    /// <summary>
    /// 方法执行完毕
    /// </summary>
    /// <param name="context"></param>
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        _executionAfter = DateTime.Now;
        // 方法执行时间
        _clubLogs.ExecutionTime = (int)(_executionAfter - _executionBefore).TotalMilliseconds;
        // 序列化返回值为JSON字符串
        _clubLogs.ReturnValue = context.Result == null ? string.Empty : JsonConvert.SerializeObject(context.Result);

        // 异常信息
        if (context.Exception != null)
        {
            // 记录异常信息
            _clubLogs.ExceptionMessage = context.Exception.Message;
            if (_clubLogs.ExceptionMessage.Length > 1024)
            {
                _clubLogs.ExceptionMessage = _clubLogs.ExceptionMessage.Substring(0, 1024);
            }

            _clubLogs.Exception = context.Exception.ToString();
            if (_clubLogs.Exception.Length > 2000)
            {
                _clubLogs.Exception = _clubLogs.Exception.Substring(0, 2000);
            }
            _clubLogs.AuditLogType = AuditLogType.Exception;

            // 记录文件异常日志
            _logger.LogError(context.Exception, "保存日志数据库异常,接口: {0}\r\nMethod: {1}\r\n参数: {2}\r\nIP: {3}\r\n花费时间: {4}ms",
                _clubLogs.ApiUrl, _clubLogs.Method, _clubLogs.Parameters, _clubLogs.ClientIpAddress, _clubLogs.ExecutionTime);
        }

        _clubLogService.Add(_clubLogs);
    }
}

5.全局动态添加方法过滤器

builder.Services.AddControllers(
    configure =>
    {
        // 全局为控制器添加日志
        configure.Filters.Add<ClubLogActionFilterAttribute>();
    })

最后,这个日志功能就成功实现了

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.net开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值