Объяснение log4net Добавление
SocketThreadWorker
выбрасывает SocketException
.Сообщение об исключении «Существующее соединение было принудительно закрыто удаленным узлом» отображается с помощью кода ошибки .
throw new SocketException(10054);
Код, создающий инструкцию log, выглядит как необработанное исключениеобработчик (сообщением выдается «Неожиданное исключение ...»).Но, для этого ответа, представьте, что это выглядит так
try
{
...
}
catch (Exception e)
{
_log.Error("Unexpected exception in SocketThreadWorker", e);
}
Что log4net производит под прикрытием, это LoggingEvent
.Он содержит предоставленное сообщение журнала и объект исключения (отдельно).Каждый аппендер может решить, как записать эти два элемента в их конечные пункты назначения (наряду с другими свойствами, параметрами макета и т. Д.).
Фильтр StringToMatch
работает только с сообщением журнала.Не в сообщении об исключении!Посмотрите этот код ниже, мы создадим систему и тест, который поможет нам отладить проблему
Воспроизведение и глубокое погружение
Вот простой класс выброса исключений сокета
public class SocketThreadWorker
{
public void DoWork()
{
throw new SocketException(10054);
}
}
Мы настроим log4net на использование ConsoleAppender
с фильтром совпадения строк, соответствующим строке сообщения об исключении.
public static class LocalLoggingConfiguration
{
public static void Configure()
{
var filter = new StringMatchFilter
{
StringToMatch = "An existing connection was forcibly closed by the remote host",
AcceptOnMatch = false,
};
var appender = new ConsoleAppender
{
Layout = new SimpleLayout()
};
appender.AddFilter(filter);
BasicConfigurator.Configure(appender);
}
}
Мы настроим log4net, получим регистратор и сделаем неудачный вызовв тесте.Вы заметите несколько операторов журнала на других уровнях и еще один на Error
, которые не будут соответствовать нашему фильтру (если он работает).Таким образом, мы можем быть уверены, что не случайно потеряем всех сообщений.
[TestClass]
public class SocketLibraryTest
{
private readonly ILog _log = LogManager.GetLogger(typeof(SocketLibraryTest));
public SocketLibraryTest()
{
LocalLoggingConfiguration.Configure();
}
[TestMethod]
public void CatchThatPeskyException()
{
_log.Debug("Testing...");
try
{
new SocketThreadWorker().DoWork();
}
catch (Exception e)
{
_log.Info("An exception!");
_log.Error("Unexpected exception in SocketThreadWorker", e);
_log.Error("It wasn't that bad.");
}
}
}
Вывод этого теста в моей среде включает исключение в отдельной строке изсообщение, потому что, по умолчанию, appender будет печатать объект исключения таким образом.
DEBUG - Testing...
INFO - An exception!
ERROR - Unexpected exception in SocketThreadWorker
System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host
at SO5894291.SocketThreadWorker.DoWork() in d:\users\anthony.mastrean\documents\Projects\SO5894291\SO5894291\SocketLibraryTest.cs:line 16
at SO5894291.SocketLibraryTest.CatchThatPeskyException() in d:\users\anthony.mastrean\documents\Projects\SO5894291\SO5894291\SocketLibraryTest.cs:line 58
ERROR - It wasn't that bad.
Если вы измените фильтр appender, чтобы он соответствовал части другого сообщения, вы увидите, что ононастроен правильно и работает.Измените строку для соответствия на «Тестирование», и вы увидите, что оператор DEBUG
исчезает из вывода консоли!
Рекомендации
Вы не хотите совпадать в общем сообщении журнала "Неожиданное исключение ... ».Это имеет шанс потерять сообщения.Даже введение фильтра совпадений в логгере не поможет, потому что этот рабочий сокет, вероятно, может и будет выдавать другие исключения (опять же, потенциально потерянные сообщения).
Единственный вариант, который я могу придумать, - реализовать свой собственный ExceptionMessageToMatchFilter
.Я скопировал реализацию StringToMatchFilter
, заменив обработанную строку сообщения на сообщение об исключении.
public class ExceptionMessageToMatchFilter : StringMatchFilter
{
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
if (loggingEvent == null)
throw new ArgumentNullException("loggingEvent");
if (loggingEvent.ExceptionObject == null)
return FilterDecision.Neutral;
var exceptionMessage = loggingEvent.GetExceptionString();
if (m_regexToMatch != null)
{
if (!m_regexToMatch.Match(exceptionMessage).Success)
return FilterDecision.Neutral;
return m_acceptOnMatch ? FilterDecision.Accept : FilterDecision.Deny;
}
if (m_stringToMatch == null || exceptionMessage.IndexOf(m_stringToMatch) == -1)
{
return FilterDecision.Neutral;
}
return m_acceptOnMatch ? FilterDecision.Accept : FilterDecision.Deny;
}
}
Я был бы осторожен с вызовом GetExceptionString()
, не знаю, может ли он вернутьсяnull
.Или что вы хотите сделать, если нет сообщения (оно пустое? Вы должны вернуть нейтральное значение или продолжить сопоставление?).
Довольно легко настроить вашу конфигурацию log4net (особенно потому, что она имеет все свойстваиз строки, соответствующей фильтру).
<filter type="MyNamespace.ExceptionMessageToMatchFilter, MyAssembly">
<stringToMatch value="An existing connection was forcibly closed by the remote host" />
<acceptOnMatch value="false" />
</filter>