前言
为了实践项目驱动的
ExtAspNet开发过程,最近我启动了另外一个开源项目 -
AppBox。
AppBox项目使用ExtAspNet作为前台展现层,SubSonic作为ORM层,SqlServer2005作为数据库,在Asp.Net2.0基础之上实现一个企业综合管理系统所必须的基础组件。
包括用户管理,菜单管理,权限管理,组织结构管理等各个部分,虽然AppBox不是给最终用户使用的,但是可以作为开发人员搭建网站的一个框架,同时在项目中遇到的控件会优先在ExtAspNet中实现。
由于在AppBox中使用了log4net作为日志记录组件,所以这篇文章就来分享一下log4net的配置和使用。
log4net配置
1. 首先到 http://logging.apache.org/ 下载最新的log4net v1.2.10。
2. 建立数据库表
CREATE TABLE [dbo].[Log] (
[Id] [int] IDENTITY (1, 1) NOT NULL,
[Date] [datetime] NOT NULL,
[Thread] [varchar] (255) NOT NULL,
[Level] [varchar] (50) NOT NULL,
[Logger] [varchar] (255) NOT NULL,
[Message] [varchar] (4000) NOT NULL,
[Exception] [varchar] (2000) NULL
)
3. 在网站根目录添加log4net.config文件
<log4net>
<root>
<level value="ALL"/>
<appender-ref ref="AdoNetAppender"/>
<appender-ref ref="RollingFileAppender"/>
</root>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender,log4net">
<param name="File" value="log\log.config"/>
<param name="AppendToFile" value="true"/>
<param name="MaxSizeRollBackups" value="10"/>
<param name="MaximumFileSize" value="5MB"/>
<param name="RollingStyle" value="Size"/>
<param name="StaticLogFileName" value="true"/>
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n"/>
</layout>
</appender>
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="0"/>
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089"/>
<connectionString value="Password=sa;Persist Security Info=True;User ID=sa;Initial Catalog=AppBox;Data Source=."/>
<commandText value="insert into X_Log(DATETIME,THREAD,LOG_LEVEL,LOGGER,MESSAGE,EXCEPTION) values (@log_date,@thread,@log_level,@logger,@message,@exception)"/>
<parameter>
<parameterName value="@log_date"/>
<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="@log_level"/>
<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="4000"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message"/>
</layout>
</parameter>
<parameter>
<parameterName value="@exception"/>
<dbType value="String"/>
<size value="2000"/>
<layout type="log4net.Layout.ExceptionLayout"/>
</parameter>
</appender>
</log4net>
注:这里我们使用了两种类型的日志记录方式,文件和数据库。
文件保存在网站根目录下的 log\log.config ,必须保证Asp.Net服务进程对此文件夹有写权限,否则不能写入文件并且没有任何提示。
比如在WindowXP下需要设置 ASPNET (Windows2003不是这个名称,可以Google一下) 对此文件夹的写权限。
同时注意我们使用log.config而不是log.txt,是为了防止匿名用户非法下载系统日志。
在数据库配置上也有个小技巧,我们设置了 bufferSize value="0",也就是说产生一条日志就写到数据库。
我刚开始也是在这个地方遇到麻烦,设置bufferSize为10,刚开始怎么也观察不到日志插入数据库,后来才知道被缓存了。
不要在多处定义数据库连接字符串
因为我们已经在Web.config中定义了数据库连接字符串:
<connectionStrings>
<clear/>
<add name="Default" connectionString="Password=sa;Persist Security Info=True;User ID=sa;Initial Catalog=AppBox;Data Source=."/>
</connectionStrings>
因此如果在log4net.config中再定义数据库连接字符串,总觉得不爽。
经过在网上一番搜索,居然发现log4net v1.2.10不支持这个Asp.Net2.0的特性,不过
这篇文章给出了一个解决方法。
我们需要在AppBox中添加一个CS文件:
using System;
using System.Collections.Generic;
using System.Web;
using log4net;
using log4net.Appender;
using System.Configuration;
namespace AppBox
{
/// <summary>
/// http://issues.apache.org/jira/browse/LOG4NET-88
/// An appender for Log4Net that uses a database based on the connection string name.
/// </summary>
public class Log4NetConnectionStringNameAdoNetAppender : AdoNetAppender
{
private static ILog _Log;
/// <summary>
/// Gets the log.
/// </summary>
/// <value>The log.</value>
protected static ILog Log
{
get
{
if (_Log == null)
_Log = LogManager.GetLogger(typeof(Log4NetConnectionStringNameAdoNetAppender));
return _Log;
}
}
private string _ConnectionStringName;
/// <summary>
/// Initialize the appender based on the options set
/// </summary>
/// <remarks>
/// <para>
/// This is part of the <see cref="T:log4net.Core.IOptionHandler"/> delayed object
/// activation scheme. The <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> method must
/// be called on this object after the configuration properties have
/// been set. Until <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> is called this
/// object is in an undefined state and must not be used.
/// </para>
/// <para>
/// If any of the configuration properties are modified then
/// <see cref="M:log4net.Appender.AdoNetAppender.ActivateOptions"/> must be called again.
/// </para>
/// </remarks>
public override void ActivateOptions()
{
PopulateConnectionString();
base.ActivateOptions();
}
/// <summary>
/// Populates the connection string.
/// </summary>
private void PopulateConnectionString()
{
// if connection string already defined, do nothing
if (!String.IsNullOrEmpty(ConnectionString)) return;
// if connection string name is not available, do nothing
if (String.IsNullOrEmpty(ConnectionStringName)) return;
// grab connection string settings
ConnectionStringSettings settings = ConfigurationManager
.ConnectionStrings[ConnectionStringName];
// if connection string name was not found in settings
if (settings == null)
{
// log error
if (Log.IsErrorEnabled)
Log.ErrorFormat("Connection String Name not found in Configuration: {0}",
ConnectionStringName);
// do nothing more
return;
}
// retrieve connection string from the name
ConnectionString = settings.ConnectionString;
}
/// <summary>
/// Gets or sets the name of the connection string.
/// </summary>
/// <value>The name of the connection string.</value>
public string ConnectionStringName
{
get { return _ConnectionStringName; }
set { _ConnectionStringName = value; }
}
}
}
然后修改log4net.config文件:
<appender name="AdoNetAppender" type="AppBox.Log4NetConnectionStringNameAdoNetAppender">
<bufferSize value="0"/>
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=2.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089"/>
<connectionStringName value="Default"></connectionStringName>
........
........
</appender>
注意,在log4net.config中我们指定使用名为 Default 的连接字符串。
使用log4net
调用方法倒很简单,比如在登录页面:
private static readonly log4net.ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected void btnSubmit_Click(object sender, EventArgs e)
{
// ....
logger.Info(String.Format("用户 - {0} - 登录成功", tbxUserName.Text));
}
生成log记录类似:
2009-08-19 18:05:37,932 [11] INFO AppBox._default [(null)] - 用户 - admin - 登录成功