asp.net core添加全局异常处理及log4net、Nlog应用
0、目录
整体架构目录:ASP.NET Core分布式项目实战-目录
一、介绍
此篇文章将会介绍项目的全局异常收集以及采用log4net或者NLog记录。
众所周知,一旦自己的项目报错,如果没有进行处理都是显示不友好的,有得甚至直接爆出错误页面,看的也是很奇怪。
为了避免出现这样的错误以及在错误出现的时候可以进行收集错误,供维护人员进行bug修改,因此需要进行全局异常的收集。
让我们开始部署吧。
此篇文章的目录
1、log4net使用
2、Nlog使用
后期将会把NLog+ELK进行结合部署收集我们的asp.net core的项目。大家可以拭目以待吧。
二、部署(log4net使用)
1、新建一个asp.net core webapi的项目
然后目前我先引入 log4net nuget包。
2、然后创建一个log4net.config文件
此文件中,我创建了一个是记录 错误的文件夹(LogError)以及是记录操作的文件夹(LogInfo),代码如下:我把需要记录的文件放在了log文件夹下面。
<?xml version="1.0" encoding="utf-8"?> <configuration> <log4net> <!-- 错误日志类--> <logger name="logerror"> <level value="ALL" /> <appender-ref ref="ErrorAppender" /> </logger> <!-- 错误日志附加介质--> <appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"> <!--日志文件路径--> <param name="File" value="Log\\LogError\\" /> <!--是否是向文件中追加日志--> <param name="AppendToFile" value="true" /> <!--log保留天数--> <param name="MaxSizeRollBackups" value="1000" /> <!--最大文件大小--> <param name="MaxFileSize" value="10240" /> <!--日志文件名是否是固定不变的--> <param name="StaticLogFileName" value="false" /> <!--日志文件名格式为:2008-08-31.log--> <param name="DatePattern" value="yyyy-MM-dd".htm"" /> <!--日志根据日期滚动--> <param name="RollingStyle" value="Date" /> <!--信息日志布局--> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="<HR COLOR=red>%n【异常时间】:%d [%t] <BR>%n【异常级别】:%-5p <BR>%n%m <BR>%n <HR Size=1>" /> </layout> </appender> <!-- 信息日志类 --> <logger name="loginfo"> <level value="ALL" /> <appender-ref ref="InfoAppender" /> </logger> <!-- 信息日志附加介质--> <appender name="InfoAppender" type="log4net.Appender.RollingFileAppender"> <!--日志文件路径--> <param name="File" value="Log\\LogInfo\\" /> <!--是否是向文件中追加日志--> <param name="AppendToFile" value="true" /> <!--log保留天数--> <param name="MaxSizeRollBackups" value="100" /> <param name="MaxFileSize" value="1" /> <!--日志文件名是否是固定不变的--> <param name="StaticLogFileName" value="false" /> <!--日志文件名格式为:2008-08-31.log--> <param name="DatePattern" value="yyyy-MM-dd".htm"" /> <!--日志根据日期滚动--> <param name="RollingStyle" value="Date" /> <!--信息日志布局--> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="<HR COLOR=blue>%n日志时间:%d [%t] <BR>%n日志级别:%-5p <BR>%n%m <BR>%n <HR Size=1>" /> </layout> </appender> </log4net> <!-- To customize the asp.net core module uncomment and edit the following section. For more info see https://go.microsoft.com/fwlink/?linkid=838655 --> <!-- <system.webServer> <handlers> <remove name="aspNetCore"/> <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/> </handlers> <aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" /> </system.webServer> --> </configuration>
3、在asp.net core项目中 Startup.cs 中需要添加初始化log4net的仓储名,主要是用来给log4net标记一个名称,这边可以随意。
4、在项目中创建一个类用来记录log的日志格式以及数据分类存放
创建LogHelper.cs,
定义log格式,当然自己可以随意定义哈。
#region 全局异常错误记录持久化 /// <summary> /// 全局异常错误记录持久化 /// </summary> /// <param name="throwMsg"></param> /// <param name="ex"></param> public static void ErrorLog(string throwMsg, Exception ex) { string errorMsg = string.Format("【抛出信息】:{0} <br>【异常类型】:{1} <br>【异常信息】:{2} <br>【堆栈调用】:{3}", new object[] { throwMsg, ex.GetType().Name, ex.Message, ex.StackTrace }); errorMsg = errorMsg.Replace("\r\n", "<br>"); errorMsg = errorMsg.Replace("位置", "<strong style=\"color:red\">位置</strong>"); logerror.Error(errorMsg); } #endregion
#region 自定义操作记录 /// <summary> /// 自定义操作记录,与仓储中的增删改的日志是记录同一张表 /// </summary> /// <param name="throwMsg"></param> /// <param name="ex"></param> public static void WriteLog(string throwMsg, Exception ex) { string errorMsg = string.Format("【抛出信息】:{0} <br>【异常类型】:{1} <br>【异常信息】:{2} <br>【堆栈调用】:{3}", new object[] { throwMsg, ex.GetType().Name, ex.Message, ex.StackTrace }); errorMsg = errorMsg.Replace("\r\n", "<br>"); errorMsg = errorMsg.Replace("位置", "<strong style=\"color:red\">位置</strong>"); logerror.Error(errorMsg); } #endregion
5、有了以上的log格式,这样我就开始定义一下全局异常处理吧
我这边先创建一个全局异常处理类 GlobalExceptions.cs 然后需要在startup.cs中注入
在ConfigureServices 方法中注入。
//注入全局异常捕获 services.AddMvc(o => { o.Filters.Add(typeof(GlobalExceptions)); });
6、GlobalExceptions类中添加处理,当然异常需要继承IExceptionFilter。
代码如下:
GlobalExceptions
public class GlobalExceptions : IExceptionFilter { private readonly IHostingEnvironment _env; public GlobalExceptions(IHostingEnvironment env) { _env = env; } public void OnException(ExceptionContext context) { var json = new JsonErrorResponse(); //这里面是自定义的操作记录日志 if (context.Exception.GetType() == typeof(UserOperationException)) { json.Message = context.Exception.Message; if (_env.IsDevelopment()) { json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息 } context.Result = new BadRequestObjectResult(json);//返回异常数据 } else { json.Message = "发生了未知内部错误"; if (_env.IsDevelopment()) { json.DevelopmentMessage = context.Exception.StackTrace;//堆栈信息 } context.Result = new InternalServerErrorObjectResult(json); } //采用log4net 进行错误日志记录 LogHelper.ErrorLog(json.Message, context.Exception); } } public class InternalServerErrorObjectResult : ObjectResult { public InternalServerErrorObjectResult(object value) : base(value) { StatusCode = StatusCodes.Status500InternalServerError; } }
JsonErrorResponse.cs
public class JsonErrorResponse { /// <summary> /// 生产环境的消息 /// </summary> public string Message { get; set; } /// <summary> /// 开发环境的消息 /// </summary> public string DevelopmentMessage { get; set; } }
UserOperationException.cs
/// <summary> /// 操作日志 /// </summary> public class UserOperationException : Exception { public UserOperationException() { } public UserOperationException(string message) : base(message) { } public UserOperationException(string message, Exception innerException) : base(message, innerException) { } }
自此,全局异常配置完成,然后我们可以测试一下,随便写一个除以0的代码在日志记录中就会出现如下的展示:
哇,发现我的错误日志的格式非常的清楚,当然这个跟我的做事态度以及性格有很大的关系的啦,毕竟楼主还是很帅的。哈哈哈。
三、NLog使用
1、在项目中添加nlog的nuget包引入,“NLog.Web.AspNetCore”
2、创建nlog.config文件,大家会发现我的log格式跟上面的格式操作,而且我的分层层次也很清楚。哈哈.
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true"> <!-- the targets to write to --> <targets> <!-- 输出到文件,这个文件记录所有的日志 --> <target xsi:type="File" name="allfile" fileName="Log\LogAll\${shortdate}.htm" layout="<HR COLOR=red>${longdate}<BR>${logger}<BR>${uppercase:${level}}<BR>${message} ${exception}<HR Size=1>" /> <!-- 输出到文件,这个文件记录错误日志 --> <target xsi:type="File" name="logError" fileName="Log\LogError\${shortdate}.htm" layout="<HR COLOR=red>【异常时间】:${date} <BR>【异常级别】:${level:uppercase=true} <BR>${message}<HR Size=1>" /> <!-- 输出到文件,这个文件记录操作日志 --> <target xsi:type="File" name="logInfo" fileName="Log\LogInfo\${shortdate}.htm" layout="<HR COLOR=red>【操作时间】:${date} <BR>【操作级别】:${level:uppercase=true} <BR>${message}<HR Size=1>" /> </targets> <!-- rules to map from logger name to target --> <rules> <!--All logs, including from Microsoft--> <logger name="*" minlevel="Trace" writeTo="allfile" /> <logger name="*" minlevel="Error" writeTo="logError" /> <logger name="*" minlevel="Info" writeTo="logInfo" /> <logger name="Microsoft.*" maxLevel="Info" final="true" /> </rules> </nlog>
注:然后将此文件点击右键,选择属性,把复制输出目录修改为“始终复制”,无法不修改,则会无法加载此文件。
3、在startup.cs中的 Configure方法注入
//ILoggerFactory loggerFactory
loggerFactory.AddNLog();
NLog.LogManager.LoadConfiguration("nlog.config"); //填入上面创建的文件的名称
然后运行以下即可看到在bin/debug下面生成文件夹
4、创建NLogHelp.cs类
public class NLogHelp { public static Logger logger = LogManager.GetCurrentClassLogger(); public static void ErrorLog(string throwMsg, Exception ex) { string errorMsg = string.Format("【异常信息】:{0} <br>【异常类型】:{1} <br>【堆栈调用】:{2}", new object[] { throwMsg, ex.GetType().Name, ex.StackTrace }); errorMsg = errorMsg.Replace("\r\n", "<br>"); errorMsg = errorMsg.Replace("位置", "<strong style=\"color:red\">位置</strong>"); logger.Error(errorMsg); } public static void InfoLog(string operateMsg) { string errorMsg = string.Format("【操作信息】:{0} <br>", new object[] { operateMsg }); errorMsg = errorMsg.Replace("\r\n", "<br>"); logger.Info(errorMsg); } }
5、在上面log4net中的GlobalExceptions类把
LogHelper.ErrorLog(json.Message, context.Exception)替换成如下:NLogHelp.ErrorLog(json.Message,context.Exception)即可。
运行测试如下:
【异常时间】:2018/09/03 14:41:36.786 【异常级别】:ERROR 【异常信息】:错误消息:Failed to create instance of type at AspectCore.Injector.ServiceCallSiteResolver.ResolvePropertyInject(ServiceDefinition service) 【异常类型】:InvalidOperationException 【堆栈调用】: at AspectCore.Injector.ServiceCallSiteResolver.ResolveTypeService(TypeServiceDefinition typeServiceDefinition) at AspectCore.Injector.ServiceCallSiteResolver.ResolvePropertyInject(ServiceDefinition service) at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) at AspectCore.Injector.ServiceResolver.b
自此,完美搞定,等后期我将会介绍采用ELK+NLog进行数据采集及展示,请大家拭目以待吧。
asp.net Core 交流群:787464275 欢迎加群交流
如果您认为这篇文章还不错或者有所收获,您可以点击右下角的【推荐】按钮精神支持,因为这种支持是我继续写作,分享的最大动力!
微信公众号:欢迎关注 QQ技术交流群: 欢迎加群