使用日志组件log4net记录异常日志
到达效果:
在控制器层自动捕获错误,并把错误保存到数据库,之后显示希望用户看到的错误页面
1 首先安装log4net
(1)“程序包管理器控制台”用命令安装:先要打开控制台,在“工具”→“NuGet程序包管理器”→“程序包管理器控制台”这样就可以打开程序包管理器控制台。
(2)也可以在项目中添加对log4net.dll的引用
2 配置日志文件
1 。
如果是CS程序,则在默认的App.config文件(没有新建一个)中添加内容;如果是BS程序,则添加到Web.config文件中
<section name="log4net"
type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
</log4net>
再按照以下添加文件方式配置
2 添加日志的配置文件Log4net.xml,再从后面通过Log4netHelper帮助类实例化
日志类型
Appenders
Appenders用来定义日志的输出方式,
经常使用的输出方式有:
AdoNetAppender 将日志记录到数据库中。可以采用SQL和存储过程两种方式。
FileAppender 将日志输出到文件。
代码如下:
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
</appender>
定义日志的类型
可以按照本地文件的日志记录,比如
<log4net>
<!--错误日志类-->
<logger name="logerror"><!--日志类的名字-->
<level value="ALL" /><!--定义记录的日志级别-->
<appender-ref ref="ErrorAppender" /><!--记录到哪个介质中去-->
</logger>
<!--信息日志类-->
<logger name="loginfo">
<level value="ALL" />
<appender-ref ref="InfoAppender" />
</logger>
<!--错误日志附加介质-->
<appender name="ErrorAppender" type="log4net.Appender.RollingFileAppender"><!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
<param name="File" value="Log\\LogError\\" /><!--日志输出到exe程序这个相对目录下-->
<param name="AppendToFile" value="true" /><!--输出的日志不会覆盖以前的信息-->
<param name="MaxSizeRollBackups" value="100" /><!--备份文件的个数-->
<param name="MaxFileSize" value="10240" /><!--当个日志文件的最大大小-->
<param name="StaticLogFileName" value="false" /><!--是否使用静态文件名-->
<param name="DatePattern" value="yyyyMMdd".htm"" /><!--日志文件名-->
<param name="RollingStyle" value="Date" /><!--文件创建的方式,这里是以Date方式创建-->
<!--错误日志布局-->
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="<HR COLOR=red>%n异常时间:%d [%t] <BR>%n异常级别:%-5p <BR>%n异 常 类:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" />
</layout>
</appender>
<!--信息日志附加介质-->
<appender name="InfoAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\\LogInfo\\" />
<param name="AppendToFile" value="true" />
<param name="MaxFileSize" value="10240" />
<param name="MaxSizeRollBackups" value="100" />
<param name="StaticLogFileName" value="false" />
<param name="DatePattern" value="yyyyMMdd".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日 志 类:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" />
</layout>
</appender>
</log4net>
使用C#代码初始化lo4net
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(Server.MapPath("~/Web.config")));
3,而我使用的是数据库的方式,文件如下:
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
<logger name="WebExceptionLog">
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
</logger>
<logger name="ServiceExceptionLog">
<level value="ALL" />
<appender-ref ref="AdoNetAppender" />
</logger>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="{connectionString}" />
<commandText value="INSERT INTO [Log4Net] ([Date],[Host],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @host, @thread, @log_level, @logger, @message, @exception)" />
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="@host" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%property{log4net:HostName}" />
</layout>
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
</log4net>
4 添加本地配置文件读取类,通过这个公共类很方便读取本地配置XML文件
public class ConfigContext
{
public IConfigService ConfigService { get; set; }
/// <summary>
/// 默认以文件形式存取配置
/// </summary>
public ConfigContext() : this(new FileConfigService())
{
}
public ConfigContext(IConfigService pageContentConfigService)
{
this.ConfigService = pageContentConfigService;
}
public virtual T Get<T>(string index = null) where T : ConfigFileBase, new()
{
var result = new T();
this.VilidateClusteredByIndex(result, index);
result = this.GetConfigFile<T>(index);
return result;
}
public void Save<T>(T configFile, string index = null) where T : ConfigFileBase
{
this.VilidateClusteredByIndex(configFile, index);
configFile.Save();
var fileName = this.GetConfigFileName<T>(index);
this.ConfigService.SaveConfig(fileName, SerializationHelper.XmlSerialize(configFile));
}
private T GetConfigFile<T>(string index = null) where T : ConfigFileBase, new()
{
var result = new T();
var fileName = this.GetConfigFileName<T>(index);
var content = this.ConfigService.GetConfig(fileName);
if (content == null)
{
this.ConfigService.SaveConfig(fileName, string.Empty);
}
else if (!string.IsNullOrEmpty(content))
{
try
{
result = (T)SerializationHelper.XmlDeserialize(typeof(T), content);
}
catch
{
result = new T();
}
}
return result;
}
public virtual void VilidateClusteredByIndex<T>(T configFile, string index) where T : ConfigFileBase
{
//if (configFile.ClusteredByIndex && string.IsNullOrEmpty(index))
// throw new Exception("调用时没有提供配置文件的分区索引");
}
public virtual string GetConfigFileName<T>(string index = null)
{
var fileName = typeof(T).Name;
if (!string.IsNullOrEmpty(index))
fileName = string.Format("{0}_{1}", fileName, index);
return fileName;
}
}
添加log.xml
<?xml version="1.0" encoding="utf-16"?>
<Log xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Log>Data Source=Data Source;Initial Catalog=Catalog;uid=uid;pwd=pwd;MAX Pool Size=512;Min Pool Size=50;Connection Lifetime=30</Log>
</Log>
5.添加Log4netHelper类实列化配置文件
public static class Log4NetHelper
{
static Log4NetHelper()
{
//初始化log4net配置
var config = CachedConfigContext.Current.ConfigService.GetConfig("log4net");
//重写log4net配置里的连接字符串
config = config.Replace("{connectionString}", CachedConfigContext.Current.Log);
var ms = new MemoryStream(Encoding.Default.GetBytes(config));
log4net.Config.XmlConfigurator.Configure(ms);
}
public static void Debug(LoggerType loggerType, object message, Exception e)
{
var logger = LogManager.GetLogger(loggerType.ToString());
logger.Debug(SerializeObject(message), e);
}
public static void Error(LoggerType loggerType, object message, Exception e)
{
var logger = LogManager.GetLogger(loggerType.ToString());
logger.Error(SerializeObject(message), e);
}
public static void Info(LoggerType loggerType, object message, Exception e)
{
var logger = LogManager.GetLogger(loggerType.ToString());
logger.Info(SerializeObject(message), e);
}
public static void Fatal(LoggerType loggerType, object message, Exception e)
{
var logger = LogManager.GetLogger(loggerType.ToString());
logger.Fatal(SerializeObject(message), e);
}
public static void Warn(LoggerType loggerType, object message, Exception e)
{
var logger = LogManager.GetLogger(loggerType.ToString());
logger.Warn(SerializeObject(message), e);
}
private static object SerializeObject(object message)
{
if (message is string || message == null)
return message;
else
return JsonConvert.SerializeObject(message, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
}
}
public enum LoggerType
{
WebExceptionLog,
ServiceExceptionLog
}
6写一个所有controllb继承的controllbase父类,所有访问的controller发生的异常在这里处理并记录
public class ControllerBase : Controller
{
/// <summary>
/// 发生异常写Log
/// </summary>
/// <param name="filterContext"></param>
protected override void OnException(ExceptionContext filterContext)
{
base.OnException(filterContext);
var e = filterContext.Exception;
var str = "错误记录";
Log4NetHelper.Error(LoggerType.WebExceptionLog, str, e);
}
}
7、在WebConfig中把过滤器配置启动
<customErrors mode="On">
</customErrors>
8控制器的代码报错时,会跳转到~/Views/Shared/Error.cshtml页面。mode="Off"页面不会跳转直接显示错误信息。
9绑定异常过滤器(过滤范围是在controller的action方法中。)
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}