Log4net filter - как писать И фильтровать, чтобы игнорировать сообщения журнала
Я пытаюсь написать условный фильтр AND в log4net. Если бы это было nLog, я мог бы написать это так:
<logger name="*" minlevel="Info" xsi:type="NLogLoggerRule" writeTo="FooLogger" >
<filters>
<when condition="equals('${event-context:item=UserID}', 'TESTUSER')
and equals('${event-context:item=URL}','/foo/foobar.aspx')"
action="Ignore" />
</filters>
</logger>
Я не уверен, как написать тот же фильтр в log4net. Я был так успешным, написав одно условие:
<appender>
....
<filter type="log4net.Filter.PropertyFilter">
<key value="URL" />
<stringToMatch value="/foo/foobar.aspx" />
<acceptOnMatch value="false" />
</filter>
</appender>
Как я могу писать условия AND с использованием фильтров log4net? Пожалуйста, помогите.
Ответы
Ответ 1
Пользовательский фильтр, поддерживающий условия И. Этот класс предоставляет свойство Filter, поэтому здесь могут использоваться существующие фильтры log4net, а также, если требуется, могут быть вложенные условия AND.
public class AndFilter : FilterSkeleton
{
private bool acceptOnMatch;
private readonly IList<IFilter> filters = new List<IFilter>();
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
if (loggingEvent == null)
throw new ArgumentNullException("loggingEvent");
foreach(IFilter filter in filters)
{
if (filter.Decide(loggingEvent) != FilterDecision.Accept)
return FilterDecision.Neutral; // one of the filter has failed
}
// All conditions are true
if(acceptOnMatch)
return FilterDecision.Accept;
else
return FilterDecision.Deny;
}
public IFilter Filter
{
set { filters.Add(value); }
}
public bool AcceptOnMatch
{
get { return acceptOnMatch;}
set { acceptOnMatch = value;}
}
}
Config:
<filter type="Namespace.AndFilter, Assembly">
<filter type="log4net.Filter.PropertyFilter">
<key value="URL" />
<stringToMatch value="/foo/foobar.aspx" />
</filter>
<filter type="log4net.Filter.PropertyFilter">
<key value="UserID" />
<stringToMatch value="TESTUSER" />
</filter>
<acceptOnMatch value="false" />
</filter>
Ответ 2
Вы можете создать собственный фильтр для своих нужд:
public class UserRequestFilter : FilterSkeleton
{
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
if (loggingEvent == null)
throw new ArgumentNullException("loggingEvent");
string userId = (string)loggingEvent.Properties["UserId"];
string url = (string)loggingEvent.Properties["Url"];
if (String.IsNullOrEmpty(UserId) || String.IsNullOrEmpty(Url))
return FilterDecision.Neutral;
if (UserId.Equals(userId) && Url.Equals(url, StringComparison.CurrentCultureIgnoreCase))
return AcceptOnMatch ? FilterDecision.Accept : FilterDecision.Deny;
return FilterDecision.Neutral;
}
public bool AcceptOnMatch { get; set; }
public string UserId { get; set; }
public string Url { get; set; }
}
Конфигурация будет выглядеть так:
<filter type="Namespace.UserRequestFilter, Assembly">
<userId value="TESTUSER"/>
<url value="/foo/foobar.aspx"/>
<acceptOnMatch value="true"/>
</filter>
Также вы можете создать составной фильтр, но я не нашел способ использовать его в конфигурации. Похоже, он может быть присоединен только программно (что бесполезно ^ _ ^):
IAppenderAttachable logger = (IAppenderAttachable)_log.Logger;
AppenderSkeleton appender = (AppenderSkeleton)logger.GetAppender("appenderName");
CompoundFilter compoundFilter = new CompoundFilter();
compoundFilter.AddFilter(new PropertyFilter() { Key = "UserId", StringToMatch = "TEST" });
compoundFilter.AddFilter(new PropertyFilter() { Key = "Url", StringToMatch = @"/foo/foobar.aspx" });
appender.AddFilter(compoundFilter);
logger.AddAppender(appender);
[ОБНОВЛЕНИЕ]
Вот трюк, который вы можете использовать - создать фильтр, который будет проверять все фильтры по цепочке фильтров:
public class DenyAllSubsequentFilter : FilterSkeleton
{
public override FilterDecision Decide(LoggingEvent loggingEvent)
{
IFilter nextFilter = Next;
if (nextFilter == null)
return FilterDecision.Accept;
while (nextFilter != null)
{
if (nextFilter.Decide(loggingEvent) != FilterDecision.Deny)
return FilterDecision.Accept;
nextFilter = nextFilter.Next;
}
return FilterDecision.Deny;
}
}
Использование:
<filter type="Namespace.DenyAllSubsequentFilter, Assembly"/>
<filter type="log4net.Filter.PropertyFilter">
<key value="UserId" />
<stringToMatch value="TEST" />
<acceptOnMatch value="false" />
</filter>
<filter type="log4net.Filter.PropertyFilter">
<key value="Url" />
<stringToMatch value="/foo/foobar.aspx" />
<acceptOnMatch value="false" />
</filter>
Этот фильтр будет отклонять сообщение регистрации, если все последующие фильтры отклонят его.