Отключение трассировки через app.config
Я пытаюсь использовать System.Diagnostics, чтобы сделать некоторые очень простые журналы. Я полагаю, что использовал бы то, что в коробке, вместо того, чтобы брать дополнительную зависимость, такую как Log4Net или EntLib.
Я все настроил, трассировка работает замечательно. Фрагмент кода:
Trace.TraceInformation("Hello World")
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="TraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Trace.log" traceOutputOptions="DateTime" />
<remove name="Default" />
</listeners>
</trace>
</system.diagnostics>
</configuration>
и мой маленький "Hello World" хорошо отображается в моем файле Trace.log. Но теперь я хотел бы отключить трассировку, поэтому я копаюсь в MSDN и нахожу Как: настроить коммутаторы трассировки. Я добавляю <switches>
элемент, и теперь мой app.config выглядит так:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="TraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="Trace.log" traceOutputOptions="DateTime" />
<remove name="Default" />
</listeners>
</trace>
<switches>
<add name="Data" value="0" />
</switches>
</system.diagnostics>
</configuration>
value="0"
следует отключить трассировку - по крайней мере, если вы затем выполните инструкции " Как: создать и инициализировать переключатели трассировки", которая скажет вам добавить эту строку кода:
Dim dataSwitch As New BooleanSwitch("Data", "DataAccess module")
Это не имеет смысла для меня: я просто должен объявить экземпляр BooleanSwicth
уметь управлять (отключать) трассировкой через файл.config? Должен ли я... использовать... объект где-нибудь?
В любом случае, я уверен, что где-то упустил нечто действительно очевидное. Пожалуйста помоги.
Как отключить трассировку в app.config?
5 ответов
Я согласен с рекомендацией @Alex Humphrey попробовать использовать TraceSources. С помощью TraceSources вы получаете больше контроля над тем, как выполняются ваши операторы регистрации / отслеживания. Например, вы могли бы иметь такой код:
public class MyClass1
{
private static readonly TraceSource ts = new TraceSource("MyClass1");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
public class MyClass2
{
private static readonly TraceSource ts = new TraceSource("MyClass2");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
Вызов TraceSource.TraceEvent автоматически проверит уровень сообщения (TraceEventType.Information) относительно настроенного уровня связанного коммутатора и определит, действительно ли сообщение должно быть записано.
Используя разные имена TraceSource для каждого типа, вы можете контролировать ведение журнала из этих классов по отдельности. Вы можете включить ведение журнала MyClass1, или вы можете отключить его, или вы можете включить его, но вести его, только если уровень сообщения (TraceEventType) больше определенного значения (может быть, только журнал "Предупреждение" и выше). В то же время, вы можете включить или отключить вход в MyClass2 или установить уровень, совершенно независимо от MyClass1. Все это включение / отключение / уровень происходит в файле app.config.
Используя файл app.config, вы также можете управлять всеми TraceSources (или группами TraceSources) таким же образом. Таким образом, вы можете настроить так, чтобы MyClass1 и MyClass2 контролировались одним и тем же коммутатором.
Если вы не хотите, чтобы TraceSource имел разные имена для каждого типа, вы можете просто создать один и тот же TraceSource для каждого класса:
public class MyClass1
{
private static readonly TraceSource ts = new TraceSource("MyApplication");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
public class MyClass2
{
private static readonly TraceSource ts = new TraceSource("MyApplication");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
Таким образом, вы можете сделать так, чтобы все журналы в вашем приложении происходили на одном уровне (или были отключены, или использовали тот же TraceListener, или любой другой).
Вы также можете настроить различные части вашего приложения так, чтобы они были независимо конфигурируемыми, не прибегая к "трудностям" определения уникального TraceSource для каждого типа:
public class Analysis1
{
private static readonly TraceSource ts = new TraceSource("MyApplication.Analysis");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
public class Analysis2
{
private static readonly TraceSource ts = new TraceSource("MyApplication.Analysis");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
public class DataAccess1
{
private static readonly TraceSource ts = new TraceSource("MyApplication.DataAccess");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
public class DataAccess2
{
private static readonly TraceSource ts = new TraceSource("MyApplication.DataAccess");
public DoSomething(int x)
{
ts.TraceEvent(TraceEventType.Information, "In DoSomething. x = {0}", x);
}
}
Если ваш класс инструктируется таким образом, вы можете сделать "DataAccess" частью журнала вашего приложения на одном уровне, в то время как часть "Analysis" вашего приложения регистрирует на другом уровне (конечно, можно настроить одну или обе части вашего приложения). так что регистрация отключена).
Вот часть файла app.config, который настраивает TraceSources и TraceSwitches:
<system.diagnostics>
<trace autoflush="true"></trace>
<sources>
<source name="MyClass1" switchName="switch1">
<listeners>
<remove name="Default"></remove>
<add name="console"></add>
</listeners>
</source>
<source name="MyClass2" switchName="switch2">
<listeners>
<remove name="Default"></remove>
<add name="console"></add>
</listeners>
</source>
</sources>
<switches>
<add name="switch1" value="Information"/>
<add name="switch2" value="Warning"/>
</switches>
<sharedListeners>
<add name="console"
type="System.Diagnostics.ConsoleTraceListener">
</add>
<add name="file"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="trace.txt">
</add>
</sharedListeners>
</system.diagnostics>
Как вы можете видеть, вы можете настроить один TraceSource и один коммутатор, и вся регистрация будет происходить с одним уровнем управления (то есть вы можете отключить всю регистрацию или сделать ее запись на определенном уровне).
Кроме того, вы можете определить несколько TraceSources (и ссылаться на соответствующие TraceSources в вашем коде) и несколько Коммутаторов. Коммутаторы могут использоваться совместно (т. Е. Несколько источников TraceSources могут использовать один и тот же коммутатор).
В конечном итоге, приложив немного больше усилий, чтобы теперь использовать TraceSources и ссылаться на соответствующим образом названные TraceSources в своем коде (т. Е. Определять имена TraceSource логически, чтобы вы могли иметь желаемую степень контроля над входом в приложение), вы получите значительный гибкость в долгосрочной перспективе.
Вот несколько ссылок, которые могут помочь вам с System.Diagnostics по мере продвижения вперед:
.net Диагностика лучшие практики?
Каков наилучший подход к ведению журнала?
Есть ли в.Net TraceSource / TraceListener framework что-то похожее на форматеры log4net?
В ссылках, которые я разместил, часто обсуждается "лучшая" система ведения журналов. Я не пытаюсь убедить вас перейти от System.Diagnostics. Ссылки также, как правило, содержат хорошую информацию об использовании System.Diagnostics, поэтому я разместил их.
Некоторые из опубликованных мной ссылок содержат ссылку на Ukadc.Diagnostics. Это действительно классная надстройка для библиотеки System.Diagnostics, которая добавляет расширенные возможности форматирования, подобно тому, что вы можете сделать с log4net и NLog. Эта библиотека налагает зависимость только для конфигурации на ваше приложение, а не на код или ссылочную зависимость.
Вы не отключаете трассировку глобально таким образом.
Ты должен
1) объявить переключатель и установить его значение:
<switches>
<add name="MySwitch" value="Information"/>
</switches>
2) свяжите этот переключатель с TraceSource, который вы используете:
<sources>
<source name="MySource" switchName="MySwitch"/>
</source>
Таким образом, все, что вы пишете через TraceSource с именем "MySource", фильтруется в соответствии со значением параметра.
Если вы используете статические методы, такие как Trace.Write
Полагаю, вы вообще не можете использовать переключатели, потому что нет TraceSource для применения фильтра.
Если вы хотите отключить трассировку статическими методами, просто удалите все слушатели: <listeners> <clear/> </listeners>
,
Проверяйте состояние dataSwitch всякий раз, когда вам нужно войти, согласно:
http://msdn.microsoft.com/en-us/library/aa984285%28v=VS.71%29.aspx
Тем не менее, это довольно неприятно, когда нужно ставить эти чеки везде. Это причина, по которой вы не хотите просто удалять TraceListener
из коллекции слушателей в app.config?
Кроме того, я бы исследовал использование трассировки.NET 2.0+, которая включает TraceSource
, Новый (er) материал предлагает гораздо более высокую степень конфигурации, и вы можете найти его более подходящим.
Это атрибут switchValue исходного узла:
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Off"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData= "somePath" />
</listeners>
</source>
</sources>
<trace autoflush="true" />
Позднее присоединение к краткой сноске о app.config, на случай, если это спасет пару дней от жизни кого-то там:
Предположим, у вас есть стартовый (.exe) проект A, содержащий класс A, который использует проект B (.dll), содержащий класс B.
ClassB, в свою очередь, использует новый экземпляр TraceSource("classB"). Для его настройки вам нужно изменить app.config или projectA. Настройка app.config проекта B ни к чему не приведет.
Также обратите внимание, что размещение
<system.diagnostics>
Раздел внутри app.config, кажется, вызывает проблемы, если поместить его перед разделом:
<configSections>
или после раздела:
<userSettings>
По крайней мере, в моем случае я получал ошибки, когда пытался разместить его в этих местах в app.config моего проекта. Макет, который работал для меня, был:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
...config sections here if any...
</configSections>
<system.diagnostics>
<trace autoflush="true"/>
<sources>
<source name="classB"
switchName="mySwitch"
switchType="System.Diagnostics.SourceSwitch" >
<listeners>
<clear/>
<add name="textwriterListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="ClassBLog.txt"
traceOutputOptions="DateTime" />
</listeners>
</source>
</sources>
<switches>
<add name="mySwitch" value="Verbose" />
</switches>
</system.diagnostics>
<runtime>
...runtime sections here if any...
</runtime>
<userSettings>
...usersettings sections here if any...
</userSettings>
</configuration>
Попробуйте это простое решение. В примере ниже SomeNoisyLibrary засоряет журнал множеством бесполезных записей. Мы фильтруем их с помощью "когда условие"
https://github.com/NLog/NLog/wiki/When-Filter
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
internalLogFile="../log/MyApplication.log"
autoReload="true" throwExceptions="true">
<targets async="true">
<target xsi:type="File"
name="file"
layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message} ${exception:format=ToString}"
fileName="../log/MyApplication.${processid}.${shortdate}.log" keepFileOpen="false"
maxArchiveFiles="10"
archiveAboveSize="10024000"
archiveEvery="Day"
/>
<target xsi:type="ColoredConsole"
name="console"
layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message}${exception:format=ToString}" />
</targets>
<rules>
<logger name="*" minlevel="Info" writeTo="file,console">
<filters defaultAction='Log'>
<when condition="equals('${logger}','SomeNoisyLibrary')" action="Ignore" />
</filters>
</logger>
</rules>
</nlog>