Log4Net记录日志到数据库启动24小时后将无法向mysql数据库插入数据

9 篇文章 0 订阅
1 篇文章 0 订阅

最近用Log4Net做成服务把日志记录到MySql数据库可是发现可以个奇怪的的问题,每过一个晚上Log4Net就不会自动向MySql数据库记录日志,后来经过多方面测试发现这个问题主要是Mysql会把空闲8小时(wait_timeout默认值为28800秒)没有操作的数据库连接给主动断开,由于晚上没有操作造成log4net长时间没有记录日志,mysql把数据库连接断开了,到第二天白天开始写日志时由于数据库连接状态部位打开状态而被跳过了记录操作,

在github上下载了log4net的源码发现有一个“ReconnectOnError”的参数意图是在数据库连接异常时是否重新连接,在构造函数中设置了默认值为false错误不重连

解决方案:

方案1、把mysql的wait_timeout设置长一些具体多长根据自己实际需求;
方案2、在log4net的配置文件中添加一行“<param name="ReconnectOnError" value="true"/>”
方案3、下log4net载源码修改掉ReconnectOnError的默认值;

AdoNetAppender代码片段:

public class AdoNetAppender : BufferingAppenderSkeleton
{
    #region Public Instance Constructors

    /// <summary> 
    /// Initializes a new instance of the <see cref="AdoNetAppender" /> class.
    /// </summary>
    /// <remarks>
    /// Public default constructor to initialize a new instance of this class.
    /// </remarks>
    public AdoNetAppender()
    {
        m_connectionType = "System.Data.OleDb.OleDbConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
        m_useTransactions = true;
        m_commandType = System.Data.CommandType.Text;
        m_parameters = new ArrayList();
        m_reconnectOnError = false;
    }

    private bool m_reconnectOnError;
……
    public bool ReconnectOnError
    {
        get { return m_reconnectOnError; }
        set { m_reconnectOnError = value; }
    }
……
    override protected void SendBuffer(LoggingEvent[] events)
    {
        if (m_reconnectOnError && (m_dbConnection == null || m_dbConnection.State != ConnectionState.Open))
        {
            LogLog.Debug(declaringType, "Attempting to reconnect to database. Current Connection State: " + ((m_dbConnection==null)?SystemInfo.NullText:m_dbConnection.State.ToString()) );

            InitializeDatabaseConnection();
            InitializeDatabaseCommand();
        }

        // Check that the connection exists and is open
        if (m_dbConnection != null && m_dbConnection.State == ConnectionState.Open)
        {
            if (m_useTransactions)
            {
                // Create transaction
                // NJC - Do this on 2 lines because it can confuse the debugger
                IDbTransaction dbTran = null;
                try
                {
                    dbTran = m_dbConnection.BeginTransaction();

                    SendBuffer(dbTran, events);

                    // commit transaction
                    dbTran.Commit();
                }
                catch(Exception ex)
                {
                    // rollback the transaction
                    if (dbTran != null)
                    {
                        try
                        {
                            dbTran.Rollback();
                        }
                        catch(Exception)
                        {
                            // Ignore exception
                        }
                    }

                    // Can't insert into the database. That's a bad thing
                    ErrorHandler.Error("Exception while writing to database", ex);
                }
            }
            else
            {
                // Send without transaction
                SendBuffer(null, events);
            }
        }
    }
}




Log4Net配置文件:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
  </configSections>
  <log4net>
    <appender name="AdoNetAppender_Error" type="log4net.Appender.AdoNetAppender">
      <!--BufferSize为缓冲区大小-->
      <bufferSize value="10" />
      <!--指定数据库类型-->
      <param name="ConnectionType" value="MySql.Data.MySqlClient.MySqlConnection, MySql.Data"/>
      <!--数据库连接字符串 -->
      <param name="ConnectionString" value="Server=127.0.0.1;Port=3306;Database=test;Uid=root;Pwd=;CharSet=utf8;"/>
      <!--数据库连接错误时重新连接 -->	  
	  <param name="ReconnectOnError" value="true"/>
      <!--INSERT 语句-->
      <commandText value="INSERT INTO sys_error_log (Date,Thread,Level,Logger,Message,Exception,GUID,OperateUID) VALUES (@LogDate, @thread, @LogLevel, @Logger, @Message, @Exception, @GUID, @OperateUID)" />

      <parameter>
        <parameterName value="@LogDate" />
        <dbType value="DateTime" />
        <layout type="log4net.Layout.RawTimeStampLayout" />
      </parameter>
      <parameter>
        <parameterName value="@Thread" />
        <dbType value="String" />
        <size value="255" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%thread" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@LogLevel" />
        <dbType value="String" />
        <size value="50" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%level" />
        </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="@Message" />
        <dbType value="String" />
        <size value="8000" />
        <layout type="log4net.Layout.PatternLayout">
          <conversionPattern value="%message" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@Exception" />
        <dbType value="String" />
        <size value="8000" />
        <layout type="log4net.Layout.ExceptionLayout" />
      </parameter>
      <parameter>
        <parameterName value="@GUID" />
        <dbType value="String" />
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%property{GUID}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@OperateUID" />
        <dbType value="Int64" />
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%property{OperateUID}" />
        </layout>
      </parameter>


    </appender>

    <!--写文本-->
    <appender name="RollingLogFileAppender_Error" type="log4net.Appender.RollingFileAppender">
      <!--日志文件路径-->
      <param name="File" value="ErrorLog\\" />
      <!--多线程时采用最小锁定-->
      <param name="lockingModel"  type="log4net.Appender.FileAppender+MinimalLock" />
      <!--是否追加到文件,默认为true,通常无需设置-->
      <param name="AppendToFile" value="true" />
      <!--日志文件名是否为静态:true,当前最新日志文件名永远为File节中的名字;false,File+DatePattern-->
      <param name="StaticLogFileName" value="false" />
      <!--日期的格式,每天换一个文件记录,如不设置则永远只记录一天的日志,需设置-->
      <param name="DatePattern" value="yyyy-MM-dd.LOG" />
      <!--变换的形式为日期,这种情况下每天只有一个日志-->
      <!--此时MaxSizeRollBackups和maximumFileSize的节点设置没有意义-->
      <param name="RollingStyle" value="Date" />
      <!--变换的形式为日志大小-->
      <!--这种情况下MaxSizeRollBackups和maximumFileSize的节点设置才有意义-->
      <!--<param name="RollingStyle" value="Size" />-->
      <!--每天记录的日志文件个数,与maximumFileSize配合使用-->
      <!--<param name="MaxSizeRollBackups" value="200" />-->
      <!--每个日志文件的最大大小-->
      <!--可用的单位:KB|MB|GB-->
      <!--不要使用小数,否则会一直写入当前日志-->
      <!--<param name="MaximumFileSize" value="10MB" />-->
      <!--自定义属性-->
      <parameter>
        <parameterName value="@GUID" />
        <dbType value="String" />
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%property{GUID}" />
        </layout>
      </parameter>
      <parameter>
        <parameterName value="@OperateUID" />
        <dbType value="Int64" />
        <layout type="log4net.Layout.PatternLayout">
          <param name="ConversionPattern" value="%property{OperateUID}" />
        </layout>
      </parameter>

      <!--%m(message):输出的日志消息,如ILog.Debug(…)输出的一条消息
      %n(new line):换行
      %d(datetime):输出当前语句运行的时刻
      %r(run time):输出程序从运行到执行到当前语句时消耗的毫秒数
      %t(thread id):当前语句所在的线程ID
      %p(priority): 日志的当前优先级别,即DEBUG、INFO、WARN…等
      %c(class):当前日志对象的名称,例如:
      %f(file):输出语句所在的文件名。
      %l(line):输出语句所在的行号。-->

      <!--日志格式-->
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="
LogDate		Thread		LogLevel		Logger		GUID		OperateUID		Message		Exception
" />
        <param name="Footer" value="
----------------------footer--------------------------
" />
        <param name="ConversionPattern" value="%d   %t    %p    %c    %property{GUID}   %property{OperateUID}   %m%n" />
      </layout>
    </appender>
   
    <logger name="DbErrorLogger">
      <level value="ALL" />
      <appender-ref ref="AdoNetAppender_Error" />
    </logger>
    <logger name="TextErrorLogger">
      <level value="ALL" />
      <appender-ref ref="RollingLogFileAppender_Error" />
    </logger>
  </log4net>
</configuration>


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,针对您的问题,我可以给您提供以下思路: 使用log4j把日志信息保存到数据库,需要进行以下步骤: 1. 创建数据库表,用于存储日志信息。例如: ```sql CREATE TABLE `log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `logger` varchar(255) DEFAULT NULL, `level` varchar(50) DEFAULT NULL, `message` text, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ``` 2. 创建Java项目,导入log4j和mysql的依赖。 3. 在log4j.properties文件中配置log4j的输出方式为JDBCAppender。例如: ```properties log4j.rootLogger=debug, db log4j.appender.db=org.apache.log4j.jdbc.JDBCAppender log4j.appender.db.URL=jdbc:mysql://localhost:3306/test log4j.appender.db.driver=com.mysql.jdbc.Driver log4j.appender.db.user=root log4j.appender.db.password=root log4j.appender.db.sql=INSERT INTO log(logger, level, message) VALUES('%c', '%p', '%m') ``` 其中,URL、driver、user、password是连接数据库的参数,sql是插入日志信息的SQL语句。 4. 在Java代码中使用log4j输出日志信息。例如: ```java import org.apache.log4j.Logger; public class TestLog { private static final Logger logger = Logger.getLogger(TestLog.class); public static void main(String[] args) { logger.debug("debug message"); logger.info("info message"); logger.warn("warn message"); logger.error("error message"); logger.fatal("fatal message"); } } ``` 运行程序后,log4j会自动将日志信息插入数据库表中。 以上就是使用log4j把日志信息保存到数据库的一般思路,希望对您有所帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值