利用Log4Net将日志插入至oracle数据库!

本文介绍了如何配置log4net将日志信息写入Oracle数据库,包括建立数据库、设置连接字符串,以及如何插入系统默认字段和自定义字段。在实现过程中需要注意引用Oracle的数据访问库,并确保项目的.NET版本正确,因为log4net在调用Oracle时错误不直接显示,调试较为困难。

log4net可以轻易的将信息日志写入文本,但是无论记录在哪里终究还是为了后期发现问题,维护所用。所以为了查询方便,可以将其配置输出至数据库(oracle)。

一、插入系统默认字段

首先建库,sql如下:

-- Create table
create table SYSTEMLOG
(
  log_id        NUMBER not null,
  log_date      DATE,
  log_level     VARCHAR2(255),
  log_identity  VARCHAR2(255),
  log_message   VARCHAR2(4000),
  log_exception VARCHAR2(4000),
  log_logger    VARCHAR2(255),
  log_source    VARCHAR2(1000),                                                                                                                           )                                                                                                                                                           -- Create sequence 
create sequence SYSTEMLOG_SEQ
minvalue 1
maxvalue 999999999
start with 8061
increment by 1
cache 20;
以上所有字段(除了log_id)均为系统字段,字段的定义可以看配置文件,如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <log4net>
    <configSections>
      <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
    </configSections>
    <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
      <bufferSize value="1" />
      <connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.111.7.20, Culture=neutral, PublicKeyToken=89b483f429c47342" />
      <connectionString value="Data Source=//59.74.137.215:1521/GSGLAQYJ;User ID=GSGLAQYJ;Password=GSGLAQYJ;" />
      <commandText value="INSERT INTO LOG4NET (LOG_ID, LOG_DATE, LOG_LEVEL, LOG_IDENTITY, LOG_MESSAGE, LOG_EXCEPTION, LOG_LOGGER, LOG_SOURCE) VALUES (LOG4NET_SEQ.nextval, :log_date, :log_level, :log_identity, :log_message, :log_exception, :logger, :source)" />
      <parameter>
        <parameterName value=":log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout">
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_level" />
        <dbType value="String" />
        <size value="10" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_identity" />
        <dbType value="String" />
        <size value="100" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%identity" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%m" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_exception" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%exception" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":source" />
        <dbType value="String" />
        <size value="1000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%file:%line" />
        </layout>
      </parameter>
    </appender>
    <appender name="InfoAppender" 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".log"" />
      <param name="RollingStyle" value="Date" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%n日志时间:%d [%t] %n日志级别:%-5p %n日 志 类:%c [%x] %n%m %n" />
      </layout>
    </appender>
    
    <!--<logger name="loginfo">
      <level value="INFO" />
      <appender-ref ref="InfoAppender" />
    </logger>-->
    <root>
      <level value="All"/>
      <appender-ref ref="ADONetAppender" />
      <appender-ref ref="InfoAppender" />
    </root>
  </log4net>
</configuration>


以上配置文件最主要的就是一下几行:

 <connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.111.7.20, Culture=neutral,                                  PublicKeyToken=89b483f429c47342" />
      <connectionString value="Data Source=//xx.xx.xx.xx:1521/xxx;User ID=xxx;Password=xxx;" />
      <commandText value="INSERT INTO 
SYSTEMLOG (LOG_ID, LOG_DATE, LOG_LEVEL, LOG_IDENTITY, LOG_MESSAGE, LOG_EXCEPTION, LOG_LOGGER, LOG_SOURCE) VALUES                                                 (LOG4NET_SEQ.nextval, :log_date, :log_level, :log_identity, :log_message, :log_exception, :logger, :source)" />


1.Oracle.DataAccess.dll

就好比你自己写sql语句一样,无论那种数据库都得引一个XXXclient的库,后面的公钥要写对,查询一个dll的公开密钥可以先打开vs的命令工具,将dll放入命令工具的当前目录下,然后输入SN -T 回车即可获得公钥.

2.Oracle.DataAccess.Client.OracleConnection

这个就不用说了,肯定是连接数据库的字符串,网上好多格式都不对,这里我贴出了详细的格式

 <connectionString value="Data Source=//xx.xx.xx.xx:1521/xxx;User ID=xxx;Password=xxx;" />
3.插入语句

<commandText value="INSERT INTO 
SYSTEMLOG (LOG_ID, LOG_DATE, LOG_LEVEL, LOG_IDENTITY, LOG_MESSAGE, LOG_EXCEPTION, LOG_LOGGER, LOG_SOURCE) VALUES
(LOG4NET_SEQ.nextval, :log_date, :log_level, :log_identity, :log_message, :log_exception, :logger, :source)" />

一定要注意变量的个数要一致,oracle变量默认以冒号开头。
4.其他配置

其他配置与写入文件的配置一样,可以参考上一篇,没有特别提出的都是在上篇的配置基础上继续进行的。

最后,调用代码如下:

 class Program
    {
        private static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        
        static void Main(string[] args)
        {
                log.Info("我");
                log.Warn("你");
                log.Debug("他");
                log.Error("她");
                log.Fatal("它");        
                Console.ReadLine();
        }
    }

结果如下图:



注意事项:

项目需要log4net.dll,和其对应的.config和xml文件,并且需要引入上面的Oracle.DataAccess.dll,若没有oracle客户端,则就需要将pl/sql中的几个必备库拷贝至debug目录才能执行成功。所需库文件已上传http://download.csdn.net/detail/kkkkkxiaofei/6436383

二、插入自定义字段

sql如下:

-- Create table
create table SYSTEMLOG
(
  log_id        NUMBER not null,
  log_date      DATE,
  log_level     VARCHAR2(255),
  log_identity  VARCHAR2(255),
  log_message   VARCHAR2(4000),
  log_exception VARCHAR2(4000),
  log_logger    VARCHAR2(255),
  log_source    VARCHAR2(1000),
  loginid       VARCHAR2(100),
  loginname     VARCHAR2(100),
  menuname      VARCHAR2(100),
  actionname    VARCHAR2(100),
  remark        VARCHAR2(1000),
  terminalno    VARCHAR2(30),
  orderno       VARCHAR2(10)
)
-- Create sequence 
create sequence SYSTEMLOG_SEQ
minvalue 1
maxvalue 999999999
start with 8061
increment by 1
cache 20;


插入自定义字段需要继承log4net里的基类,先看配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler, log4net" />
  </configSections>
  <log4net>

    <logger name="RollingLogFileAppender">
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />
    </logger>

    <logger name="AdoNetAppender_Oracle">
      <level value="ALL" />
      <appender-ref ref="AdoNetAppender_Oracle" />
    </logger>

    <logger name="WarningDatail_Oracle">
      <level value="ALL" />
      <appender-ref ref="WarningDatail_Oracle" />
    </logger>

    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <!--日志的路径-->
      <file value="./GSGLAQYJLOG/ExecuteInfo.log" />
      <!--是否覆盖,默认是追加true-->
      <appendToFile value="true" />
      <!--按照文件的大小进行变换日志文件-->
      <rollingStyle value="Size" />
      <!--按照日期变换文件名称
      <rollingStyle value="Date" />
      <datePattern value="yyyyMMdd-HHmm'.log'" />
      -->
      <!--设置无限备份=-1 ,最大备份数为1000-->
      <maxSizeRollBackups value="-1" />
      <!--每个文件的最大2M-->
      <maximumFileSize value="2MB" />
      <!--日志文件名是否为静态-->
      <staticLogFileName value="false" />
      <!--输出文件格式-->
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%d [%t] %-5p %c [%x] - %m [%r]%n" />
      </layout>
      <!--輸出文件格式説明:
         %d      输出当前语句运行的时刻
         %t      当前语句所在的线程
         %-数字:表示该项的最小长度,如果不够,则用空格填充
         %p      日志的当前优先级别,即DEBUG、INFO<、WARN…等
         %m      输出的日志消息,如ILog.Debug(…)>输出的一条消息
         %n      换行
         %r      運行的時間  
         %c      当前日志对象的名称
      -->
      <!--Log4net 多线程写入-->
      <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    </appender>

    <!--日志记录数据库-->
    <appender name="AdoNetAppender_Oracle" type="log4net.Appender.AdoNetAppender">
      <bufferSize  value="1"/>
      <!--<connectionType value="System.Data.OracleClient.OracleConnection, System.Data.OracleClient, Version=4.0.30319.1, Culture=neutral, PublicKeyToken=b77a5c561934e089" />-->
      <connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.111.7.20, Culture=neutral, PublicKeyToken=89b483f429c47342" />
      <connectionString value="DATA SOURCE=//59.74.137.215:1521/GSGLAQYJ;USER ID=GSGLAQYJ;PASSWORD=GSGLAQYJ"/>
      <!--<commandText value="INSERT INTO LOG4NET (LOG_ID, LOG_DATE, LOG_LEVEL, LOG_IDENTITY, LOG_MESSAGE, LOG_EXCEPTION, LOG_LOGGER, LOG_SOURCE) VALUES (LOG4NET_SEQ.nextval, :log_date, :log_level, :log_identity, :log_message, :log_exception, :logger, :source)" />-->
      <commandText value="INSERT INTO SYSTEMLOG (LOG_ID, LOG_DATE,LOG_LEVEL,LOG_IDENTITY,LOG_MESSAGE,LOG_EXCEPTION,LOG_LOGGER,LOG_SOURCE,LOGINID,LOGINNAME,MENUNAME,ACTIONNAME,REMARK) VALUES 
                          (SYSTEMLOG_SEQ.nextval,:log_date,:log_level,:log_identity,:log_message,:log_exception,:logger,:source,:LoginID,:LoginName,:MenuName,:ActionName,:Remark)" />
      <parameter>
        <parameterName value=":log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value=":log_level" />
        <dbType value="String" />
        <size value="10" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_identity" />
        <dbType value="String" />
        <size value="100" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%identity" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_message" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%m" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":log_exception" />
        <dbType value="String" />
        <size value="4000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%exception" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":logger" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%logger" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":source" />
        <dbType value="String" />
        <size value="1000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%file:%line" />
        </layout>
      </parameter>
      <!--自定义属性-->
      <parameter>
        <parameterName value=":LoginID" />
        <dbType value="String" />
        <size value="100" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%LoginID" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":LoginName" />
        <dbType value="String" />
        <size value="100" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%LoginName" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":MenuName" />
        <dbType value="String" />
        <size value="100" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%MenuName" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":ActionName" />
        <dbType value="String" />
        <size value="100" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%ActionName" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":Remark" />
        <dbType value="String" />
        <size value="1000" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%Remark" />
        </layout>
      </parameter>
    </appender>
    <appender name="WarningDatail_Oracle" type="log4net.Appender.AdoNetAppender">
      <bufferSize  value="1"/>
      <connectionType value="Oracle.DataAccess.Client.OracleConnection, Oracle.DataAccess, Version=2.111.7.20, Culture=neutral, PublicKeyToken=89b483f429c47342" />
      <connectionString value="DATA SOURCE=//59.74.137.215:1521/GSGLAQYJ;USER ID=GSGLAQYJ;PASSWORD=GSGLAQYJ"/>
      <commandText value="INSERT INTO SYSTEMLOG (LOG_ID, LOG_DATE,TERMINALNO,ORDERNO) VALUES (SYSTEMLOG_SEQ.nextval,:log_date,:terminalno,:orderno)" />
      <parameter>
        <parameterName value=":log_date" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <!--自定义属性:-->
      <parameter>
        <parameterName value=":terminalno" />
        <dbType value="String" />
        <size value="30" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%TerminalNo" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":orderno" />
        <dbType value="String" />
        <size value="10" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%OrderNo" />
        </layout>
      </parameter>
    </appender>

  </log4net>
</configuration>
配置文件定义了三个节点

<logger name="RollingLogFileAppender">
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />
    </logger>

    <logger name="AdoNetAppender_Oracle">
      <level value="ALL" />
      <appender-ref ref="AdoNetAppender_Oracle" />
    </logger>

    <logger name="WarningDatail_Oracle">
      <level value="ALL" />
      <appender-ref ref="WarningDatail_Oracle" />
    </logger>
每一个logger就相当一个root(上面插入系统字段时用的是root,两者都行),一个logger对应一个appender,分别是:

写入文本的节点:

<logger name="RollingLogFileAppender">
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender" />
    </logger>
写入数据库的字段(一部分自定义字段):

<logger name="AdoNetAppender_Oracle">
      <level value="ALL" />
      <appender-ref ref="AdoNetAppender_Oracle" />
    </logger>
写入数据库的字段(另一部分自定义字段)

 <logger name="WarningDatail_Oracle">
      <level value="ALL" />
      <appender-ref ref="WarningDatail_Oracle" />
    </logger>
其中自定义字段分两个节点是因为最后一个节点是在warn级别时才记录入库,而前者在info级别就入库了,这么做有利于分开处理。到时候插入库的时候也会发现插入前者时后者为空,而插入后者时前者也为空。

自定义节点如下:

 <!--自定义属性:-->
      <parameter>
        <parameterName value=":terminalno" />
        <dbType value="String" />
        <size value="30" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%TerminalNo" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value=":orderno" />
        <dbType value="String" />
        <size value="10" />
        <layout type="Log4netHandler.CustomLayout">
          <conversionPattern value="%OrderNo" />
        </layout>
      </parameter>
以第一个节点为例,插入时的变量为:terminalno,在重写的类里,该变量是做为属性TerminalNo出现的,其实就是将类里的TerminalNo利用反射转换为oracle所能识别的变量:terminalno

代码如下:

1.实现该属性的类

 internal sealed class TerminalNo : PatternLayoutConverter
    {
        // Methods
        protected override void Convert(TextWriter writer, LoggingEvent loggingEvent)
        {
            LogContent content = loggingEvent.MessageObject as LogContent;
            if (content != null)
            {
                writer.Write(content.TerminalNo);
            }
        }
    }

其他几个变量一样,都需要继承PatterLayoutConverter

2.反射

namespace Log4netHandler
{
     public class CustomLayout:PatternLayout
    {
        // Methods
        public CustomLayout()
        {
           
            base.AddConverter("TerminalNo", typeof(TerminalNo));
           
        }

    }
}
再看上面自定义属性时的配置文件,里面有一行
 <layout type="Log4netHandler.CustomLayout">
这时看到这个类想必就应该有所领悟了吧.

3.封装节点

public class OperaterLog
    {
        // Fields
        private static ILog logfile;
        private static ILog logoracle;
        private static ILog logwaring;

        // Methods
        public static ILog Login2File()
        {
            return (logfile = LogManager.GetLogger("文件节点"));
        }

        public static ILog Login2Oracle()
        {
            return (logoracle = LogManager.GetLogger("数据库节点1"));
        }

        public static ILog LoginWarning()
        {
            return (logwaring = LogManager.GetLogger("数据库节点2"));
        }
    }
4.调用

 class Program
    { 
        static void Main(string[] args)
        { 
           Log4netHandler.LogContent msg = new Log4netHandler.LogContent();
           msg.LoginID = "OutSocket_LoginID";
           msg.LoginName = "OutSocket_LoginName";
           msg.MenuName = "OutSocket_MenuName";
           msg.ActionName = "OutSocket_ActionName";
           msg.Remark = "12312";
           msg.TerminalNo = "空123";
           msg.OrderNo = "空2323";
           Log4netHandler.OperaterLog.Login2Oracle().Info(msg);
           Log4netHandler.OperaterLog.Login2File().Info("12312");
           Log4netHandler.OperaterLog.LoginWarning().Info(msg);
           Console.Read();
           }
        }
    }

5.结果如下



如上面所说,插入第一部分自定义字段时后面两个为空,插入后面两个时前面也为空,这些都取决于封装的时候读取的节点。最后要说明一下,整个调试过程十分恶心,无论是出现任何错误,用Log4Net调用oracle时都不报错,所以必须十分小心,记得把项目类型换成.net 4,不然会吐血的。再次吐槽CSDN的排版,蛋疼。。

























评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值