2009-08-28 2 views
9

Я в основном хочу написать logger/tracer клиента, который также регистрирует имя класса и метода метода, вызывающего logger/tracer. Это должно быть быстрым, чтобы оно не влияло на производительность приложения, строго набиралось и очищалось. У кого-нибудь есть хорошие идеи?Каков наиболее эффективный способ регистрации имени класса и метода?

Вот несколько я имел, но я беспокоюсь о производительности из-за отражения: (? Слишком много накладных расходов)

  • StackTrace/StackFrame

  • MethodInfo.GetCurrentMethod() (все еще слишком медленно? и не очень чистый) метод

  • проход в качестве делегата (C# можно сделать это неявно и у меня есть доступ к MethodInfo, но не очень чистый)

Я ценю чьи-либо комментарии.

UPDATE:

мне понравилась cleanless из StackFrame поэтому я задал более конкретный вопрос here в отношении производительности StackFrame, и я получил некоторые действительно хороший ответ, включая тесты производительности. Оказывается, что MethodInfo.GetCurrentMethod() является самым быстрым (занимает около 1 микросекунды на моем компьютере) и new StackFrame(1) можно запросить по запросу (занимает около 15-20 микросекунд на моем компьютере). Я выбрал метод как вариант делегирования, поскольку он слишком запутан, когда метод имеет несколько параметров.

ВЫВОД:

Я смотрел на все варианты и лучше всего написать специальный плагин для PostSharp, который впрыскивает имя метода в виде строки в MSIL во время компиляции при применении пользовательского атрибута, как [Trace]. На мой взгляд, это самый быстрый и удобный вариант. Это даже позволяет намного больше вещей, например, передавать имена параметров и аргументы без каких-либо отражений, а также исключать и регистрировать исключения. Это my related question для получения дополнительной информации.

+0

Могу ли я спросить, почему вы не хотите использовать log4net? – nWorx

+0

Мне не нравится слишком полагаться на другие компоненты. А также в случае log4net это слишком сложно. – 2009-08-28 20:44:09

+2

Германн, это, как правило, упоминается в нашей отрасли как «не придуманный здесь синдром», и его лучше всего избегать. Вот ссылка на Википедию с дополнительной информацией об этом несчастье: http://en.wikipedia.org/wiki/Not_Invented_Here –

ответ

3

Проще говоря, самый быстрый способ сделать это статически во время компиляции:

public void DoSomething() 
{ 
    TraceCall("DoSomething"); 
} 

public void TraceCall(string methodName) 
{ 
    if (!tracingEnabled) { return; } 
    // Log the call 
} 

, то вопрос, по существу, такой же, как ваш предыдущий вопрос; Каков наилучший способ сделать это в удобном и точном месте? Варианты времени выполнения, которые мы обсуждали ранее, относились к относительно серьезному результату, но компромисс заключается в том, что их можно легко реализовать.

Как уже упоминалось в предыдущей теме, это начинает склоняться к Аспектно-ориентированному программированию; PostSharp - одна из таких библиотек, которая может помочь найти баланс статически скомпилированной производительности при простом обслуживании.

+0

Вы правы. Надеюсь, это не займет слишком много усилий, чтобы реализовать это с помощью PostSharp. Я думаю, это зависит от потребностей каждого человека, но я бы не назвал 20 микросекунд серьезным ударом. – 2009-08-28 20:49:43

+0

@ Hermann: если вы не пишете что-то, что должно обрабатывать пропускную способность Google, 20 мс совершенно небрежно. Тесты, которые мы сделали в другом вопросе, показывали, что если вам нужно инициировать протоколирование вызовов на 100 000 методов, это добавит - самое большее - 1,5 секунды. Независимо от того, что некоторые методы значительно быстрее других, все методы являются маргинальными в конце дня. – STW

2

Когда вы уже находитесь внутри метода (или если вы перехватываете метод), я не думаю, что вы можете сделать намного лучше, чем MethodInfo.GetCurrentMethod - что не слишком ужасно быстро - если вы хотите остаться в типе -безопасно.

Поскольку вы хотите сделать это для ведения журнала, считаете ли вы это в асинхронной операции, чтобы не замедлить основной поток?

В зависимости от нагрузки, уже имеющейся в вашем приложении, она может или не поможет.

+0

Да, я тоже об этом думал. Но что происходит, когда приложение занято? Разве это не отложит журнал и не будет ли он потерян при сбое приложения? – 2009-08-28 11:24:59

+0

Зависит от того, как вы выполняете операцию async. Если вы просто бросите его на ThreadPool, тогда да, вы правы, и заказ не гарантируется. Тем не менее, вы также можете записать его в MSMQ, что может дать вам постоянное ведение журнала. –

+1

Опция async только облегчит запись в журнал (что может быть полезно). Фактический вызов GetCurrentMethod все равно будет налагать штраф за производительность на основной поток. – STW

0

Лучший способ сделать это во время компиляции: C++ традиционно использовал символы препроцессора ____FILE____ и ____LINE____ в макросах для этого. К сожалению, компилятор C# не предлагает макросов или эквивалентов ____FILE____ и ____LINE____ на данный момент.

Это эффективно означает, что ваш единственный вариант заключается в том, чтобы регистрировать эту информацию во время выполнения, что означает либо утомительное добавление ручной трассировки для каждого метода, который вы хотите зарегистрировать, либо с помощью нажатия отражения, как вы описали.

0

Думаю, Log4PostSharp очень хорошо справится с этой задачей.

+0

Я не хочу использовать другой регистратор, особенно не что-то, основанное на log4net, но я вообще), как идея вводящий код MSIL. Мне нужно научиться, если я смогу это использовать. – 2009-08-28 11:27:37

+0

Чтение ответа Сть - это займет ок. один час для разработки эквивалента __FILE__ и __LINE__ с использованием PostSharp (или __TYPE__ и __METHOD__). Ну, 1 час мне. –

+0

Я посмотрю PostSharp. Спасибо, Гаэль! – 2009-08-28 15:41:34

0

Если речь идет о скорости, то фактическое сообщение журнала должно быть создано с использованием Event Tracing for Windows. ETW - это высокоскоростная библиотека регистрации, реализованная в качестве драйвера, доступного как из режима ядра, так и из режима пользователя. Трассировка может быть динамически включена и выключена. Ведение журнала добавляет очень мало накладных расходов на приложение. Я использовал ETW для реализации трассировки в высокопроизводительных серверных приложениях. Отъезд NTrace.

4

Самый быстрый способ сделать это во время компиляции, это правда, но самый удобный способ сделать это в .NET через использование CallerMemberName, CallerFilePath и другие службы составитель атрибуты incroduced в .NET 4.5:

public void TraceMethodCall([CallerMemberName]string methodName) 
{ 
}