如何在C#中的每个方法调用中添加Trace()?

时间:2009-02-17 23:12:22

标签: c# logging trace

我很难跟踪锁定问题,所以我想记录每个方法调用的进入和退出。我以前用C ++完成了这个,而不必为每个方法添加代码。这可能与C#?

有关

7 个答案:

答案 0 :(得分:19)

可能你最好的选择是使用AOP(面向方面​​编程)框架在方法执行之前和之后自动调用跟踪代码。 AOP和.NET的流行选择是PostSharp

答案 1 :(得分:3)

分析器非常适合在开发过程中查看正在运行的代码,但如果您正在寻找能够在生产中执行自定义跟踪的功能,那么,正如Denis G.所提到的,PostSharp是完美的工具:您不必更改所有代码,您可以轻松打开/关闭它。

在几分钟内设置也很容易,而PostSharp的创建者GaëlFraiteur甚至还有一些视频,向您展示向现有应用添加跟踪是多么容易。
您可以在documentation section中找到示例和教程。

答案 2 :(得分:3)

如果您的主要目标是记录功能进入/退出点以及两者之间的偶然信息,我使用一次性日志记录对象获得了良好的结果,其中 构造函数跟踪功能输入 Dispose()跟踪退出 。这允许调用代码简单地将每个方法的代码包装在单个使用语句中。还为其间的任意日志提供了方法。这是一个完整的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 ...
        */
    }
}

答案 3 :(得分:2)

使用Red Gate的ANTS Profiler将是您最好的选择。如果不这样做,请查看interceptors中的Castle Windsor。这确实假设你通过IoC加载你的类型。

反射是另一种方式,您可以使用System.Reflection.Emit方法将代码“写入”内存。该代码可以替换您的方法的代码,并执行它但具有适当的日志记录。祝你好运......但更容易使用面向方面的编程框架,如Aspect#

答案 4 :(得分:1)

它可能正在等待锁定问题占用,进行内存转储并分析各种线程上的调用堆栈。您可以使用DebugDiag附带的Debugging Tools for Windows或adplus脚本(在这种情况下为挂起模式)。

Tess Ferrandez还有excellent lab series学习使用.NET内存转储调试各种问题。我强烈推荐它。

答案 5 :(得分:0)

你怎么知道它正在发生?如果这是一个多线程应用程序,我建议测试条件并在检测到时在运行时调用System.Diagnostics.Debugger.Break()。然后,只需打开Threads窗口并逐步浏览每个相关线程上的调用堆栈。

答案 6 :(得分:0)

如果您遇到死锁问题,请查看http://www.codeproject.com/KB/dotnet/Deadlock_Detection.aspx