基于log4net的日志组件扩展分装,实现自动记录交互日志 XYH.Log4Net.Extend

背景:

  随着公司的项目不断的完善,功能越来越复杂,服务也越来越多(微服务),公司迫切需要对整个系统的每一个程序的运行情况进行监控,并且能够实现对自动记录不同服务间的程序调用的交互日志,以及通一个服务或者项目中某一次执行情况的跟踪监控

根据log4net的现有功能满足不了实际需求,所以需要以log4net为基础进行分装完善,现在分装出了一个基础的版本,如有不妥之处,多多指点
功能简介:
  该组件是在log4net的基础上,进行了一定的扩展封装实现的自动记录交互日志功能
  该组件的封装的目的是解决一下几个工作中的实际问题
  1、对记录的日志内容格式完善
  2、微服务项目中,程序自动记录不同服务间的调用关系,以及出参、入参、执行时间等
  3、同一项目中,不同方法及其层之间的调用关系等信息
  4、其最终目的就是,实现对系统的一个整体监控

主要封装扩展功能点:
1、通过对log4net进行扩展,能够自定义了一些日志格式颜色内容等
2、通过代理+特性的方式,实现程序自动记录不同服务间,以及同一程序间的相互调用的交互日志
3、采用队列的方式实现异步落地日志到磁盘文件

主要核心代码示例,具体的详细代码,我已经上传至githut开源项目中,如有需要可以下载了解

github源码地址:https://github.com/xuyuanhong0902/XYH.Log4Net.Extend.git

代理实现自动记录方法调用的详细日志

   /// <summary>
    /// XYH代理实现类.
    /// </summary>
    public class XYHAopProxy : RealProxy
    {
        /// <summary>
        /// 构造函数.
        /// </summary>
        /// <param name="target">目标类型.</param>
        public XYHAopProxy(Type target)
            : base(target)
        {
        }

        /// <summary>
        /// 重写代理实现.
        /// </summary>
        /// <param name="msg">代理函数</param>
        /// <returns>返回结果</returns>
        public override IMessage Invoke(IMessage methodInvoke)
        {
            //// 方法开始执行时间
            DateTime executeStartTime = System.DateTime.Now;

            //// 方法执行结束时间
            DateTime executeEndTime = System.DateTime.Now;

            IMessage message = null;
            IMethodCallMessage call = methodInvoke as IMethodCallMessage;
            object[] customAttributeArray = call.MethodBase.GetCustomAttributes(false);
            call.MethodBase.GetCustomAttributes(false);

            try
            {
                // 前处理.
                List<IAopAction> proActionList = this.InitAopAction(customAttributeArray, AdviceType.Before);

                //// 方法执行开始记录日志
                if (proActionList != null && proActionList.Count > 0  )
                {
                    foreach (IAopAction item in proActionList)
                    {
                        IMessage preMessage = item.PreProcess(methodInvoke, base.GetUnwrappedServer());
                        if (preMessage != null)
                        {
                            message = preMessage;
                        }
                    }

                    if (message != null)
                    {
                        return message;
                    }
                }

                message = Proessed(methodInvoke);

                // 后处理.
                proActionList = this.InitAopAction(customAttributeArray, AdviceType.Around);

                //// 方法执行结束时间
                executeEndTime = System.DateTime.Now;

                //// 方法执行结束记录日志
                if (proActionList != null && proActionList.Count > 0)
                {
                    foreach (IAopAction item in proActionList)
                    {
                        item.PostProcess(methodInvoke, message, base.GetUnwrappedServer(), executeStartTime, executeEndTime);
                    }
                }
            }
            catch (Exception ex)
            {
                //// 方法执行结束时间
                executeEndTime = System.DateTime.Now;

                // 异常处理.吃掉异常,不影响主业务
                List<IAopAction> proActionList = this.InitAopAction(customAttributeArray, AdviceType.Around);
                if (proActionList != null && proActionList.Count > 0)
                {
                    foreach (IAopAction item in proActionList)
                    {
                        item.ExceptionProcess(ex, methodInvoke, base.GetUnwrappedServer(), executeStartTime, executeEndTime);
                    }
                }
            }

            return message;
        }

        /// <summary>
        /// 处理方法执行.
        /// </summary>
        /// <param name="methodInvoke">代理目标方法</param>
        /// <returns>代理结果</returns>
        public virtual IMessage Proessed(IMessage methodInvoke)
        {
            IMessage message;
            if (methodInvoke is IConstructionCallMessage)
            {
                message = this.ProcessConstruct(methodInvoke);
            }
            else
            {
                message = this.ProcessInvoke(methodInvoke);
            }
            return message;
        }

        /// <summary>
        /// 普通代理方法执行.
        /// </summary>
        /// <param name="methodInvoke">代理目标方法</param>
        /// <returns>代理结果</returns>
        public virtual IMessage ProcessInvoke(IMessage methodInvoke)
        {
            IMethodCallMessage callMsg = methodInvoke as IMethodCallMessage;
            object[] args = callMsg.Args;   //方法参数
            object o = callMsg.MethodBase.Invoke(base.GetUnwrappedServer(), args);  //调用 原型类的 方法       

            return new ReturnMessage(o, args, args.Length, callMsg.LogicalCallContext, callMsg);   // 返回类型 Message
        }

        /// <summary>
        /// 构造函数代理方法执行.
        /// </summary>
        /// <param name="methodInvoke">代理目标方法</param>
        /// <returns>代理结果</returns>
        public virtual IMessage ProcessConstruct(IMessage methodInvoke)
        {
            IConstructionCallMessage constructCallMsg = methodInvoke as IConstructionCallMessage;
            IConstructionReturnMessage constructionReturnMessage = this.InitializeServerObject((IConstructionCallMessage)methodInvoke);
            RealProxy.SetStubData(this, constructionReturnMessage.ReturnValue);

            return constructionReturnMessage;
        }

        /// <summary>
        /// 代理包装业务处理.
        /// </summary>
        /// <param name="customAttributeArray">代理属性</param>
        /// <param name="adviceType">处理类型</param>
        /// <returns>结果.</returns>
        public virtual List<IAopAction> InitAopAction(object[] customAttributeArray, AdviceType adviceType)
        {
            List<IAopAction> actionList = new List<IAopAction>();
            if (customAttributeArray != null && customAttributeArray.Length > 0)
            {
                foreach (Attribute item in customAttributeArray)
                {
                    XYHMethodAttribute methodAdviceAttribute = item as XYHMethodAttribute;
                    if (methodAdviceAttribute != null && (methodAdviceAttribute.AdviceType == adviceType))
                    {
                        if (methodAdviceAttribute.ProcessType == ProcessType.None)
                        {
                            continue;
                        }

                        if (methodAdviceAttribute.ProcessType == ProcessType.Log)
                        {
                            actionList.Add(new LogAopActionImpl());
                            continue;
                        }
                    }
                }
            }

            return actionList;
        }
    }

  类注解

  /// <summary>
    /// XYH代理属性[作用于类].
    /// ************************************
    /// [DecorateSymbol] Class ClassName
    /// ************************************
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class XYHAopAttribute : ProxyAttribute
    {
        public XYHAopAttribute()
        {
        }

        public override MarshalByRefObject CreateInstance(Type serverType)
        {
            XYHAopProxy realProxy = new XYHAopProxy(serverType);
            return realProxy.GetTransparentProxy() as MarshalByRefObject;
        }
    }

  队列实现异步日志落地到磁盘文件

namespace XYH.Log4Net.Extend
{
    /// <summary>
    /// 通过队列的方式实现异步记录日志
    /// </summary>
    public sealed class ExtendLogQueue
    {
        /// <summary>
        /// 记录消息 队列
        /// </summary>
        private readonly ConcurrentQueue<LogMessage> extendLogQue;

        /// <summary>
        /// 信号
        /// </summary>
        private readonly ManualResetEvent extendLogMre;

        /// <summary>
        /// 日志
        /// </summary>
        private static ExtendLogQueue _flashLog = new ExtendLogQueue();

        /// <summary>
        /// 构造函数
        /// </summary>
        private ExtendLogQueue()
        {
            extendLogQue = new ConcurrentQueue<LogMessage>();
            extendLogMre = new ManualResetEvent(false);
        }

        /// <summary>
        /// 单例实例
        /// </summary>
        /// <returns></returns>
        public static ExtendLogQueue Instance()
        {
            return _flashLog;
        }

        /// <summary>
        /// 另一个线程记录日志,只在程序初始化时调用一次
        /// </summary>
        public void Register()
        {
            Thread t = new Thread(new ThreadStart(WriteLogDispatch));
            t.IsBackground = false;
            t.Start();
        }

        /// <summary>
        /// 从队列中写日志至磁盘
        /// </summary>
        private void WriteLogDispatch()
        {
            while (true)
            {

                //// 如果队列中还有待写日志,那么直接调用写日志
                if (extendLogQue.Count > 0)
                {
                    //// 根据队列写日志
                    WriteLog();

                    // 重新设置信号
                    extendLogMre.Reset();
                }

                //// 如果没有,那么等待信号通知
                extendLogMre.WaitOne();
            }
        }

        /// <summary>
        /// 具体调用log4日志组件实现
        /// </summary>
        private void WriteLog()
        {
            LogMessage msg;
            // 判断是否有内容需要如磁盘 从列队中获取内容,并删除列队中的内容
            while (extendLogQue.Count > 0 && extendLogQue.TryDequeue(out msg))
            {
                new LogHandlerImpl(LogHandlerManager.GetILogger(msg.LogSerialNumber)).WriteLog(msg);
            }
        }

        /// <summary>
        /// 日志入队列
        /// </summary>
        /// <param name="message">日志文本</param>
        /// <param name="level">等级</param>
        /// <param name="ex">Exception</param>
        public  void EnqueueMessage(LogMessage logMessage)
        {
            //// 日志入队列
            extendLogQue.Enqueue(logMessage);

            // 通知线程往磁盘中写日志
            extendLogMre.Set();
        }
    }
}

  自定义扩展log4net日志格式内容

namespace XYH.Log4Net.Extend
{
    /// <summary>
    /// 自定义布局(对log2net日志组件的布局自定义扩展).
    /// </summary>
    public class HandlerPatternLayout : PatternLayout
    {
        /// <summary>
        /// 构造函数.
        /// </summary>
        public HandlerPatternLayout()
        {
            ///// 机器名称
            this.AddConverter("LogMachineCode", typeof(LogMachineCodePatternConvert));

            //// 方法名称
            this.AddConverter("MethodName", typeof(LogMethodNamePatternConvert));

            //// 方法入参
            this.AddConverter("MethodParam", typeof(LogMethodParamConvert));

            //// 方法出参
            this.AddConverter("MethodResult", typeof(LogMethodResultConvert));

            //// 程序名称
            this.AddConverter("LogProjectName", typeof(LogProjectNamePatternConvert));

            //// IP 地 址
            this.AddConverter("LogIpAddress", typeof(LogServiceIpPatternConvert));

            //// 日志编号
            this.AddConverter("LogUniqueCode", typeof(LogUniquePatternConvert));

            //// 日志序列号
            this.AddConverter("LogSerialNumber", typeof(LogSerialNumberPatternConvert));

            //// 调用路径
            this.AddConverter("InvokeName", typeof(LogInvokeNamePatternConvert));

            //// 执行开始时间
            this.AddConverter("ExecuteStartTime", typeof(ExecuteStartTimePatternConvert));

            //// 执行结束时间
            this.AddConverter("ExecuteEndTime", typeof(ExecuteEndTimePatternConvert));

            //// 执行时间
            this.AddConverter("ExecuteTime", typeof(ExecuteTimePatternConvert));
        }
    }
}

  

使用说明:
第一步:需要dll文件引用
需要引用两个dell文件:
jeson序列化:Newtonsoft.Json.dll
log4net组件:log4net.dll
log3net扩展组件:XYH.Log4Net.Extend.dll

第二步:log4配置文件配置
主要配置日志的存储地址,日志文件存储格式、内容等
下面,给一个参考配置文件,具体的配置可以根据实际需要自由配置,其配置方式很log4net本身的配置文件一样,在此不多说

<log4net>
  <root>
    <!-- 定义记录的日志级别[None、Fatal、ERROR、WARN、DEBUG、INFO、ALL]-->
    <level value="ALL"/>
    <!-- 记录到什么介质中-->
    <appender-ref ref="LogInfoFileAppender"/>
    <appender-ref ref="LogErrorFileAppender"/>
  </root>
  <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
  <appender name="LogInfoFileAppender" 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".html""/>
    <param name="RollingStyle" value="Date"/>
    <!--布局-->
    <layout type="XYH.Log4Net.Extend.HandlerPatternLayout">
      <param name="ConversionPattern" value="<HR COLOR=blue>%n%n
                                             日志编号:%property{LogUniqueCode}  <BR >%n
                                             日志序列:%property{LogSerialNumber} <BR>%n
                                             机器名称:%property{LogMachineCode} <BR>%n
                                             IP 地 址:%property{LogIpAddress} <BR>%n
                                             开始时间:%property{ExecuteStartTime} <BR>%n
                                             结束时间:%property{ExecuteEndTime} <BR>%n
                                             执行时间:%property{ExecuteTime} <BR>%n
                                             程序名称:%property{LogProjectName} <BR>%n
                                             方法名称:%property{MethodName} <BR>%n
                                             方法入参:%property{MethodParam} <BR>%n
                                             方法出参:%property{MethodResult} <BR>%n
                                             日志信息:%m <BR >%n
                                             日志时间:%d <BR >%n
                                             日志级别:%-5p <BR >%n
                                             异常堆栈:%exception <BR >%n
                                             <HR Size=1 >"/>
    </layout>
  </appender>
  <!-- name属性指定其名称,type则是log4net.Appender命名空间的一个类的名称,意思是,指定使用哪种介质-->
  <appender name="LogErrorFileAppender" type="log4net.Appender.RollingFileAppender">
    <!-- 输出到什么目录-->
    <param name="File" value="Log\\LogError\\"/>
    <!-- 是否覆写到文件中-->
    <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".html""/>
    <param name="RollingStyle" value="Date"/>
    <!--布局-->
    <layout type="XYH.Log4Net.Extend.HandlerPatternLayout">
      <param name="ConversionPattern" value="<HR COLOR=red>%n
                                             日志编号:%property{LogUniqueCode}  <BR >%n
                                             日志序列:%property{LogSerialNumber} <BR>%n
                                             机器名称:%property{LogMachineCode} <BR>%n
                                             IP 地 址: %property{LogIpAddress} <BR>%n
                                             程序名称:%property{LogProjectName} <BR>%n
                                             方法名称:%property{MethodName}<BR>%n
                                             方法入参:%property{MethodParam} <BR>%n
                                             方法出参:%property{MethodResult} <BR>%n
                                             日志信息:%m <BR >%n
                                             日志时间:%d <BR >%n
                                             日志级别:%-5p <BR >%n
                                             异常堆栈:%exception <BR >%n
                                             <HR Size=1 >"/>
    </layout>
    <filter type="log4net.Filter.LevelRangeFilter">
      <levelMin value="ERROR"/>
      <levelMax value="FATAL"/>
    </filter>
  </appender>
</log4net>

  

第三步:在Global.asax文件中注册消息队列
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);

////注册日志队列
ExtendLogQueue.Instance().Register();
}

第四步:在Global.asax文件中生成处理日志序列号
/// <summary>
/// 每一个请求执行开始
/// </summary>
protected void Session_Start() {
//// 记录获取创建每一个请求的序列号
/// 如果调用放传递了序列号,那么就直接去调用放传递的序列号
/// 如果调用放未传递,那么则生成一个序列号
/// 这样,在一次请求的头部传递一个该请求的唯一序列号,并在以后的每一个请求都一直传递下去
/// 这样,就能够通过这个序列号把每一次请求之间的服务或者方法调用关系串联起来
String[] serialNumber = Request.Headers.GetValues("serialNumber");
if (serialNumber!=null && serialNumber.Length>0 && !string.IsNullOrEmpty(serialNumber[0]))
{
Session["LogSerialNumber"] = serialNumber[0];
}
else
{
Session["LogSerialNumber"] = Guid.NewGuid().ToString().Replace("-", "").ToUpper();
}
}

第五步:在需要自动记录日志的方法类上加上对应的注解

//// 在需要自动记录日志的类上加上 XYHAop注解
[XYHAop]
public class Class2: calssAdd
{
//// 需要记录自动记录交互日志的方法注解 ProcessType.Log

//// 同时该类还必须继承ContextBoundObject

[XYHMethod(ProcessType.Log)]
public int AddNum(int num1, int num2)
{
}
//// 需要记录自动记录交互日志的方法注解 ProcessType.None,其实不加注解也不会记录日志
[XYHMethod(ProcessType.None)]
public int SubNum(int num1, int num2)
{
}
}

第六步:完成上面五步已经能够实现自动记录交互日志了,

 但是在实际使用中我们也会手动记录一些日志,本插件也支持手动记录日志的同样扩展效果

目前支持以下6中手动记录日志的重载方法基于log4net的日志组件扩展分装,实现自动记录交互日志 XYH.Log4Net.Extend

 /// <summary>
    /// 记录日志扩展入口
    /// </summary>
    public class XYHLogOperator
    {
        /// <summary>
        /// 添加日志.
        /// </summary>
        /// <param name="message">日志信息对象</param>
        public static void WriteLog(object message)
        {
            new MessageIntoQueue().WriteLog(message);
        }

        /// <summary>
        /// 添加日志.
        /// </summary>
        /// <param name="message">日志信息对象</param>
        /// <param name="level">日志信息级别</param>
        public static void WriteLog(object message, LogLevel level)
        {
            new MessageIntoQueue().WriteLog(message, level);
        }

        /// <summary>
        /// 添加日志.
        /// </summary>
        /// <param name="message">日志信息对象</param>
        /// <param name="level">日志信息级别</param>
        /// <param name="exception">异常信息对象</param>
        public static void WriteLog(object message, Exception exception)
        {
            new MessageIntoQueue().WriteLog(message, exception);
        }

        /// <summary>
        /// 添加日志.
        /// </summary>
        /// <param name="message">日志信息对象</param>
        /// <param name="methodName">方法名</param>
        /// <param name="methodParam">方法入参</param>
        /// <param name="methodResult">方法请求结果</param>
        public static void WriteLog(object message, string methodName, object methodParam, object methodResult)
        {
            new MessageIntoQueue().WriteLog(message, methodName, methodParam, methodResult);
        }

        /// <summary>
        /// 添加日志.
        /// </summary>
        /// <param name="message">日志信息对象</param>
        /// <param name="methodName">方法名</param>
        /// <param name="methodParam">方法入参</param>
        /// <param name="methodResult">方法请求结果</param>
        /// <param name="level">日志记录级别</param>
        public static void WriteLog(object message, string methodName, object methodParam, object methodResult, LogLevel level)
        {
            new MessageIntoQueue().WriteLog(message, methodName, methodParam, methodResult, level);
        }

        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="extendLogInfor">具体的日志消息model</param>
        public static void WriteLog(LogMessage extendLogInfor)
        {
            new MessageIntoQueue().WriteLog(extendLogInfor);
        }
    }
}

  

手动记录日志示例:

object message = "一个参数日志记录单元测试"; // TODO: 初始化为适当的值
XYHLogOperator.WriteLog(message);

如有问题,欢迎QQ随时交流
QQ:1315597862

github源码地址:https://github.com/xuyuanhong0902/XYH.Log4Net.Extend.git

原文地址:https://www.cnblogs.com/xiaoXuZhi/p/XYH_Log4Net_Extend.html

时间: 2024-11-08 15:38:33

基于log4net的日志组件扩展分装,实现自动记录交互日志 XYH.Log4Net.Extend的相关文章

ASP.NET使用log4Net日志组件教程(按日期与按日志大小切割)

对于一个大型网站与系统来说,日志是必备的工具,通过日志你可以非常清楚程序的运行情况,及时得到反馈来解决问题,下面介绍ASP.NET版本的log4Net日志组件是个非常强大的工具,最新版本for .net2.0 1.2.10.0 本人搞了一天,终于知道搞清楚怎样使用了,简单记录一下. 以下介绍的方法是log4net使用单独的配置文件的. 开始行动: 第一步:在项目引用log4net.dll文件 第二步: 在Web.config文件中加入一句代码,位置如下: <configuration>   

ASP.NET 日志组件LogNet.DLL 引用即可写入日志及读取日志

借助LogNet组件,以后查看站点日志,再也不用去服务器下载了 日志组件:LogNet.DLL ,引用即可使用 写入方法: 1.LogNet.Log.WriteLog("日志标题", "日志内容"); 2.LogNet.Log.WriteLog("日志标题",new Exception()); 日志内容同时写入年月日三份文本文件中 站点读取方法: 复制 ReadLogNet.aspx 文件到站点,WebForm和MVC站点都一样,文件名也可自定义

日志组件解析

日志组件解析 NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包含控制台.文本文件.数据库,一般都是创建全局的Logger,在需要记录日志的地方调用相应的Logger输出至相应目标.遇到输出目标多了有时候也感觉挺麻烦的,不过也还能接受.开始学习.NetCore后接触到了日志记录框架(Logging组件),虽然完全可以用之前的方式记录日志,不过应该使用

.NetCore中的日志(1)日志组件解析

.NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包含控制台.文本文件.数据库,一般都是创建全局的Logger,在需要记录日志的地方调用相应的Logger输出至相应目标.遇到输出目标多了有时候也感觉挺麻烦的,不过也还能接受.开始学习.NetCore后接触到了日志记录框架(Logging组件),虽然完全可以用之前的方式记录日志,不过应该使用更通用的方式

C#组件系列———又一款日志组件:Elmah的学习和分享

前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇.最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛.一如既往,园子里每年这个时候都有大把的年终总结.回忆过去展望未来之类的文章.博主是没时间写总结了,要学的东西太多.关于Vue的系列一定要抽时间补上.最近刚用了一个日志组件Elmah,比较适合开发阶段异常信息的快速定位与追溯,有兴趣的跟着博主一起来看看吧. 本文原创地址:http://www.cnblogs.com/landea

【Go】类似csv的数据日志组件设计

原文链接:https://blog.thinkeridea.com/201907/go/csv_like_data_logs.html 我们业务每天需要记录大量的日志数据,且这些数据十分重要,它们是公司收入结算的主要依据,也是数据分析部门主要得数据源,针对这么重要的日志,且高频率的日志,我们需要一个高性能且安全的日志组件,能保证每行日志格式完整性,我们设计了一个类 csv 的日志拼接组件,它的代码在这里 datalog. 它是一个可以保证日志各列完整性且高效拼接字段的组件,支持任意列和行分隔符,

log4net日志组件

一.什么是log4net组件 Log4net是基于.net开发的一款非常著名的记录日志开源组件.他最早是2001年7月由NeoWorks Limited启动的项目,基本的框架源于另外的一个非常著名的姐妹组件-log4j.Log4net记录日志的功能非常强大.它可以将日志分不同的等级,比不同的样式,将日志输出到不同的媒介(数据库.文本.控制台.邮件--). 二.log4net的核心内容 Log4net 主要分为5个核心主键: Logger,Appender,Filter,Layout,Object

MVC扩展Filter,通过继承HandleErrorAttribute,使用log4net或ELMAH组件记录服务端500错误、HttpException、Ajax异常等

□ 接口 public interface IExceptionFilter{    void OnException(ExceptionContext filterContext);} ExceptionContext继承于ControllerContext,从中可以获得路由数据route data.HttpContext. □ 的HandleErrorAttribute是对IExceptionFilter的实现,默认是启用的 public static void RegisterGlobal

快速入门系列--Log4net日志组件

Log4net是阿帕奇基金会的非常流行的开源日志组件,是log4j的.NET移植版本,至今已经有11年的历史,使用方便并且非常稳定,此外很重要的一点是其和很多开源组件能很好的组合在一起工作,例如NHibernate等.对于以本地日志为主的中小型的项目,Log4net已经足够使用,当然涉及跨平台的大型分布式系统可以选择Elmah等其他日志组件. 在这里,主要介绍log4net的一些关键知识点,详细内容可见以下链接: 官方配置文档:http://logging.apache.org/log4net/