.NET Core 内置了标准化日志框架和全局异常处理机制,无需第三方库即可实现生产级日志记录、异常捕获与处理。下面从基础配置、日志使用、异常处理、最佳实践四个维度,给你最实用的落地方案。
一、核心概念
- 日志:记录程序运行状态、请求信息、错误详情,用于排查问题、监控系统;
- 异常管理:统一捕获程序未处理的错误,避免程序崩溃,返回友好的错误响应;
- .NET Core 原生支持:
ILogger日志接口 + 中间件/过滤器 异常处理。
二、日志配置(原生日志,无需第三方包)
1. 基础配置(Program.cs,.NET 6+ 顶级语句)
.NET Core 默认集成日志,只需在配置文件定义日志级别、输出渠道。
var builder = WebApplication.CreateBuilder(args);
// 1. 配置日志(默认已集成,可自定义扩展)
builder.Logging.ClearProviders(); // 清空默认日志提供者
builder.Logging.AddConsole(); // 输出到控制台
builder.Logging.AddDebug(); // 输出到调试窗口
// 可选:添加文件日志(需安装第三方包,文末推荐)
// builder.Logging.AddFile("Logs/myapp-{Date}.txt");
// 2. 配置日志级别(appsettings.json 优先级更高)
builder.Logging.SetMinimumLevel(LogLevel.Information);
// 添加控制器
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.Run();
2. 配置文件(appsettings.json)
统一管理日志级别,区分环境、区分组件:
{
"Logging": {
"LogLevel": {
"Default": "Information", // 默认级别
"Microsoft.AspNetCore": "Warning", // 系统框架日志只记录警告及以上
"MyApp.Controllers": "Debug" // 自定义命名空间日志级别
}
}
}
日志级别(从低到高):
Trace < Debug < Information < Warning < Error < Critical
3. 日志使用(依赖注入 ILogger)
在控制器/服务中直接注入 ILogger<T>,无需手动实例化:
using Microsoft.AspNetCore.Mvc;
namespace MyApp.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class TestController : ControllerBase
{
// 注入日志对象(泛型指定当前类,自动标记日志来源)
private readonly ILogger<TestController> _logger;
public TestController(ILogger<TestController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
try
{
// 记录普通日志
_logger.LogInformation("接口 /api/test 被调用");
_logger.LogDebug("调试信息:参数为空");
// 模拟异常
throw new Exception("测试业务异常");
return Ok("成功");
}
catch (Exception ex)
{
// 记录异常日志(自带堆栈信息)
_logger.LogError(ex, "接口执行失败:{Message}", ex.Message);
return StatusCode(500, "服务器内部错误");
}
}
}
}
三、异常管理(全局统一处理,推荐)
不推荐在每个接口写 try-catch,全局异常中间件是最佳实践:统一捕获所有未处理异常,返回标准化响应。
1. 自定义全局异常中间件
创建 ExceptionMiddleware.cs:
using Microsoft.AspNetCore.Http;
using System.Net;
using System.Text.Json;
namespace MyApp.Middlewares
{
// 全局异常中间件
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionMiddleware> _logger;
public ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
// 核心处理方法
public async Task InvokeAsync(HttpContext context)
{
try
{
// 调用后续中间件/接口
await _next(context);
}
catch (Exception ex)
{
// 1. 记录异常日志(关键:堆栈、请求路径、时间)
_logger.LogError(ex, "全局异常捕获 | 请求路径:{Path} | 异常信息:{Message}",
context.Request.Path, ex.Message);
// 2. 统一处理异常响应
await HandleExceptionAsync(context, ex);
}
}
// 标准化错误响应
private Task HandleExceptionAsync(HttpContext context, Exception ex)
{
// 设置响应类型和状态码
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
// 生产环境隐藏敏感堆栈,开发环境返回完整信息
var errorResponse = new
{
Code = context.Response.StatusCode,
Message = ex.Message,
// 开发环境开启堆栈,生产环境注释
StackTrace = ex.StackTrace
};
// 序列化返回JSON
return context.Response.WriteAsync(JsonSerializer.Serialize(errorResponse));
}
}
}
2. 注册中间件(Program.cs)
必须放在所有中间件最前面,才能捕获所有异常:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Logging.AddConsole();
var app = builder.Build();
// 注册全局异常中间件(第一行!)
app.UseMiddleware<ExceptionMiddleware>();
app.UseHttpsRedirection();
app.UseRouting();
app.MapControllers();
app.Run();
3. 进阶:自定义业务异常
区分系统异常和业务异常,返回不同状态码:
// 自定义业务异常类
public class BusinessException : Exception
{
public int Code { get; set; }
public BusinessException(string message, int code = 400) : base(message)
{
Code = code;
}
}
// 中间件中适配自定义异常
private Task HandleExceptionAsync(HttpContext context, Exception ex)
{
context.Response.ContentType = "application/json";
// 业务异常返回400,系统异常返回500
if (ex is BusinessException busEx)
{
context.Response.StatusCode = busEx.Code;
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
}
// ... 省略响应代码
}
四、生产级增强(第三方日志库)
原生日志仅支持控制台/调试输出,Serilog 是 .NET Core 最流行的日志库,支持文件、数据库、ELK 等持久化存储。
Serilog 快速集成
- 安装 NuGet 包:
Install-Package Serilog.AspNetCore
Install-Package Serilog.Sinks.File
- Program.cs 配置:
using Serilog;
// 初始化日志(程序启动前配置)
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogLevel.Warning)
.Enrich.FromLogContext()
// 按天生成日志文件,自动滚动清理
.WriteTo.File("Logs/log-.txt", rollingInterval: RollingInterval.Day)
.WriteTo.Console()
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
// 替换原生日志为 Serilog
builder.Host.UseSerilog();
try
{
builder.Services.AddControllers();
var app = builder.Build();
app.UseMiddleware<ExceptionMiddleware>();
app.MapControllers();
app.Run();
}
catch (Exception ex)
{
// 捕获程序启动异常
Log.Fatal(ex, "程序启动失败");
}
finally
{
Log.CloseAndFlush(); // 确保日志写入完成
}
五、最佳实践总结
日志规范
- 禁止使用
Console.WriteLine(),必须用ILogger; - 敏感信息(密码、身份证)绝不记录;
- 关键业务(登录、支付、订单)必须记录
Information日志; - 异常必须记录
LogError(ex, "描述"),保留堆栈信息。
异常规范
- 全局唯一异常处理,不分散
try-catch; - 业务异常用自定义异常类,系统异常统一捕获;
- 生产环境不返回堆栈信息,只返回友好提示;
- 所有异常必须记录日志,方便排查。
总结
- 日志:依赖注入
ILogger<T>,配置文件控制级别,Serilog 实现持久化; - 异常:全局异常中间件统一捕获,自定义业务异常区分错误类型;
- 这套方案是 .NET Core 官方推荐的生产级标准方案,简单、稳定、易维护。