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 接口,该接口提供日志记录所需的大量方法。
通常情况下,我们通过 LogManager.GetLogger() 来获取一个记录器。LogManager 内部维护一个 hashtable,保存新创建 Logger 引用,下次需要时直接从 hashtable 获取其实例。
所有 Logger 的参数设置都直接或间接继承自 root,其继承关系类似 namespace。比如,名为 "MyLogger.X.Y" 参数设置继承自 "MyLogger.X"。当我们创建 "MyLooger.X.Y" 记录器时,会在配置文件找该名称的记录器设置,如果没找到,则按继承关系向上查找,直到 root。因此,在创建 Logger 时,我们通常使用类型名称做为记录器的名字,缺省情况下,它会使用 root 或某一个父配置,但在需要的时候,我们随时可以为具体的类型添加一个更加 "详细" 的配置。
在创建 Logger 设置时,需要注意 "level" 参数。Log4net 允许我们通过该参数调整日志记录级别,只有高于或等于该级别的日志才会被记录下来。比如在代码调试阶段,我们可能希望记录所有的信息,而在部署阶段,我们只希望记录级别更高的错误信息。这个参数的好处是允许我们在不修改代码的前提下,随时调整记录级别。
"appender-ref" 参数用于绑定一个或多个具体的 Appender。
2. Appender / Layout
Log4net 提供了大量的 Appender,最常用的包括 AdoNetAppender、AspNetTraceAppender、ConsoleAppender、FileAppender、OutputDebugStringAppender。每种 Appender 都有特定一些参数,使用时直接从 《Log4net 手册》的示例中拷贝过去,就OK了。(代码摘自 Log4net 手册)
(1) AspNetTraceAppender
(2) ConsoleAppender
(3) OutputDebugStringAppender
(4) FileAppender
有关 Layout 详细信息,请参考 Log4net 相关文档,本文不做详述。
3. Configuration
Log4net 的配置方式十分灵活,即可以写到应用程序配置文件中,也可以使用独立配置文件。同时它还提供了监测配置文件变化的功能,这样我们随时可以调整配置,而无须重启应用程序。
(1) 使用 app.config / web.config
app.config / web.config
使用代码初始化配置。
(2) 使用自定义配置文件
test.log4net
使用代码初始化配置。
使用 XmlConfigurator.ConfigureAndWatch() 方法除了初始化配置外,还会监测配置文件的变化,一旦发生修改,将自动刷新配置。
(3) XmlConfiguratorAttribute
我们还可以使用 XmlConfiguratorAttribute 代替 XmlConfigurator.Config()/ConfigureAndWatch(),ConfiguratorAttribute 用于定义与 Assembly 相关联的配置文件名。
方式1: 关联到 test.log4net,并监测变化。
方式2: 关联到 test.exe.log4net (或 test.dll.log4net,文件名前缀为当前程序集名称),并监测变化。