NET CORE 5.0 全局日志的书写
第一步 创建.NET CORE项目
第二步 项目依赖项下安装neget包 log4net
dotnet add package log4net
第三步 创建log4net.config文件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
</configSections>
<log4net>
<!-- 将日志以回滚文件的形式写到文件中 -->
<!-- 按日期切分日志文件,并将日期作为日志文件的名字 -->
<appender name="RollingFileAppenderNameByDate" type="log4net.Appender.RollingFileAppender">
<!-- 日志文件存放位置,可以为绝对路径也可以为相对路径 -->
<file value="D:\Common.API\Logs\" />
<!-- 将日志信息追加到已有的日志文件中-->
<appendToFile value="true" />
<!-- 最小锁定模式,以允许多个进程可以写入同一个文件 -->
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
<!-- 指定按日期切分日志文件 -->
<rollingStyle value="Date" />
<!-- 日志文件的命名规则 -->
<datePattern value=""UtilLogs_"yyyyMMdd".log"" />
<!-- 当将日期作为日志文件的名字时,必须将staticLogFileName的值设置为false -->
<staticLogFileName value="false" />
<!-- 日志显示模板 -->
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="【异常时间】:%date %newline%message%newline--------------------------------------------------------------------%newline" />
</layout>
</appender>
<root>
<!-- 控制级别,由低到高:ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF -->
<!-- 比如定义级别为INFO,则INFO级别向下的级别,比如DEBUG日志将不会被记录 -->
<!-- 如果没有定义LEVEL的值,则缺省为DEBUG -->
<level value="ALL" />
<!-- 按日期切分日志文件,并将日期作为日志文件的名字 -->
<appender-ref ref="RollingFileAppenderNameByDate" />
</root>
</log4net>
</configuration>
第四步 创建AppSetting.cs类
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Common.API
{
public class AppSetting
{
private static readonly object objLock = new object();
private static AppSetting instance = null;
private IConfigurationRoot Config { get; }
private AppSetting()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
Config = builder.Build();
}
public static AppSetting GetInstance()
{
if (instance == null)
{
lock (objLock)
{
if (instance == null)
{
instance = new AppSetting();
}
}
}
return instance;
}
public static string GetConfig(string name)
{
return GetInstance().Config.GetSection(name).Value;
}
}
}
第五步 创建ILoggerHelper.cs接口类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Common.API.Log
{
public interface ILoggerHelper
{
/// <summary>
/// 调试信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Debug(object source, string message);
/// <summary>
/// 调试信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="ps">ps</param>
void Debug(object source, string message, params object[] ps);
/// <summary>
/// 调试信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Debug(Type source, string message);
/// <summary>
/// 关键信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Info(object source, object message);
/// <summary>
/// 关键信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Info(Type source, object message);
/// <summary>
/// 警告信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Warn(object source, object message);
/// <summary>
/// 警告信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Warn(Type source, object message);
/// <summary>
/// 错误信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Error(object source, object message);
/// <summary>
/// 错误信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Error(Type source, object message);
/// <summary>
/// 失败信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Fatal(object source, object message);
/// <summary>
/// 失败信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
void Fatal(Type source, object message);
/* Log a message object and exception */
/// <summary>
/// 调试信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Debug(object source, object message, Exception exception);
/// <summary>
/// 调试信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Debug(Type source, object message, Exception exception);
/// <summary>
/// 关键信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Info(object source, object message, Exception exception);
/// <summary>
/// 关键信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Info(Type source, object message, Exception exception);
/// <summary>
/// 警告信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Warn(object source, object message, Exception exception);
/// <summary>
/// 警告信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Warn(Type source, object message, Exception exception);
/// <summary>
/// 错误信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Error(object source, object message, Exception exception);
/// <summary>
/// 错误信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Error(Type source, object message, Exception exception);
/// <summary>
/// 失败信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Fatal(object source, object message, Exception exception);
/// <summary>
/// 失败信息
/// </summary>
/// <param name="source">source</param>
/// <param name="message">message</param>
/// <param name="exception">ex</param>
void Fatal(Type source, object message, Exception exception);
}
}
第六步 创建 ILoggerHelper.cs接口实现类LogerHelper.cs 并实现接口方法继承
using Common.API.Log;
using log4net;
using log4net.Config;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Common.API
{
public class LogHelper : ILoggerHelper
{
private readonly ConcurrentDictionary<Type, ILog> Loggers = new ConcurrentDictionary<Type, ILog>();
/// <summary>
/// 获取记录器
/// </summary>
/// <param name="source">soruce</param>
/// <returns></returns>
private ILog GetLogger(Type source)
{
if (Loggers.ContainsKey(source))
{
return Loggers[source];
}
else
{
ILog logger = LogManager.GetLogger(Startup.repository.Name, source);
Loggers.TryAdd(source, logger);
return logger;
}
}
public void Debug(object source, string message)
{
Debug(source.GetType(), message);
}
public void Debug(object source, string message, params object[] ps)
{
Debug(source.GetType(), string.Format(message, ps));
}
public void Debug(Type source, string message)
{
ILog logger = GetLogger(source);
if (logger.IsDebugEnabled)
{
logger.Debug(message);
}
}
public void Debug(object source, object message, Exception exception)
{
Debug(source.GetType(), message, exception);
}
public void Debug(Type source, object message, Exception exception)
{
GetLogger(source).Debug(message, exception);
}
public void Error(object source, object message)
{
Error(source.GetType(), message);
}
public void Error(Type source, object message)
{
ILog logger = GetLogger(source);
if (logger.IsErrorEnabled)
{
logger.Error(message);
}
}
public void Error(object source, object message, Exception exception)
{
Error(source.GetType(), message, exception);
}
public void Error(Type source, object message, Exception exception)
{
GetLogger(source).Error(message, exception);
}
public void Fatal(object source, object message)
{
Fatal(source.GetType(), message);
}
public void Fatal(Type source, object message)
{
ILog logger = GetLogger(source);
if (logger.IsFatalEnabled)
{
logger.Fatal(message);
}
}
public void Fatal(object source, object message, Exception exception)
{
Fatal(source.GetType(), message, exception);
}
public void Fatal(Type source, object message, Exception exception)
{
GetLogger(source).Fatal(message, exception);
}
public void Info(object source, object message)
{
Info(source.GetType(), message);
}
public void Info(Type source, object message)
{
ILog logger = GetLogger(source);
if (logger.IsInfoEnabled)
{
logger.Info(message);
}
}
public void Info(object source, object message, Exception exception)
{
Info(source.GetType(), message, exception);
}
public void Info(Type source, object message, Exception exception)
{
GetLogger(source).Info(message, exception);
}
public void Warn(object source, object message)
{
Warn(source.GetType(), message);
}
public void Warn(Type source, object message)
{
ILog logger = GetLogger(source);
if (logger.IsWarnEnabled)
{
logger.Warn(message);
}
}
public void Warn(object source, object message, Exception exception)
{
Warn(source.GetType(), message, exception);
}
public void Warn(Type source, object message, Exception exception)
{
GetLogger(source).Warn(message, exception);
}
}
}
第七步 创建全局异常类 GlobalExceptionFilter.cs
using Common.API.Log;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Common.API.Filte
{
public class GlobalExceptionFilter : IExceptionFilter
{
private readonly IHostingEnvironment _env;
private readonly ILoggerHelper _loggerHelper;
public GlobalExceptionFilter(IHostingEnvironment env, ILoggerHelper loggerHelper)
{
_env = env;
_loggerHelper = loggerHelper;
}
public void OnException(ExceptionContext context)
{
var json = new JsonErrorResponse();
json.Message = context.Exception.Message;//错误信息
if (_env.IsDevelopment())
{
json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息
}
context.Result = new InternalServerErrorObjectResult(json);
//采用log4net 进行错误日志记录
_loggerHelper.Error(json.Message, WriteLog(json.Message, context.Exception));
}
/// <summary>
/// 自定义返回格式
/// </summary>
/// <param name="throwMsg"></param>
/// <param name="ex"></param>
/// <returns></returns>
public string WriteLog(string throwMsg, Exception ex)
{
return string.Format("【自定义错误】:{0} \r\n【异常类型】:{1} \r\n【异常信息】:{2} \r\n【堆栈调用】:{3}", new object[] { throwMsg,
ex.GetType().Name, ex.Message, ex.StackTrace });
}
}
public class InternalServerErrorObjectResult : ObjectResult
{
public InternalServerErrorObjectResult(object value) : base(value)
{
StatusCode = StatusCodes.Status500InternalServerError;
}
}
//返回错误信息
public class JsonErrorResponse
{
/// <summary>
/// 生产环境的消息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 开发环境的消息
/// </summary>
public string DevelopmentMessage { get; set; }
}
}
第八步 路由注册 StarUp.cs
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Common.API
{
public class Startup
{
/// <summary>
/// log4net 仓储库
/// </summary>
public static ILoggerRepository repository { get; set; }
public Startup(IConfiguration configuration)
{
//log4net
repository = LogManager.CreateRepository("Common.API");//Common.API 为需要获取日志的仓库名,也就是你的当然项目名
//指定配置文件,如果这里你遇到问题,应该是使用了InProcess模式,请查看Blog.Core.csproj,并删之
XmlConfigurator.Configure(repository, new FileInfo("log4net.config"));//配置文件
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//注入日志的全局异常捕获
services.AddMvc(x =>
{
x.Filters.Add(typeof(GlobalExceptionFilter));
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
//log日志依赖注入
services.AddSingleton<ILoggerHelper, LogHelper>();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Common.API", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Common.API v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
第九步 判断结果 可在appsettings.json 内配置数据库连接字符串查看其异常结果 ,第三步内的 log4net.config文件可以修改日志的存放路径
异常记录
【异常时间】:2021-12-29 13:32:47,754
【自定义错误】:The ConnectionString property has not been initialized.
【异常类型】:InvalidOperationException
【异常信息】:The ConnectionString property has not been initialized.
【堆栈调用】: at System.Data.SqlClient.SqlConnection.PermissionDemand()
at System.Data.SqlClient.SqlConnectionFactory.PermissionDemand(DbConnection outerConnection)
at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions userOptions) at System.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at Common.API.SqlServer.SqlServerDBHelper.ExecuteNonQuery(String sql, String StringName) in D:\ComPany\ProjectFile\Exercise_Project\Common\Common.API\SqlServer\SqlServerDBHelper.cs:line 17
at Common.API.Controllers.WeatherForecastController.Sum(Int32 a, Int32 b) in D:\ComPany\ProjectFile\Exercise_Project\Common\Common.API\Controllers\WeatherForecastController.cs:line 46
at lambda_method3(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Logged|12_1(ControllerActionInvoker invoker)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
— End of stack trace from previous location —
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)