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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/559148/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 08:08:55  来源:igfitidea点击:

How can I add a Trace() to every method call in C#?

c#loggingtrace

提问by Jon Tackabury

I am having a hard time tracking down a lock issue, so I would like to log every method call's entry and exit. I've done this before with C++ without having to add code to every method. Is this possible with C#?

我很难追踪锁定问题,所以我想记录每个方法调用的进入和退出。我以前用 C++ 做过这件事,而不必向每个方法添加代码。这可以用 C# 实现吗?

采纳答案by Dennis G.

Probably your best bet would be to use an AOP (aspect oriented programming) framework to automatically call tracing code before and after a method execution. A popular choice for AOP and .NET is PostSharp.

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

回答by Neil Barnwell

Use ANTS Profilerfrom Red Gate would be your best bet. Failing that, look into interceptorsin Castle Windsor. That does assume you're loading your types via IoC though.

使用Red Gate 的ANTS Profiler将是您最好的选择。如果做不到这一点,看看拦截温莎城堡。不过,这确实假设您正在通过 IoC 加载您的类型。

Reflection is another way, you can use the System.Reflection.Emitmethods to "write" code into memory. That code could replace your method's code, and execute it but with appropriate logging. Good luck on that one, though... Easier would be to use an Aspect Oriented Programming framework like Aspect#.

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

回答by Robert Venables

How do you know that it's happening? If this is a multithreaded application, i would recommend testing for the condition and calling System.Diagnostics.Debugger.Break() at runtime when it's detected. Then, simply open up the Threads window and step through the call stacks on each relevant thread.

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

回答by Renaud Bompuis

A profiler is great for looking at your running code during development but if you're looking for the ability to do custom traces in production, then, as Denis G. mentionned, PostSharpis the perfect tool: you don't have to change all your code and you can easily switch it on/off.

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

It's also easy to set-up in a few minutes and Ga?l Fraiteur, the creator of PostSharp even has videos that shows you how easy it is to add tracing to an existing app.
You will find examples and tutorials in the documentation section.

几分钟内设置也很容易,PostSharp 的创建者 Ga?l Fraiteur 甚至有视频向您展示向现有应用程序添加跟踪是多么容易。
您将在文档部分找到示例和教程。

回答by Richard Szalay

It might be waiting for the lock issue to take hold, doing a memory dump and analysing the call stack on various threads. You can use DebugDiagor the adplus script (hang mode, in this case) that comes with Debugging Tools for Windows.

它可能正在等待锁定问题发生,进行内存转储并分析各种线程上的调用堆栈。您可以使用DebugDiagWindows 调试工具附带的 adplus 脚本(在本例中为挂起模式)。

Tess Ferrandezalso has an excellent lab serieson learning to debug various issues using .NET memory dumps. I highly recommend it.

Tess Ferrandez还有一个关于学习使用 .NET 内存转储调试各种问题的优秀实验室系列。我强烈推荐它。

回答by Eric C. Berridge

If your primary goal is to log function entry/exit points and occasional information in between, I've had good results with an Disposablelogging object where the constructor traces the function entry, and Dispose() traces the exit. This allows calling code to simply wrap each method's code inside a single usingstatement. Methods are also provided for arbitrary logs in between. Here is a complete C# ETW event tracing class along with a function entry/exit wrapper:

如果您的主要目标是记录函数入口/出口点和中间的偶尔信息,我使用Disposable日志对象取得了不错的结果,其中构造函数跟踪函数 entry,而Dispose() 跟踪 exit。这允许调用代码将每个方法的代码简单地包装在单个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);
        }
    }
}

Code that uses it will look something like this:

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

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