Dotnet_log4net 介绍说明
Log4net可以从http://logging.apache.org/log4net/download.html网站下载最新版本。
在具体应用中,对该组件进行了扩展包装,按日期记录系统异常信息以及相关系统信息。具体代码如下:
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Web;
using System.IO;
using Digital.Common;
using log4net;
#region 使用说明
/*
* 在使用时,应在应用程序目录下,建立目录config(config目录作为所有相关config文件的目录),
* 并添加log4net.config文件,该文件的内容可为如下内容:
*
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
</configSections>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<param name="File" value="Log\"/>
<param name="AppendToFile" value="true"/>
<param name="MaxSizeRollBackups" value="100"/>
<param name="StaticLogFileName" value="false"/>
<param name="DatePattern" value="yyyyMMdd".html""/>
<param name="RollingStyle" value="Date"/>
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="<HR COLOR=red>%n <b>异常时间:</b>%d <BR>%n <b>异常级别:</b>%-5p <BR>%n%m %n <HR Size=1>"/>
</layout>
</appender>
<root>
<level value="ALL"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>
</log4net>
</configuration>
*
*/
#endregion
namespace Digital.Framework
{
/// <summary>
/// 日志类,可以添加Debug、Message、Warn、Error、Fatal等类别信息,
/// 该类是Log4Net的包装类
/// </summary>
public sealed class MyLog
{
internal static log4net.ILog m_MyLog = log4net.LogManager.GetLogger("MyLog");
#region 私有构造函数,单例模式,防止被实例化
/// <summary>
/// 私有构造函数,单例模式,防止被实例化
/// </summary>
private MyLog()
{
}
#endregion
#region 初始化加载配置文件log4net.config
/// <summary>
/// 初始化加载配置文件log4net.config
/// </summary>
public static void InitializeLog4Net()
{
log4net.Config.XmlConfigurator.Configure();
}
#endregion
#region 事件基本信息
/// <summary>
/// 事件基本信息
/// </summary>
private struct EventBody
{
/// <summary>
/// 日志标题变量
/// </summary>
public string Title;
/// <summary>
/// 日志等级变量
/// </summary>
public LogLevel LogLevel;
/// <summary>
/// 日志来源变量
/// </summary>
public LogSource LogSource;
/// <summary>
/// 远程主机IP地址
/// </summary>
public string UserHostAddress
{
get
{
return HttpHelper.GetClientIP();
}
}
/// <summary>
/// 出错页面地址
/// </summary>
public string ErrorPage
{
get
{
return WebHelper.GetUrl();// RequestHelper.GetUrl();
}
}
/// <summary>
/// 页面来源地址
/// </summary>
public string ReferrerPage
{
get
{
return WebHelper.GetUrlReferrer();
}
}
/// <summary>
/// 当前会话信息属性
/// </summary>
public string CurrentSessionInfo
{
get
{
StringBuilder SessionInfo = new StringBuilder();
if (HttpContext.Current != null && HttpContext.Current.Session != null)
{
for (int i = 0; i < HttpContext.Current.Session.Count; i++)
{
SessionInfo.Append(Environment.NewLine).Append((i + 1).ToString())
.Append(":Session[").Append(HttpContext.Current.Session.Keys[i])
.Append("] = ").Append(HttpContext.Current.Session[i] == null ? "" : HttpContext.Current.Session[i].ToString());
}
}
if (SessionInfo.Length == 0)
{
return "Session会话信息为空!";
}
else
{
return SessionInfo.Insert(0, "Session会话信息为:" + Environment.NewLine).ToString();
}
}
}
}
#endregion
//公有
#region 写日志方法
/// <summary>
/// 写日志方法
/// </summary>
public static void WriteLog()
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = "未知内容";
CurrentEventBody.LogSource = LogSource.UnknowLayer;
CurrentEventBody.LogLevel = LogLevel.Info;
WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Title">日志标题</param>
public static void WriteLog(string Title)
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = Title;
CurrentEventBody.LogSource = LogSource.UnknowLayer;
CurrentEventBody.LogLevel = LogLevel.Info;
WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Source">日志来源</param>
private static void WriteLog(LogSource Source)
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = "未知内容";
CurrentEventBody.LogSource = Source;
CurrentEventBody.LogLevel = LogLevel.Info;
WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Level">日志等级</param>
private static void WriteLog(LogLevel Level)
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = "未知内容";
CurrentEventBody.LogSource = LogSource.UnknowLayer;
CurrentEventBody.LogLevel = Level;
WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Level">日志等级</param>
/// <param name="Source">日志来源</param>
public static void WriteLog(LogLevel Level, LogSource Source)
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = "未知内容";
CurrentEventBody.LogSource = Source;
CurrentEventBody.LogLevel = Level;
WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Title">日志标题</param>
/// <param name="Level">日志等级</param>
/// <param name="Source">日志来源</param>
public static void WriteLog(string Title, LogLevel Level, LogSource Source)
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = Title;
CurrentEventBody.LogSource = Source;
CurrentEventBody.LogLevel = Level;
WriteLog(CurrentEventBody, HttpContext.Current.Server.GetLastError());
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="EventLevel">日志等级</param>
/// <param name="Source">日志来源</param>
/// <param name="Exp">异常对象</param>
private static void WriteLog(LogLevel Level, LogSource Source, Exception Exp)
{
WriteLog("未知内容", Level, Source, Exp);
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Title">日志标题</param>
/// <param name="Level">日志等级</param>
/// <param name="Source">日志来源</param>
/// <param name="Exp">异常对象</param>
public static void WriteLog(string Title, LogLevel Level, LogSource Source, Exception Exp)
{
WriteLog(Title, Level, Source, Exp, null);
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="Title">日志标题</param>
/// <param name="Level">日志等级</param>
/// <param name="Source">日志来源</param>
/// <param name="Exp">异常对象</param>
/// <param name="obj">异常发生对象</param>
public static void WriteLog(string Title, LogLevel Level, LogSource Source, Exception Exp, object obj)
{
EventBody CurrentEventBody = new EventBody();
CurrentEventBody.Title = Title;
CurrentEventBody.LogLevel = Level;
CurrentEventBody.LogSource = Source;
for (Exception Temp = Exp; Temp != null; Temp = Temp.InnerException)
{
WriteLog(CurrentEventBody, Temp, obj);
}
}
#endregion
#region 获取日志文件
/// <summary>
/// 获取日志文件
/// </summary>
/// <returns></returns>
public static DataTable GetFileinfoDataTable()
{
DataTable objDataTable = new DataTable("Fileinfo");
objDataTable.Columns.Add("FileName", System.Type.GetType("System.String"));
objDataTable.Columns.Add("FileTime", System.Type.GetType("System.String"));
string rootPath = HttpContext.Current.Server.MapPath(WebHelper.CurrentContext.Request.Path);
rootPath = rootPath.Substring(0, rootPath.LastIndexOf('\\'));
DirectoryInfo objDirectoryInfo = new DirectoryInfo(rootPath);
FileInfo[] ArrFileInfo = objDirectoryInfo.GetFiles();
DataRow objDataRow;
File.Delete(rootPath + "/current.html");
foreach (FileInfo objFileInfo in ArrFileInfo)
{
if (objFileInfo.Name.ToLower().IndexOf("errorlog") == -1 &&
objFileInfo.Name.ToLower().IndexOf("current") == -1 &&
objFileInfo.Extension == ".html")
{
objDataRow = objDataTable.NewRow();
if (objFileInfo.Name == DateTime.Now.ToString("yyyyMMdd") + ".html")
{
File.Copy(objFileInfo.FullName, rootPath + "/current.html");
objDataRow["FileName"] = "current.html";
objDataRow["FileTime"] = DateTime.Now.ToString("yyyy年MM月dd日");
}
else
{
objDataRow["FileName"] = objFileInfo.Name;
objDataRow["FileTime"] = objFileInfo.Name.Replace(".html", "").Insert(4, "年").Insert(7, "月") + "日";
}
objDataTable.Rows.InsertAt(objDataRow, 0);
}
}
return objDataTable;
}
#endregion
//私有方法
#region private 写日志方法
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="objEventBody">事件信息体</param>
/// <param name="objExp">异常</param>
private static void WriteLog(EventBody objEventBody, Exception objExp)
{
WriteLog(objEventBody, objExp, null);
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name="objEventBody">事件信息体</param>
/// <param name="objExp">异常</param>
private static void WriteLog(EventBody objEventBody, Exception objExp, object obj)
{
//事件信息初始化
StringBuilder strEventMessage = new StringBuilder();
strEventMessage.Append("\r\n");
strEventMessage.Append("<b>内容标题:</b>").Append(objEventBody.Title).Append("<br>\r\n");
strEventMessage.Append("<b>远程主机:</b>").Append(objEventBody.UserHostAddress).Append("<br>\r\n");
strEventMessage.Append("<b>出错页面:</b>").Append(objEventBody.ErrorPage).Append("<br>\r\n");
strEventMessage.Append("<b>页面来源:</b>").Append(objEventBody.ReferrerPage).Append("<br>\r\n");
strEventMessage.Append("<b>会话信息:</b>").Append(objEventBody.CurrentSessionInfo).Append("<br>\r\n");
strEventMessage.Append("<b>事件来源:</b>").Append(objEventBody.LogSource.ToString()).Append("<br>\r\n");
if (obj != null)
{
string objInfo = GetObjectInfo(obj);
strEventMessage.Append(objInfo);
}
switch ((LogLevel)objEventBody.LogLevel)
{
case LogLevel.Fatal:
if (m_MyLog.IsFatalEnabled)
{
m_MyLog.Fatal(strEventMessage.ToString(), objExp);
}
break;
case LogLevel.Error:
if (m_MyLog.IsErrorEnabled)
{
m_MyLog.Error(strEventMessage.ToString(), objExp);
}
break;
case LogLevel.Warn:
if (m_MyLog.IsWarnEnabled)
{
m_MyLog.Warn(strEventMessage.ToString(), objExp);
}
break;
case LogLevel.Info:
if (m_MyLog.IsInfoEnabled)
{
m_MyLog.Info(strEventMessage.ToString(), objExp);
}
break;
case LogLevel.Debug:
if (m_MyLog.IsDebugEnabled)
{
m_MyLog.Debug(strEventMessage.ToString(), objExp);
}
break;
}
}
#endregion
#region private GetObjectInfo 获取对象所有属性信息
/// <summary>
/// 获取对象所有属性信息
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
private static string GetObjectInfo(object obj)
{
StringBuilder sb = new StringBuilder();
Type t = obj.GetType();
sb.Append("<hr size=1 /><b>对象信息:</b>").Append("<br/>\r\n");
sb.Append("对象名称:").Append(t.Name).Append("<br/>\r\n");
sb.Append("对象全名:").Append(t.FullName).Append("<br/>\r\n");
sb.Append("相关属性:");
System.Reflection.PropertyInfo[] pis = t.GetProperties();
foreach (System.Reflection.PropertyInfo pi in pis)
{
if (pi.CanRead)
{
sb.Append(pi.Name).Append(":[").Append(pi.GetValue(obj, null)).Append("], ");
}
}
return sb.ToString();
}
#endregion
}
#region 日志等级(参考log4net等级)
/// <summary>
/// 日志等级(参考log4net等级)
/// </summary>
public enum LogLevel
{
/// <summary>
/// The Fatal level designates very severe error events
/// that will presumably lead the application to abort.
/// </summary>
Fatal = 110000, //log4net.Core.Level.Fatal.Value
/// <summary>
///The Error level designates error events that might
///still allow the application to continue running.
/// </summary>
Error = 80000, //log4net.Core.Level.Error.Value,
/// <summary>
/// The Warn level designates potentially harmful
/// situations.
/// </summary>
Warn = 60000, //log4net.Core.Level.Warn.Value,
/// <summary>
/// The Info level designates informational messages that
/// highlight the progress of the application at coarse-grained level.
/// </summary>
Info = 40000, //log4net.Core.Level.Info.Value,
/// <summary>
/// The Debug level designates fine-grained informational
/// events that are most useful to debug an application.
/// </summary>
Debug = 30000 //log4net.Core.Level.Debug.Value
}
#endregion
#region 日志所在层LogSource
/// <summary>
/// 日志所在层
/// </summary>
public enum LogSource
{
/// <summary>
/// Web层
/// </summary>
WebLayer,
/// <summary>
/// 通用层
/// </summary>
CommonLayer,
/// <summary>
/// 数据库访问层
/// </summary>
DataLayer,
/// <summary>
/// 框架层
/// </summary>
FrameworkLayer,
/// <summary>
/// 规则层
/// </summary>
RuleLayer,
/// <summary>
/// 用户控件基类层
/// </summary>
WebUILayer,
/// <summary>
/// 搜索层
/// </summary>
SearchLayer,
/// <summary>
/// 项目后台管理层
/// </summary>
AdminLayer,
/// <summary>
/// 全局
/// </summary>
GlobalLayer,
/// <summary>
/// 未知层
/// </summary>
UnknowLayer
}
#endregion
}
另外,可参考如下网址学习log4net的应用
http://www.cnblogs.com/dragon/archive/2005/03/24/124254.aspx
http://www.rainsts.net/article.asp?id=488
本文仅对 Log4net 的使用做个简要说明,所有涉及到扩展和开发的部分一概忽略。
使用 Log4net,需要熟悉的东东有 Logger、Appender 以及 Layout。Logger 是日志记录器,我们使用其相关方法来完成日志记录;Appender 用于设置日志的存储方式和位置,Logger 的配置中会绑定一个或多个 Appender;Layout 关联具体的 Appender,用于设置日志字符串的格式。
1. Logger
所有的记录器都必须实现 ILog 接口,该接口提供日志记录所需的大量方法。
{
void Debug(...);
void Error(...);
void Fatal(...);
void Info(...);
void Warn(...);
bool IsDebugEnabled { get; }
bool IsErrorEnabled { get; }
bool IsFatalEnabled { get; }
bool IsInfoEnabled { get; }
bool IsWarnEnabled { get; }
}
通常情况下,我们通过 LogManager.GetLogger() 来获取一个记录器。LogManager 内部维护一个 hashtable,保存新创建 Logger 引用,下次需要时直接从 hashtable 获取其实例。
log.Debug("aaaaaaaaaaaaaaa");
所有 Logger 的参数设置都直接或间接继承自 root,其继承关系类似 namespace。比如,名为 "MyLogger.X.Y" 参数设置继承自 "MyLogger.X"。当我们创建 "MyLooger.X.Y" 记录器时,会在配置文件找该名称的记录器设置,如果没找到,则按继承关系向上查找,直到 root。因此,在创建 Logger 时,我们通常使用类型名称做为记录器的名字,缺省情况下,它会使用 root 或某一个父配置,但在需要的时候,我们随时可以为具体的类型添加一个更加 "详细" 的配置。
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<logger name="Learn.Library.Log4netTest">
<level value="ALL" />
</logger>
<root>
<level value="OFF" />
<appender-ref ref="Console" />
</root>
</log4net>
在创建 Logger 设置时,需要注意 "level" 参数。Log4net 允许我们通过该参数调整日志记录级别,只有高于或等于该级别的日志才会被记录下来。比如在代码调试阶段,我们可能希望记录所有的信息,而在部署阶段,我们只希望记录级别更高的错误信息。这个参数的好处是允许我们在不修改代码的前提下,随时调整记录级别。
"appender-ref" 参数用于绑定一个或多个具体的 Appender。
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
</appender>
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="Console" />
<appender-ref ref="RollingFile" />
</root>
</log4net>
2. Appender / Layout
Log4net 提供了大量的 Appender,最常用的包括 AdoNetAppender、AspNetTraceAppender、ConsoleAppender、FileAppender、OutputDebugStringAppender。每种 Appender 都有特定一些参数,使用时直接从 《Log4net 手册》的示例中拷贝过去,就OK了。(代码摘自 Log4net 手册)
(1) AspNetTraceAppender
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
(2) ConsoleAppender
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
(3) OutputDebugStringAppender
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
(4) FileAppender
<file value="log-file.txt" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>
有关 Layout 详细信息,请参考 Log4net 相关文档,本文不做详述。
3. Configuration
Log4net 的配置方式十分灵活,即可以写到应用程序配置文件中,也可以使用独立配置文件。同时它还提供了监测配置文件变化的功能,这样我们随时可以调整配置,而无须重启应用程序。
(1) 使用 app.config / web.config
app.config / web.config
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="Console" />
</root>
</log4net>
</configuration>
使用代码初始化配置。
(2) 使用自定义配置文件
test.log4net
<log4net>
<appender name="Console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%5level [%thread] (%file:%line) - %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="Console" />
</root>
</log4net>
使用代码初始化配置。
使用 XmlConfigurator.ConfigureAndWatch() 方法除了初始化配置外,还会监测配置文件的变化,一旦发生修改,将自动刷新配置。
(3) XmlConfiguratorAttribute
我们还可以使用 XmlConfiguratorAttribute 代替 XmlConfigurator.Config()/ConfigureAndWatch(),ConfiguratorAttribute 用于定义与 Assembly 相关联的配置文件名。
方式1: 关联到 test.log4net,并监测变化。
方式2: 关联到 test.exe.log4net (或 test.dll.log4net,文件名前缀为当前程序集名称),并监测变化。