65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.23/5 (11投票s)

2008年5月14日

CPOL

3分钟阅读

viewsIcon

171516

downloadIcon

306

一篇展示如何使用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 对象分配给 SampleDataContextLog 属性
  • 通过调用几个 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 日:首次发布
© . All rights reserved.