ASP.NET Core使用log4net的详细流程
在 ASP.NET Core 中,最佳实践是通过 Microsoft.Extensions.Logging 抽象层集成 log4net,从而利用依赖注入(DI)和统一日志接口。
一、安装 NuGet 包
你需要安装两个包:log4net 核心库和 ASP.NET Core 的适配包。
c#
Install-Package log4net
Install-Package Microsoft.Extensions.Logging.Log4Net.AspNetCore
// 根据你的数据库类型选择对应的驱动
// SQL Server
dotnet add package System.Data.SqlClient
//或者 SQL Server
dotnet add package Microsoft.Data.SqlClient
二、创建配置文件
2.1、日志写入本地文件
在项目根目录创建 log4net.config 文件,并将属性设置为 "复制到输出目录: 如果较新则复制"。
xml
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<!-- 定义滚动日志文件追加器 -->
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 日志文件路径 -->
<file value="Logs/rbac-.log" />
<!-- 是否追加到现有文件 -->
<appendToFile value="true" />
<!-- 滚动方式:按日期 -->
<rollingStyle value="Date" />
<!-- 日期格式 -->
<datePattern value="yyyyMMdd'.log'" />
<!-- 最多保留30个备份文件 -->
<maxSizeRollBackups value="30" />
<!-- 每个文件最大10MB -->
<maximumFileSize value="10MB" />
<!-- 静态文件名,为false则动态生成 -->
<staticLogFileName value="false" />
<!-- 日志布局格式 -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
<!-- 编码格式 -->
<encoding value="utf-8" />
</appender>
<!-- 定义控制台追加器 -->
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<!-- 根日志配置 -->
<root>
<!-- 日志级别:INFO及以上 -->
<level value="INFO" />
<!-- 引用追加器 -->
<appender-ref ref="RollingFileAppender" />
<appender-ref ref="ConsoleAppender" />
</root>
<!-- 操作日志记录器 -->
<logger name="OperationLog">
<level value="INFO" />
<appender-ref ref="RollingFileAppender" />
</logger>
</log4net>
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="logs/app.log" />
<appendToFile value="true" />
<rollingStyle value="Date" />
<datePattern value="yyyyMMdd'.log'" />
<staticLogFileName value="false" />
<maxSizeRollBackups value="10" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
</appender>
<root>
<level value="Info" />
<appender-ref ref="ConsoleAppender" />
<appender-ref ref="RollingFileAppender" />
</root>
</log4net>
2.2、日志写入SQL Server
创建数据库表
在您的数据库中创建一个用于存储日志的表。表结构应至少包含时间、日志级别、消息等基本信息,也可以根据需要添加自定义字段(如用户ID、IP地址等)。
sql
CREATE TABLE ProgramLog (
Id int IDENTITY(1,1) PRIMARY KEY,
Date datetime NOT NULL,
Thread nvarchar(255) NOT NULL,
Level nvarchar(50) NOT NULL,
Logger nvarchar(255) NOT NULL,
Message nvarchar(max) NOT NULL,
Exception nvarchar(max),
UserId nvarchar(100), -- 自定义字段示例
IpAddress nvarchar(45) -- 自定义字段示例
);
配置Log4Net (通常在 log4net.config 文件中)
- 定义一个
AdoNetAppender。 - 设置
connectionString为您的数据库连接字符串。 - 设置
commandText为您插入日志的SQL语句(通常是INSERT INTO ... VALUES (...))。 - 使用
<mapping>元素将SQL参数(如@log_date,@log_message)映射到Log4Net事件的属性(如%date,%message)。
xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<!-- AdoNetAppender 配置 -->
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<!-- 数据库连接字符串 -->
<connectionString value="Server=your_server;Database=your_db;Trusted_Connection=true;" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data.SqlClient" />
<!-- SQL 插入命令 -->
<commandText value="INSERT INTO ProgramLog (Date, Thread, Level, Logger, Message, Exception, UserId, IpAddress) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @user_id, @ip_address)" />
<!-- 参数映射 -->
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy-MM-dd HH:mm:ss.fff}" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%thread" />
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" value="%level" />
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%logger" />
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%message" />
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
<!-- 自定义字段映射示例 -->
<parameter>
<parameterName value="@user_id" />
<dbType value="String" />
<size value="100" />
<layout type="log4net.Layout.PatternLayout" value="%property{UserId}" />
</parameter>
<parameter>
<parameterName value="@ip_address" />
<dbType value="String" />
<size value="45" />
<layout type="log4net.Layout.PatternLayout" value="%property{IpAddress}" />
</parameter>
</appender>
<!-- Root Logger 配置 -->
<root>
<level value="DEBUG" />
<appender-ref ref="AdoNetAppender" />
</root>
</log4net>
</configuration>
2.3、日志同时写入SQL Server和本地文件
xml
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<!-- 定义滚动日志文件追加器 -->
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<!-- 日志文件路径 -->
<file value="Logs/rbac-.log" />
<!-- 是否追加到现有文件 -->
<appendToFile value="true" />
<!-- 滚动方式:按日期 -->
<rollingStyle value="Date" />
<!-- 日期格式 -->
<datePattern value="yyyyMMdd'.log'" />
<!-- 最多保留30个备份文件 -->
<maxSizeRollBackups value="30" />
<!-- 每个文件最大10MB -->
<maximumFileSize value="10MB" />
<!-- 静态文件名,为false则动态生成 -->
<staticLogFileName value="false" />
<!-- 日志布局格式 -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
</layout>
<!-- 编码格式 -->
<encoding value="utf-8" />
</appender>
<!-- AdoNetAppender 配置 -->
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<!-- 1. 指定数据库驱动类型 -->
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data.SqlClient" />
<!-- 2. 数据库连接字符串 -->
<connectionString value="Server=HC-PC\HC;Database=FMS_Db;User ID=sa;Password=68501507;integrated security=false;persist security info=True;Trusted_Connection=true;" />
<!-- 3. 命令缓冲区大小(可选,提高性能) -->
<bufferSize value="100" />
<!-- SQL 插入命令 -->
<commandText value="INSERT INTO ProgramLog (Date, Thread, Level, Logger, Message, Exception, UserId, IpAddress) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @user_id, @ip_address)" />
<!-- 参数映射 -->
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy-MM-dd HH:mm:ss.fff}" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%thread" />
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout" value="%level" />
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout" value="%logger" />
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout" value="%message" />
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
<!-- 自定义字段映射示例 -->
<parameter>
<parameterName value="@user_id" />
<dbType value="String" />
<size value="100" />
<layout type="log4net.Layout.PatternLayout" value="%property{UserId}" />
</parameter>
<parameter>
<parameterName value="@ip_address" />
<dbType value="String" />
<size value="45" />
<layout type="log4net.Layout.PatternLayout" value="%property{IpAddress}" />
</parameter>
</appender>
<!-- 根日志配置 -->
<root>
<!-- 日志级别:INFO及以上 -->
<level value="INFO" />
<!-- 引用追加器 -->
<appender-ref ref="RollingFileAppender" />
<appender-ref ref="AdoNetAppender" />
</root>
<!-- 操作日志记录器 -->
<logger name="OperationLog">
<level value="INFO" />
<appender-ref ref="RollingFileAppender" />
</logger>
</log4net>
三、在 Program.cs 中注册
在 Program.cs 中,使用 AddLog4Net扩展方法将 log4net 添加到日志构建器中。
csharp
// 1. 清除默认的日志提供者(可选,如果你只想用 Log4Net)
builder.Logging.ClearProviders();
// 2. 添加 Log4Net
// 方法 A: 使用扩展方法自动读取 log4net.config (推荐)
// 注意:确保 log4net.config 文件存在于项目根目录并已设置为复制
builder.Logging.AddLog4Net("log4net.config");
// 或者明确指定配置文件地址
//builder.Logging.AddLog4Net(Path.Combine(Directory.GetCurrentDirectory(), "log4net.config"));
// 其他服务注册...
builder.Services.AddControllers();
var app = builder.Build();
// 中间件配置...
app.MapControllers();
app.Run();
四、在控制器中使用
通过构造函数注入 ILogger 即可使用,无需直接引用 log4net 的 API。
csharp
[Authorize(Policy = "AdminOnly")]
public class GatewayController : LayuiApiController
{
private readonly IGatewayRepository _gatewayRepository;
/// <summary>
/// 日志记录器,用于记录告警相关的操作日志和错误日志
/// </summary>
private readonly ILogger<GatewayController> _logger;
public GatewayController(IGatewayRepository gatewayRepository, ILogger<GatewayController> logger)
{
_gatewayRepository = gatewayRepository;
_logger = logger;
}
/// <summary>
/// 网关主页
/// </summary>
/// <returns></returns>
public IActionResult GatewayIndex()
{
ViewData["Title"] = "网关管理";
return View();
}
/// <summary>
/// 获取所有网关列表(支持分页)
/// </summary>
/// <param name="page">页码</param>
/// <param name="limit">每页数量</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> GatewayList(int page = 1, int limit = 10)
{
try
{
var gateways = await _gatewayRepository.GetAllGatewaysAsync();
var total = gateways.Count();
var pagedData = gateways.Skip((page - 1) * limit).Take(limit).ToList();
return SuccessResult(data: pagedData, count: total);
}
catch (Exception ex)
{
_logger.LogError(ex, "GatewayList的方法,获取网关列表失败");
return ErrorResult($"获取网关列表失败:{ex.Message}");
}
}
}
}