log4net配置写入文本和写入数据库(sqlserver-sqlclient,mysql-odbc) 传入自定义业务对象...

在项目中需要记录业务日志(即用户进行了什么操作,操作什么内容,什么时候,操作内容以结构化的方式存储,以方便以后数据挖掘)。

系统已经采用了log4net来记录文本日志(一般用来记录应用程序错误和我们自己认为需要的提示信息,如“正在解析第i条xml数据...”,当前执行的sql,之类的供开发自己看的信息)。我想既然用了它来记录文本,那就再用它来记录业务日志到数据库吧,反正在log4net中加个Appender就可以。

由于业务需要记录的并不是简单的系统时间%date,级别%level,信息%message等字段,而是自定义的业务字段。发现记日志的info,error,debug等方法可以传入object参数:log.info(object message)。于是到网上查找它是不是象我预想的这样,传一个自定义的业务日志对象给info方法,它自动帮我得到该业务对象的字段的值。

找了半天,答案是:没有。

仔细想了下,难道别人都不这样用吗?我为什么要传入自定义业务对象?要记录的业务操作都是info级别的,根据级别优先级别(由高到低为OFF,FATAL, ERROR,WARN,INFO,DEBUG,ALL),开发时,级别要不定义为debug,要不为all,发布后设置为info。如果同时开启文本和AdoNetAppender,那么除了一些业务操作会进入该日志表,其它只给我自己看的info级别的信息,如前所说的当前执行的sql等信息也会试图存入该表,当然这些是直接传入一句提示信息,所以存入数据库中时,所有字段可能都会是空的。

这样的局面也太尴尬了吧。

这样来讲,似乎log4net并不适合记录这种业务日志。除非有两个非不干涉的log4net。各记录各的日志。

虽然看起来已经没有什么必要,但还是自己做出了解决方案。

下面把配置方式及传入自定义业务对象的解决方案附上。

一、log4net针对sqlserver,mysql及文本的配置方式:

(注:如果配置写入数据库,需要将System.Data.dll拷到bin目录下。)

文本和sqlserver-sqlclient连接库:

ContractedBlock.gif ExpandedBlockStart.gif Code
<configuration>
  
<!-- Register a section handler for the log4net section -->
  
<configSections>
    
<!--<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />-->
    
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
  
</configSections>
  
<!-- This section contains the log4net configuration settings -->
  
<log4net>
    
<root>
      
<level value="All" />
      
<appender-ref ref="RollingFileAppender"/>
      
      
<appender-ref ref="AdoNetAppender"/>
    
</root>

    
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender" >
      
<file value="testlog.txt" />
      
<appendToFile value="true" />
      
<maxSizeRollBackups value="10" />
      
<maximumFileSize value="100" />
      
<rollingStyle value="Date" />
      
<datePattern value="yyyy-MM-dd"/>
      
<staticLogFileName value="true" />
      
<layout type="log4net.Layout.PatternLayout">
        
<conversionPattern value="%-5level %date %logger - %message%newline" />
      
</layout>
    
</appender>

    
    
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">

      
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data" />
      
<connectionString value="data source=arlenpc\arlenserver;database=testdb;user id=sa;password=111;integrated security=false;persist security info=True;" />
      
<commandText value="INSERT INTO test_log([LogTime],[level],Content) VALUES (@LogTime,@level,@Content)" />
      
<parameter>
        
<parameterName value="@LogTime" />
        
<dbType value="DateTime" />
        
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" />
      
</parameter>

      
<parameter>
        
<parameterName value="@level" />
        
<dbType value="String" />
        
<size value="50" />
        
<layout type="log4net.Layout.PatternLayout" value="%level" />
      
</parameter>

      
<parameter>
        
<parameterName value="@Content" />
        
<dbType value="String" />
        
<size value="1000" />
        
<layout type="log4net.Layout.PatternLayout" value="%message" />
      
</parameter>

 

mysql-odbc方式连接库:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
<connectionType value="System.Data.Odbc.OdbcConnection, System.Data" />
    
<connectionString value="DRIVER={MySQL ODBC 3.51 Driver};SERVER=服务器ip地址;DATABASE=数据库名;UID=用户名;PASSWORD=密码;OPTION=3" />
    
<commandText value="INSERT INTO ads_log(LogTime,Operator) VALUES (?,?)" />
    
<parameter>
      
<parameterName value="@LogTime" />
      
<dbType value="DateTime" />
      
<layout type="log4net.Layout.PatternLayout" value="%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}" />
    
</parameter>

 

调用代码:

ContractedBlock.gif ExpandedBlockStart.gif Code
static void Main(string[] args)
        {
            log4net.Config.XmlConfigurator.Configure();

            log4net.ILog log 
= log4net.LogManager.GetLogger(typeof(Program));
            
            log.Error(
"test-log4net");

            log.Info(
"log4net测试");
           
        }

 

二、log.info(object messageObject)传入自定义对象

比如说插入数据库时需要将该业务操作的原因也记录,假设数据库中该字段名称为Reason。

1.自定义一个业务对象,LogContent

 

ContractedBlock.gif ExpandedBlockStart.gif Code
public class LogContent
    {
        
public LogContent(string reason)
        {
            _Reason 
= reason;
        }

        
private string _Reason;
        
public string Reason
        {
            
get { return _Reason; }
            
set { _Reason = value; }
        }

        
    }

 

2.自定义一个Layout(在该类的构造方法中将自定义的Converter加进去,以处理property{}中的自定义字段)和一个PatternConverter:

ContractedBlock.gif ExpandedBlockStart.gif Code
public class MyLayout : PatternLayout
    {
        
public MyLayout()
        {
            
this.AddConverter("property"typeof(MyMessagePatternConverter));
        }
    }

public class MyMessagePatternConverter : PatternLayoutConverter
    {
        
protected override void Convert(System.IO.TextWriter writer, log4net.Core.LoggingEvent loggingEvent)
        {
            
if (Option != null)
            {
                
// Write the value for the specified key
                WriteObject(writer, loggingEvent.Repository, LookupProperty(Option, loggingEvent));
            }
            
else
            {
                
// Write all the key value pairs
                WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
            }
            
//if (Option != null)
            
//{
            
//    // Write the value for the specified key
            
//    WriteObject(writer, loggingEvent.Repository, loggingEvent.LookupProperty(Option));
            
//}
            
//else
            
//{
            
//    // Write all the key value pairs
            
//    WriteDictionary(writer, loggingEvent.Repository, loggingEvent.GetProperties());
            
//}
        }

        
/// <summary>
        
/// 通过反射获取传入的日志对象的某个属性的值
        
/// </summary>
        
/// <param name="property"></param>
        
/// <returns></returns>
        private object LookupProperty(string property, log4net.Core.LoggingEvent loggingEvent)
        {
            
object propertyValue = string.Empty;
            
            PropertyInfo propertyInfo 
= loggingEvent.MessageObject.GetType().GetProperty(property);
            
if(propertyInfo != null)
                propertyValue 
= propertyInfo.GetValue(loggingEvent.MessageObject, null);
            
            
return propertyValue;
        }

 

3.配置文件中相应节点:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
<parameter>
        
<parameterName value="@Reason" />
        
<dbType value="String" />
        
<size value="100" />
        
<layout type="Component.MyLayout, Component" >
          
<param name="ConversionPattern" value="%property{Reason}"/>
        
</layout>
      
</parameter>

 

4.调用代码:

 

ContractedBlock.gif ExpandedBlockStart.gif Code
            log.Info(new LogContent("reason-because"));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值