将LINQ to SQL DataContext日志消息重定向到Log4Net






4.23/5 (11投票s)
一篇展示如何使用Log4Net捕获LINQ to SQL DataContext类生成的日志消息的文章
引言
当处理 LINQ to SQL 进行 ORM 时,Visual Studio 会自动生成 DataContext
类的子类。这些自动生成的类有一个名为 Log
的属性,类型为 System.IO.TextWriter
。如果将 TextWriter
类型或其子类的对象分配给此属性,则它将使用该实例来写入日志消息。由于 Log4Net 是 .NET 企业级项目中使用最广泛的日志记录库之一,因此在本项目中,我将提供一个通过 Log4Net 日志记录捕获日志消息的解决方案。
背景
在我的项目中,我有一个使用 Log4Net 的成熟的日志记录框架。现在我转移到 LINQ to SQL,我需要获取从 LINQ C# 代码生成的原始 SQL,用于检测和性能目的。从 MSDN,我了解到我需要传递一个 TextWriter
类型的实例来从 DataContext
子类获取日志消息。因此,我最终编写了 TextWriter
的一个子类,名为 LINQLogger
,它封装了使用 Log4Net 记录器的责任,因为它从 DataContext
类接收日志消息。
我希望这篇与我有着类似需求的文章的读者也能在他们的项目中发现它是有用的。
Using the Code
在这篇文章中,我将采用代码描述-代码描述模式,并讨论示例代码的关键部分。请单击顶部的下载链接,获取我为本文编写的示例应用程序的完整源代码。
类图
源代码包含几个接口和类。示例应用程序的类图如下所示

ILogger 接口
我创建了一个包含用于日志记录的方法的接口。此接口允许我提取对 Log4Net 或我正在使用的任何日志记录框架的依赖性。这个简单的接口在以下代码段中呈现
namespace LINQ2Log4Net
{
// An interface for loggers.
public interface ILogger
{
// This method creates a logger for specified class
void CreateLogger(Type loggerType);
// Indexer for setting properties for logging
string this[string propertyName]
{
set;
}
//These methods log in various logging levels
void Debug(string message);
void Fatal(string message);
void Info(string message);
void Error(string message);
void Warn(string message);
}
}
Log4NetLogger : ILogger 类
Log4NetLogger
是接口 ILogger
的一个实现,它在内部使用 Log4Net 进行日志记录。我在我的类中使用了以下代码进行日志记录
namespace LINQ2Log4Net
{
/// <summary>
/// This is an implementation of ILogger interface which uses log4net for logging.
/// </summary>
public class Log4NetLogger : ILogger
{
private ILog log;
public void CreateLogger(Type loggerType)
{
log = LogManager.GetLogger(loggerType);
}
// An implementation of interface indexer for setting logging properties.
public string this[string propertyName]
{
set { ThreadContext.Properties[propertyName] = value; }
}
// An implementation of interface method for logging Debug messages
public void Debug(string message)
{
if (log.IsDebugEnabled)
log.Debug(message);
}
// An implementation of interface method for logging Fatal messages
public void Fatal(string message)
{
if (log.IsFatalEnabled)
log.Fatal(message);
}
// An implementation of interface method for logging Info messages
public void Info(string message)
{
if (log.IsInfoEnabled)
log.Info(message);
}
// An implementation of interface method for logging Error messages
public void Error(string message)
{
if (log.IsErrorEnabled)
log.Error(message);
}
// An implementation of interface method for logging Warning messages
public void Warn(string message)
{
if (log.IsWarnEnabled)
log.Warn(message);
}
}
}
LINQLogger : System.IO.TextWriter 类
正如我在介绍中已经提到的,DataContext
类的 Log
属性的类型是 TextWriter
,我们需要一个 TextWriter.LINQLogger
的子类。我们的子类 LINQLogger
在内部保存对 ILogger
对象的引用,并且当从 DataContext
对象调用 Write
方法时,它会调用记录器上的相应方法来执行日志记录,如下一个代码片段所示
namespace LINQ2Log4Net
{
public class LINQLogger : TextWriter
{
//The ILogger Instance
private ILogger _logger;
public ILogger Logger
{
get { return _logger; }
set { _logger = value; }
}
//The Log level enum
private LogLevelType _logLevelType;
public LogLevelType LogLevel
{
get { return _logLevelType; }
set { _logLevelType = value; }
}
private Encoding _encoding;
public override Encoding Encoding
{
get
{
if (_encoding == null)
{
_encoding = new UnicodeEncoding(false, false);
}
return _encoding;
}
}
public LINQLogger()
{
}
public LINQLogger(ILogger logger, LogLevelType logLevel)
{
_logger = logger;
_logLevelType = logLevel;
}
public override void Write(string value)
{
switch (_logLevelType)
{
case LogLevelType.Fatal: _logger.Fatal(value); break;
case LogLevelType.Error: _logger.Error(value); break;
case LogLevelType.Warn: _logger.Warn(value); break;
case LogLevelType.Info: _logger.Info(value); break;
case LogLevelType.Debug: _logger.Debug(value); break;
}
}
public override void Write(char[] buffer, int index, int count)
{
Write(new string(buffer, index, count));
}
}
public enum LogLevelType
{
Fatal,
Error,
Warn,
Info,
Debug
}
}
SampleDBDataContext 和 Visitor 类
这两个类由 Visual Studio 2008 自动生成,因此我将跳过源代码。但是,从类图中,您可以看到 Visitor
类的属性,我们将在此处将其用于演示目的。
示例用法
在下面的代码片段中,您将看到我到目前为止讨论的类的示例使用场景。关键流程如下
- 初始化
Log4NetLogger
- 使用
Log4NetLogger
和首选的LogLevelType
初始化LINQLogger
- 将
LINQLogger
对象分配给SampleDataContext
的Log
属性 - 通过调用几个 LINQ to SQL 查询来查看日志记录的实际效果
//Initialize the Log4Net from the XML
log4net.Config.XmlConfigurator.Configure();
//Create the logger for this class
ILogger logger = new Log4NetLogger();
logger.CreateLogger(typeof(LINQ2Log4Net.Program));
//Create an instance of the LINQLogger
LINQLogger linqLogger = new LINQLogger(logger, LogLevelType.Debug);
//Set the linqLogger to the log of the DataContext
SampleDBDataContext context = new SampleDBDataContext();
context.Log = linqLogger;
//Run some queries in the context
Visitor visitor = new Visitor { Name = "S M Sohan", Country = "Bangladesh" };
context.Visitors.InsertOnSubmit(visitor);
context.SubmitChanges();
int count = (from v in context.Visitors select v).Count();
Console.WriteLine("Total # of visitors = {0}", count);
免责声明
这篇文章的全部目的是向您展示使用 LINQ to SQL 类实现 Log4Net 日志记录的方法。因此,我故意避免了其他方面,例如异常处理代码,以仅关注目标点。
历史
- 2008 年 5 月 14 日:首次发布