最近用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>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)