Как сопоставить сообщение с новой строкой в ​​log4net с фильтром stringToMatch? - PullRequest
10 голосов
/ 05 мая 2011

У меня проблемы с настройкой StringMatchFilter для соответствия строка в сообщении с символами новой строки. Я хочу пропустить некоторые сообщения, и я добавили фильтр, как это, и он работает.

<filter type="log4net.Filter.StringMatchFilter">
  <param name="AcceptOnMatch" value="false" />
  <stringToMatch value="Unexpected exception in SocketThreadWorker" />
</filter>

Но если я изменю stringToMatch на "Существующее соединение было принудительно закрывается удаленным хостом ", который происходит во втором ряду сообщение фильтр не работает. Это из-за перевода строки в сообщение или я здесь что-то не так делаю?

Типичное сообщение может выглядеть так:

------ Пример сообщения ----------------------------

2011-05-04 16:22:24,078 [Client (connected from "127.0.0.1:4076" at 16:22)] ERROR - Unexpected exception in SocketThreadWorker System.Net.Sockets.SocketException:
An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)

------ Завершить пример сообщения ---------------------------

«Неожиданное исключение в SocketThreadWorker» находится в первой строке сообщения, а «Существующее соединение было принудительно закрыто» - во второй строке.

Редактировать

Аппендер выглядит так:

<appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
  <filter type="log4net.Filter.StringMatchFilter">
    <param name="AcceptOnMatch" value="false" /> 
    <stringToMatch value="An existing connection was forcibly closed by the remote host" />        
  </filter>
  <to value="..." />
  <from value="..." />
  <subject value="[... ${COMPUTERNAME}] An Error occurred" />
  <smtpHost value=".." />
  <bufferSize value="1024" />
  <lossy value="true" />
  <evaluator type="log4net.Core.LevelEvaluator">
     <threshold value="ERROR"/>
  </evaluator>
  <layout type="log4net.Layout.PatternLayout">
     <conversionPattern value="%newline%date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
  </layout>
</appender>

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

1 Ответ

15 голосов
/ 15 июня 2011

Объяснение 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>
...