log4net 扩展自己的PatternLayout

  log4net中提供了一些常用的pattern string,如:%m为输出日志信息,%n为输出一新行。  
  但有时我们也需要记录一些其它的常用信息,如用户的id、ip、浏览器信息、agent等,这个时候便可以通过继承log4net原生的PatternLayout来实现一些自定义的扩展。

  以浏览器信息为例,以下我们扩展一个记录浏览器信息的PatternConverter:  

  1. 新建一个HttpRequestPatternConverter,继承自log4net的PatternLayoutConverter,作为我们将pattern string转换为http请求相关信息的基类
    public abstract class HttpRequestPatternConverter : PatternLayoutConverter
    {
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            try
            {
                if (HttpContext.Current.Session != null)
                {
                    HttpConvert(writer, loggingEvent, HttpContext.Current);
                }
                else
                {
                    writer.Write("-");
                }
            }
            catch (HttpException) {}
        }

        protected abstract void HttpConvert(TextWriter writer, LoggingEvent loggingEvent, HttpContext currentContext);

    }

  
2.新建一个BrowserPatternConverter,继承自HttpRequestPatternConverter,并改写方法HttpConvert,在该方法中记录浏览器信息

    public class BrowserPatternConverter : HttpRequestPatternConverter
    {
        protected override void HttpConvert(TextWriter writer, LoggingEvent loggingEvent, HttpContext currentContext)
        {
            var request = currentContext.Request;
            writer.Write(request.Browser.Browser + " " + request.Browser.Version);
        }
    }

  在上面的实现中记录了浏览器的名称和版本号
  
3. 新建一个HttpPatternLayout,继承自log4net的PatternLayout,通过构造方法扩展上面实现的BrowserPatternConverter

    public class HttpPatternLayout: PatternLayout
    {
        public HttpPatternLayout() : base()
        {
            //todo:: here extend pattern layout
            AddConverter("browser", typeof(BrowserPatternConverter));
        }
    }

4.使用扩展的PatternLayout配置log4net输出浏览器信息

  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="AdoNetAppender" />
      <appender-ref ref="TraceAppender" />
    root>
    <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
      <layout type="Common.Tool.Extend.Log4Net.PatternLayout.HttpPatternLayout">
        <conversionPattern value="%n记录时间:%d  线程ID:[%t]%n日志级别:%-5p  记录类:%c%n浏览器 : %browser%nUrl Referrer : %url_referrer%nUrl : %url%n会话ID : %session_id%n日志信息:%m%n%n" />
      layout>
    appender>
  log4net>

  在这里我配置的是TraceAppender,输出日志到vs的输出窗口。
  注意此时使用的layout type要使用扩展后的HttpPatternLayout,才能成功对扩展的pattern layout进行解析处理。
  
5. 查看结果
  log4net 扩展自己的PatternLayout_第1张图片

Q: PatternConverter是什么
A: 在log4net中,%m%n之类的占位符称之为pattern string,这些string在解析后都会有一个对应的PatternConverter进行处理,将之转换为所需的信息。

Q: 为什么需要基类HttpRequestPatternConverter
A: 因为在如果并非在外部请求的线程中调用log4net时(如在mvc的app_start中),获取HttpRequest会报一个异常,所以先判断HttpContext的Session是否为null,如果为null,则将pattern string统一转换为”-“;不为null,则执行子类实现的HttpConvert将pattern string转换为所需信息。如果这一判断放在子类中直接完成,势必造成很多重复的代码。

Q: 为什么在TacPatternLayout的构造函数中扩展PatternConverter,AddConverter方法又是哪里来的
A: log4net存储Converter定义了两个字段,分别是s_globalRulesRegistry和m_instanceRulesRegistry。前者是静态字段,用于存储log4net本身定义的一些全局PatternConverter,我们没有办法进行修改(除非改源码);后者是实例字段,是log4net提供给我们扩展PatternConverter的字段,AddConverter方法正是log4net提供给我们操作这个字段的接口。因此我们只需在TacPatternLayout的构造方法中调用AddConverter即可以扩展PatternConverter。

Q: Converter的name为browser,为什么使用时写的是%browser
A: 在log4net中,解析pattern string时都是以%[converter_name]的形式进行解析的,所以如果定义了Converter的name为browser,配置时便要写成%browser

你可能感兴趣的:(log4net,log4net,Pattern,Converter)