也用 Log4Net 之将日志记录到数据库的后台实现 (二)

  大家下午好,昨天讲了配置,今天我们讲讲后台实现,在完成了后台实现后,我们才能真正意义上的解决把自定义属性字段值录入到数据库中。

  在开写之前我先着重强调一下,“日志”的概念非常广泛,有错误日志、操作日志、访问日志、事件日志等等。我们并不提倡把所有的日志都记录到数据库,因为这样做没有必要。同时如果日志数据表与业务表同在一个数据库的话,频繁的记录日志的操作会影响性能(Log4Net提供了缓存机制,可以在缓存日志数据达到设定值,比如200条时,Log4Net会批量将数据录入到数据库中。即便是这么好的机制,我还是建议大家一定要分清情况,一般错误日志和事件日志我们采用文件形式记录,相应的操作日志我们可以采用数据库记录)。

  “通用日志记录系统” 的重点是通用。能适应各种要求,比如要提供丰富的日志记录形式(如:文件、数据库等等),以及适应不同的业务需求,比如A业务希望记录A1,A2,A3字段,B业务希望记录B1,B2,B3字段。同时还要做到灵活性,能适应业务变更。Log4Net正是这样的一种开源框架,说了这么多,我想表述的是:数据库记录日志的方式并不是唯一的和最好的,大家一定在酌情而定。

  好了,言归正传,我们现在开始讲后台的处理代码:

  (1)、日志对象,就是在存放日志的载体:

public class LogMessage
{
public int UserID { get; set; }
}

  

  在项目中 LogMessage 充当日志对象,大家一定很奇怪,为什么我的只有一个属性UserID。原因是我在测试自定义属性能不能记录到日志数据库中,所以弄太多的属性也没必要。

  Log4Net在将日志记录到数据库时会提供一些缺省的属性,他们分别是:

[Id] [int] IDENTITY (1, 1) NOT NULL,       
[Date] [datetime]  NULL,        --异常记录时间
[Thread] [varchar] (255)  NULL, --线程ID(数字)
[Level] [varchar] (50)  NULL,   --日志级别(FALAT,ERROR,WARN,INFO,DEBUG)
[Logger] [varchar] (255)  NULL,  --记录的类
[Message] [varchar] (4000) NULL,   --消息

  这些缺省值我们最好在每个日志表里都加上,我测试的时候自行把 Message给删除了,结果怎么也记录不进去日志。所以我建议大家把这几个都带了。字段名字你可以自己改,比如,我就把Date改成了RecordTime,但是在配置文件中,RecordTime字段对应的值依然是@log_date,忘记了的同学回上一篇中去看配置去。

  

  (2)、CustomLayout 类

  CustomLayout 类继承至 log4net.Layout.PatternLayout

  关于Layout大家应该不陌生,“Layout 组件用于向用户显示最后经过格式化的输出信息。输出信息可以以多种格式显示,主要依赖于我们采用的Layout组件类型。可以是线性的或一个XML文件。Layout组件和一个Appender组件一起工作。API帮助手册中有关于不同Layout组件的列表。一个Appender对象,只能对应一个Layout对象。要实现你自己的Layout类,你需要从log4net.Layout.LayoutSkeleton类继承,它实现了ILayout接口。”

  因为我们要使用自定义属性UserID,所以我们要实现自己的Layout类,我们来看代码:

public class CustomLayout : log4net.Layout.PatternLayout
{
public CustomLayout()
{
this.AddConverter("UserID", typeof(UserIDPatternConverter));
}
}

  typeof(UserIDPatternConverter)语句中的UserIDPatternConverter实现了格式化的输出信息。

internal sealed class UserIDPatternConverter : PatternLayoutConverter
{
override protected void Convert(TextWriter writer, LoggingEvent loggingEvent)
{
LogMessage logMessage = loggingEvent.MessageObject as LogMessage; if (logMessage != null)
writer.Write(logMessage.UserID);
}
}

  (3)、对Log4Net的简单封装

   public class LogHelper
{
public LogHelper()
{ } public static string LoggerName = string.Empty; private static LogMessage message = null; private static ILog _log; public static ILog log
{
get
{
string path = @"C:\Log4Net.config";
log4net.Config.XmlConfigurator.Configure(new FileInfo(path)); if (_log == null)
{
//从配置文件中读取Logger对象
//WebLogger 里面的配置信息是用来将日志录入到数据库的
//做为扩展 做判断来确定日志的记录形式,数据库也好,txt文档也好,控制台程序也好。
_log = log4net.LogManager.GetLogger(LoggerName); //log4net.LogManager.GetLogger("WebLogger");
}
else
{
if (_log.Logger.Name != LoggerName)
{
_log = log4net.LogManager.GetLogger(LoggerName);
}
} return _log;
}
} /// <summary>
/// 调试
/// </summary>
public static void debug()
{
if (log.IsDebugEnabled)
{
log.Debug(message);
}
} /// <summary>
/// 错误
/// </summary>
public static void error()
{
if (log.IsErrorEnabled)
{
log.Error(message);
}
} /// <summary>
/// 严重错误
/// </summary>
public static void fatal()
{
if (log.IsFatalEnabled)
{
log.Fatal(message);
}
} /// <summary>
/// 记录一般日志
/// </summary>
public static void info( )
{
if (log.IsInfoEnabled)
{
//log.Info("Jerry");
log.Info(message);
}
} /// <summary>
/// 记录警告
/// </summary>
public static void warn()
{
if (log.IsWarnEnabled)
{
log.Warn(message);
}
} /// <summary>
/// 需要写日志的地方调用此方法
/// </summary>
/// <param name="level">自定义级别</param>
public static void SaveMessage(LogMessage logMessage,int level)
{
message = logMessage; switch (level)
{
case 1:
info();
break; case 2:
warn();
break; case 3:
error();
break; case 4:
fatal();
break; default: break;
}
} }

  Log4Net根据不同的日志级别提供了不同的记录方法,对了,这里所说的日志级别就是对应的 Level 字段,我们来看一下 Log4Net的日志级别:

  这是我从别的网站上找到的图,用来说明一下级别。好了,到此为此,我们就已经把 Log4Net 底层这好了,注意,你可以把上页的这些类都统一写到一个类库中。这样做的好处是,当其它项目要用到日志记录功能的时候,直接引用你类库的 dll 就可以了,是不是很方便。同时这样做也实现了对Log4Net的简单封装,让其它项目组的人更易使用。

  重点强调一下,记得在这个类库中引用Log4Net.dll。毕竟我们是要用Log4Net来实现日志记录的,别写了半天都没引用,那就要出问题了。

  (4)、好了,让我们在Web展示层中调用他吧! Default.aspx

protected void Page_Load(object sender, EventArgs e)
{
LogHelper.LoggerName = "WebLogger";
LogMessage logMessage = new LogMessage(); logMessage.UserID = 123456;
LogHelper.SaveMessage(logMessage,1);
}

  因为我们在配置文件中设定了缓存数,<bufferSize value="10"/> 所以你刷新十下,这时候数据就进入到数据库了。不过聪明的做法是,将bufferSize 的value值改为1

  (5)、数据库中的信息

  (6)、对不起,刚才自己看的时候发现没有建表的Sql语句,现在补上。

USE [LogSys]
GO /****** Object: Table [dbo].[Log] Script Date: 08/29/2012 14:56:11 ******/
SET ANSI_NULLS ON
GO SET QUOTED_IDENTIFIER ON
GO SET ANSI_PADDING ON
GO CREATE TABLE [dbo].[Log](
[Id] [int] IDENTITY(1,1) NOT NULL,
[LevelName] [varchar](50) NULL,
[UserID] [int] NULL,
[Message] [varchar](4000) NULL,
[Exception] [varchar](2000) NULL,
[RecordTime] [varchar](50) NULL,
CONSTRAINT [PK_Log_1] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] GO SET ANSI_PADDING OFF
GO

  好了,就写到这里,我是百灵,祝大家天天好心情,身体健康。

最新文章

  1. ASP.NET Core开发-后台任务利器Hangfire使用
  2. 把java对象转化为json格式的对象数组
  3. win2003远程桌面端口修改
  4. ORA-12520: TNS: 监听程序无法为请求的服务器类型找到可用的处理程序
  5. oracle系列--第四篇 Oracle的卸载
  6. [SAP ABAP开发技术总结]OLE
  7. Win10下IIS配置图解、MVC项目发布图解、IIS添加网站图解
  8. CentOS 6下的VPN搭建
  9. 更改maven中央仓库
  10. HTML中的target标记
  11. python入门(Python和Pycharm安装)
  12. redis安装linux(二)
  13. Linux文件系统深度讨论【转】
  14. gitbook build 报错
  15. jQuery自定义数组操作类(类似于List集合的增删改查)
  16. Modify Dokuwiki Email Template 修改 Dokuwiki 邮件模板
  17. GNU与Linux
  18. leetcode ---双指针+滑动窗体
  19. Cuda 9.2 CuDnn7.0 官方文档解读
  20. 【转】多线程Core Data

热门文章

  1. hadoop可能遇到的问题
  2. java开发命名规范总结
  3. 解决.net定时器在iis7上不执行问题
  4. 使用maven 命令运行项目
  5. spring +hibernate 启动优化【转】
  6. html css 如何将表头固定(转)
  7. [转载]mvc使用JsonResult返回Json数据
  8. jquery捕捉文本域输入事件
  9. [转载]jquery cookie的用法
  10. asp 文件上传(ASPUpload组件上传)