从c#对象中分离日志代码



目前我在c#中有一个自定义构建的静态日志类,可以用以下代码调用:

EventLogger.Log(EventLogger.EventType.Application, string.Format("AddData request from {0}", ipAddress));

当调用它时,它只会写入配置文件中指定的已定义日志文件。

然而,由于我必须记录很多很多事件,我的代码开始变得难以阅读,因为所有的日志消息。

是否有一种既定的方法或多或少地将日志代码从c#类中的对象和方法中分离出来,这样代码就不会变得难以控制?

提前感谢大家的帮助,因为这是我最近一直在努力的事情

我喜欢PostSharp提供的AOP特性。在我看来,登录是任何一种软件的一个方面。日志记录不是应用程序应该提供的主要值。

所以在我的情况下,PostSharp一直都很好。春天。. NET也有一个AOP模块可以用来实现这一点。

我见过的最常用的技术是以这样或那样的形式使用AOP。

PostSharp是一个将IL编织作为AOP形式的产品,尽管不是在。net中实现AOP的唯一方法。

对此的解决方案是使用面向方面的编程,您可以在其中分离这些关注点。这是一个相当复杂/侵入性的改变,所以我不确定它在你的情况下是否可行。

我曾经有一个自定义构建的记录器,但最近更改为TracerX。这提供了一种简单的方法,可以根据不同的严重程度对代码进行检测。可以使用与您正在使用的类等密切相关的名称创建日志记录器

它有一个独立的查看器,具有许多过滤功能,包括日志记录器,严重性等。

http://tracerx.codeplex.com/

这里有一篇关于它的文章:http://www.codeproject.com/KB/dotnet/TracerX.aspx

如果您的主要目标是记录函数进入/退出点以及两者之间的偶然信息,那么我使用Disposable日志对象已经取得了很好的结果,其中构造函数跟踪函数进入,而Dispose()跟踪退出。这允许调用代码简单地将每个方法的代码包装在单个using语句中。还为中间的任意日志提供了方法。下面是一个完整的c# ETW事件跟踪类以及函数入口/退出包装器:

using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace MyExample
{
    // This class traces function entry/exit
    // Constructor is used to automatically log function entry.
    // Dispose is used to automatically log function exit.
    // use "using(FnTraceWrap x = new FnTraceWrap()){ function code }" pattern for function entry/exit tracing
    public class FnTraceWrap : IDisposable
    {
        string methodName;
        string className;
        private bool _disposed = false;
        public FnTraceWrap()
        {
            StackFrame frame;
            MethodBase method;
            frame = new StackFrame(1);
            method = frame.GetMethod();
            this.methodName = method.Name;
            this.className = method.DeclaringType.Name;
            MyEventSourceClass.Log.TraceEnter(this.className, this.methodName);
        }
        public void TraceMessage(string format, params object[] args)
        {
            string message = String.Format(format, args);
            MyEventSourceClass.Log.TraceMessage(message);
        }
        public void Dispose()
        {
            if (!this._disposed)
            {
                this._disposed = true;
                MyEventSourceClass.Log.TraceExit(this.className, this.methodName);
            }
        }
    }
    [EventSource(Name = "MyEventSource")]
    sealed class MyEventSourceClass : EventSource
    {
        // Global singleton instance
        public static MyEventSourceClass Log = new MyEventSourceClass();
        private MyEventSourceClass()
        {
        }
        [Event(1, Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
        public void TraceMessage(string message)
        {
            WriteEvent(1, message);
        }
        [Event(2, Message = "{0}({1}) - {2}: {3}", Opcode = EventOpcode.Info, Level = EventLevel.Informational)]
        public void TraceCodeLine([CallerFilePath] string filePath = "",
                                  [CallerLineNumber] int line = 0,
                                  [CallerMemberName] string memberName = "", string message = "")
        {
            WriteEvent(2, filePath, line, memberName, message);
        }
        // Function-level entry and exit tracing
        [Event(3, Message = "Entering {0}.{1}", Opcode = EventOpcode.Start, Level = EventLevel.Informational)]
        public void TraceEnter(string className, string methodName)
        {
            WriteEvent(3, className, methodName);
        }
        [Event(4, Message = "Exiting {0}.{1}", Opcode = EventOpcode.Stop, Level = EventLevel.Informational)]
        public void TraceExit(string className, string methodName)
        {
            WriteEvent(4, className, methodName);
        }
    }
}

使用它的代码看起来像这样:

public void DoWork(string foo)
{
    using (FnTraceWrap fnTrace = new FnTraceWrap())
    {
        fnTrace.TraceMessage("Doing work on {0}.", foo);
        /*
        code ...
        */
    }
}

为了使代码可读,只记录您真正需要的内容(info/warning/error)。在开发期间记录调试消息,但在完成后删除大部分消息。对于跟踪日志记录,使用AOP来记录简单的事情,比如方法进入/退出(如果你觉得你需要那种粒度)。

的例子:

public int SomeMethod(int arg)
{
   Log.Trace("SomeClass.SomeMethod({0}), entering",arg);  // A
   if (arg < 0)
   {
      arg = -arg;
      Log.Warn("Negative arg {0} was corrected", arg);    // B
   }
   Log.Trace("SomeClass.SomeMethod({0}), returning.",arg);  // C
   return 2*arg;
}

在这个例子中,唯一需要的日志语句是b。日志语句A和C是样板文件,你可以留给PostSharp来为你插入日志。

还有:在你的例子中,你可以看到有某种形式的"Action X被Y调用",这表明你的很多代码实际上可以移动到更高的级别(例如命令/过滤器)。

大量的日志记录语句可以告诉你一些事情:可以使用某种形式的设计模式,它也可以集中大量的日志记录。

void DoSomething(Command command, User user)
{
   Log.Info("Command {0} invoked by {1}", command, user);
   command.Process(user);
}

我认为在ASP中实现类似过滤器的东西是一个很好的选择。净MVC。这是借助属性和反射来实现的。你标记每一个方法,你想以某种方式登录和享受。我想可能会有更好的方法,可能是借助观察者模式或其他东西,但只要我想到它,我就想不出更好的方法。

基本上这样的问题被称为横切关注点,可以在AOP的帮助下解决。

我也认为一些有趣的继承模式可以应用于日志实体的基础,但我想要过滤器

最新更新