Как я могу добавить Trace () для каждого вызова метода в C #? - PullRequest
26 голосов
/ 18 февраля 2009

Мне трудно отследить проблему блокировки, поэтому я хотел бы регистрировать вход и выход каждого вызова метода. Я делал это раньше с C ++ без необходимости добавлять код для каждого метода. Это возможно с C #?

Ответы [ 7 ]

19 голосов
/ 18 февраля 2009

Вероятно, вам лучше всего использовать AOP (аспектно-ориентированное программирование) для автоматического вызова кода трассировки до и после выполнения метода. Популярным выбором для AOP и .NET является PostSharp .

3 голосов
/ 01 января 2014

Если ваша основная цель состоит в том, чтобы регистрировать точки входа / выхода функции и случайную информацию между ними, у меня были хорошие результаты с Одноразовым регистрирующим объектом, где конструктор отслеживает функцию запись и 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 голосов
/ 18 февраля 2009

Профилировщик отлично подходит для просмотра вашего работающего кода во время разработки, но если вы ищете возможность создавать собственные трассировки в производственном процессе, то, как отметил Денис Г., PostSharp - идеальный инструмент : вам не нужно менять весь ваш код, и вы можете легко включить / выключить его.

Его также легко настроить за несколько минут, и у Gaël Fraiteur, создателя PostSharp, даже есть видеоролики, показывающие, как легко добавить трассировку в существующее приложение.
Примеры и учебные пособия вы найдете в разделе документации .

2 голосов
/ 18 февраля 2009

Используйте ANTS Profiler от Red Gate. В противном случае посмотрите на перехватчики в Castle Windsor . Это предполагает, что вы загружаете ваши типы через IoC.

Отражение - это еще один способ, вы можете использовать методы System.Reflection.Emit для «записи» кода в память. Этот код может заменить код вашего метода и выполнить его, но с соответствующей регистрацией. Удачи в этом, хотя ... Проще было бы использовать фреймворк Aspect Oriented Programming, как Aspect # .

1 голос
/ 24 апреля 2009

Возможно, ожидание решения проблемы блокировки, создание дампа памяти и анализ стека вызовов в различных потоках. Вы можете использовать DebugDiag или сценарий adplus (в данном случае режим зависания), который поставляется с Средствами отладки для Windows .

У Тесс Феррандез также есть превосходная лабораторная серия по обучению отладке различных проблем с использованием дампов памяти .NET. Я настоятельно рекомендую это.

0 голосов
/ 09 октября 2009

если у вас возникла проблема тупика, проверьте http://www.codeproject.com/KB/dotnet/Deadlock_Detection.aspx

0 голосов
/ 18 февраля 2009

Откуда ты знаешь, что это происходит? Если это многопоточное приложение, я бы порекомендовал протестировать условие и вызывать System.Diagnostics.Debugger.Break () во время выполнения при его обнаружении. Затем просто откройте окно «Потоки» и прокрутите стеки вызовов в каждом соответствующем потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...