Должен ли TraceSource быть защищен операторами if?

Следует ли проверять "Уровень трассировки" перед отправкой самой трассировки перед трассировкой в ​​TraceSource?

var ts = new TraceSource("foo");
ts.Switch.Level = SourceLevels.Warning;
if (/* should there be a guard here? and if so, what? */) {
    ts.TraceEvent(TraceEventType.Warning, 0, "bar");
}

Пока есть SourceSwitch.ShouldTrace(TraceEventType), документация указывает

Код приложения не должен вызывать этот метод; он предназначен для вызова только методами в классе TraceSource.

Похоже, что модель pre-TraceSource использовала класс TraceSwitch (не SourceSwitch), который имел различные TraceXYZ методы (для этой цели?), но такие, как представляется, не нужны / не используются / не упоминаются в модели TraceSource.

(Наличие защиты вне метода trace влияет на оценку выражений, используемых в / для вызова - конечно, побочные эффекты или вычислительно дорогостоящие операции в таких случаях являются "плохими" и "опрометчивыми", но я все же хотел бы сосредоточиться на основной вопрос.)

4 ответа

Решение

Я знаю, что в NLog вы, как правило, просто выполняете трассировку на любом уровне, который хотите, и он позаботится о том, должен ли отслеживаться уровень журнала или нет.

Мне кажется, что TraceSource работает так же.

Поэтому я бы сказал "Нет", вы, вероятно, не должны проверять.

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

Я думаю, что с точки зрения производительности, вы, как правило, в порядке, если используете методы, определенные в классе:

Основано на примере: http://msdn.microsoft.com/en-us/library/sdzz33s6.aspx

Это хорошо:

ts.TraceEvent(TraceEventType.Verbose, 3, "File {0} not found.", "test");

Это было бы плохо

string potentialErrorMessageToDisplay = string.Format( "File {0} not found.", "test" );
ts.TraceEvent(TraceEventType.Verbose, 3, potentialErrorMessageToDisplay );

В первом случае библиотека, вероятно, избегает вызова string.Format, если уровень ошибки все равно не будет записан. Во втором случае всегда вызывается string.Format.

По подсчетам дорогих параметров трассировки я придумал следующее:

internal sealed class LazyToString
{
    private readonly Func<object> valueGetter;

    public LazyToString(Func<object> valueGetter)
    {
        this.valueGetter = valueGetter;
    }

    public override string ToString()
    {
        return this.valueGetter().ToString();
    }
}

Использование будет

traceSource.TraceEvent(TraceEventType.Verbose, 0, "output: {0}", new LazyToString(() =>
{
    // code here would be executed only when needed by TraceSource
    // so it can contain some expensive computations
    return "1";
}));

Есть идея получше?

Являются ли строки, которые вы передаете аргументу сообщения, дорогими? Константа или литерал довольно дешевы. Если это так, не беспокойтесь об этом, используйте переключатели трассировки / фильтры прослушивателя трасс и т. Д., Чтобы уменьшить количество обработанной трассировки (и стоимость выполнения трассировки) (Кстати, прослушиватель трассировки по умолчанию очень дорог, всегда очистите слушателей трассировки перед добавлением желаемых)

System.Diagnostics не имеет ничего, чтобы сделать неактивный вызов TraceSource бесплатным. Даже если вы используете фильтры прослушивателя или установите переключатель трассировки в ноль (выключите его), TraceEvent будет вызван и будет создана строка сообщения.

Представьте, что строка трассировки дорогая для вычисления, например, она перебирает все строки в наборе данных и выгружает их в строку. Это может занять нетривиальное количество миллисекунд.

Чтобы обойти это, вы можете сделать часть построения строки обернутой в функцию, которая имеет условный атрибут, чтобы отключить ее в режиме выпуска, или использовать метод-обертку, который принимает лямбда-выражение или Func, который создает строку (и не выполняется) когда не нужно)

Как предполагает @nexuzzz, могут быть ситуации, когда вычисление параметра события стоит дорого. Вот что я мог придумать.

Совет разработчикам: "Если у вас нет строкового аргумента, используйте лямбда-версию TraceInformation или TraceWarning.

public class TraceSourceLogger : ILogger
{
    private TraceSource _traceSource;

    public TraceSourceLogger(object that)
    {
        _traceSource = new TraceSource(that.GetType().Namespace);
    }

    public void TraceInformation(string message)
    {
        _traceSource.TraceInformation(message);
    }

    public void TraceWarning(string message)
    {
        _traceSource.TraceEvent(TraceEventType.Warning, 1, message);
    }

    public void TraceError(Exception ex)
    {
        _traceSource.TraceEvent(TraceEventType.Error, 2, ex.Message);
        _traceSource.TraceData(TraceEventType.Error, 2, ex);
    }

    public void TraceInformation(Func<string> messageProvider)
    {
        if (_traceSource.Switch.ShouldTrace(TraceEventType.Information))
        {
            TraceInformation(messageProvider());
        }
    }

    public void TraceWarning(Func<string> messageProvider)
    {
        if (_traceSource.Switch.ShouldTrace(TraceEventType.Warning))
        {
            TraceWarning(messageProvider());
        }
    }
}
Другие вопросы по тегам