动态修改log4net的输出设置: HttpResponse

来源:互联网 发布:周口网络教育官网 编辑:程序博客网 时间:2024/05/21 11:01

在进行web开发时,有时候需要动态调试系统的处理流程,更有甚者需要把这个跟踪直接输出到http response中,这样可以直接调试而不是在执行完毕后再去查看log4net的跟踪日志。能不能让log4net直接把日志写到用户的web请求中呢?答案是肯定的,那就是自己创建一个 TextWriter。 log4net是 支持动态修改和配置的。(原文链接 http://ddbiz.com/?p=114)

看如下代码:

        public static void RedirectLogger2Response()
        {

Hierarchy hierarchy = LogManager.GetRepository() as Hierarchy;

            ResponseAppender responseAppender = null;
            foreach (log4net.Appender.IAppender adr in hierarchy.GetAppenders())
            {
                if (adr is ResponseAppender)
                {
                    responseAppender = (ResponseAppender)adr;
                    break;
                }
            }
            if (responseAppender == null)
            {
                responseAppender = new ResponseAppender();
                responseAppender.ActivateOptions();


                log4net.Config.BasicConfigurator.Configure(responseAppender);


                hierarchy.Root.AddAppender(responseAppender);
                hierarchy.Root.Level = log4net.Core.Level.All;


                hierarchy.Configured = true;
                hierarchy.RaiseConfigurationChanged(EventArgs.Empty);
            }
            else
            {
                responseAppender.InitAppender();
            }
            Logger = LogManager.GetLogger("OnlineResponse");
         }


RedirectLogger2Response 就是把当前的Logger 重定向到Http的Response中,关键在于使用自己定义的一个 Appender : ResponseAppender,ResponseAppender的定义很简单,如下:

internal sealed class ResponseAppender : log4net.Appender.TextWriterAppender
        {
            public ResponseAppender():base()
            {
                base.Name = "OnlineResponseAppender";
                base.Layout =
                    new log4net.Layout.PatternLayout()
                    {
                        ConversionPattern = "%message%newline"
                    };
                base.ImmediateFlush = true;
                base.AddFilter(new log4net.Filter.LoggerMatchFilter() { LoggerToMatch = "OnlineResponse", AcceptOnMatch=true });
                base.AddFilter(new log4net.Filter.DenyAllFilter() { });
                InitAppender();
            }


            public void InitAppender()
            {
                base.Writer = new System.IO.StreamWriter(System.Web.HttpContext.Current.Response.OutputStream);
            }
        }

每次需要使用ResponseAppender时,把 HttpContext的Current Response的输出流绑定到 Writer上,就是这么简单。


因为每次web请求时,处理的线程会不同,response使用的是不同的response,所以有必要每个请求都重新绑定一个输出流:

            public void InitAppender()
            {
                base.Writer = new System.IO.StreamWriter(System.Web.HttpContext.Current.Response.OutputStream);
            }

处理过程中,唯一需要注意的是,动态绑定的Logger,是附加在 root上的,hierarchy.Root.AddAppender(responseAppender);  就定义了使输出能够在 Root级的设置中发生作用。如果log4net.xml.cfg 的配置中对 Root 的输出做了限定,如 <<priority value="OFF" />,那么还要打开这个设置为你需要的输出级别:

 hierarchy.Root.Level = log4net.Core.Level.All;

然后从新激活 log4net的配置即可。当然这样有可能会看到一些不需要的输出,或者不是本线程的输出,那么我们还需要在 ResponseAppender中增加一个过滤装置,仅仅出书我们需要调试的内容:

                base.AddFilter(new log4net.Filter.LoggerMatchFilter() { LoggerToMatch = "OnlineResponse", AcceptOnMatch=true });
                base.AddFilter(new log4net.Filter.DenyAllFilter() { });

值得提醒的一点是,这种修改方式是单线程的,只对一个用户的请求有效(static 方法),所以它是 非线程安全的。好在我们仅仅是需要调试,而不是让多个用户来使用。(原文链接 http://ddbiz.com/?p=114)