我们正在使用NLog在发生“严重”错误时发送电子邮件。在某些情况下,可能会经常发生过多的消息。
有没有办法让NLog限制它在一个特定时间段内发送的一个特定错误或任何错误的消息数量?
log4net或任何其他流行的日志记录库中是否存在类似的机制?
答案 0 :(得分:4)
配置文件更改:
<target name="SystemErrorLog" xsi:type="TokenTimeThrottler" EntryExpirationPeriodSec="300">
<target xsi:type="AsyncWrapper" queueLimit="5000" overflowAction="Discard">
<target xsi:type="Mail" ... />
</target> </target>
目标类:
[Target("TokenTimeThrottler", IsCompound = true)]
public class ThrottlingLogTarget : CompoundTargetBase
{
private ITokenTimeThrottler _tokenTimeThrottler;
public ThrottlingLogTarget()
: this(new Target[0])
{
}
public ThrottlingLogTarget(params Target[] targets)
: base(targets)
{
}
[Required]
public int EntryExpirationPeriodSec { get; set; }
protected override void InitializeTarget()
{
base.InitializeTarget();
_tokenTimeThrottler = new TokenTimeThrottler(EntryExpirationPeriodSec > 0 ? EntryExpirationPeriodSec : 0);
}
protected override void Write(AsyncLogEventInfo logEvent)
{
if (this.Targets.Count == 0)
{
logEvent.Continuation(null);
return;
}
var token = string.Format("{0},{1},{2}", logEvent.LogEvent.LoggerName, logEvent.LogEvent.Level, logEvent.LogEvent.FormattedMessage);
if (_tokenTimeThrottler.CheckAllow(token))
{
foreach (var target in Targets)
{
target.WriteAsyncLogEvent(logEvent);
}
}
}
}
public class TokenTimeThrottler : ITokenTimeThrottler
{
private readonly ConcurrentDictionary<string, DateTime> _entriesLastTimes;
private readonly int _expirationPeriodSec;
public TokenTimeThrottler(int entryExpirationPeriodSec)
{
_entriesLastTimes = new ConcurrentDictionary<string, DateTime>();
_expirationPeriodSec = entryExpirationPeriodSec;
}
public bool CheckAllow(string token)
{
DateTime lastLoggedTime;
if (_entriesLastTimes.TryGetValue(token, out lastLoggedTime))
{
DateTime? updatedTime = null;
if (lastLoggedTime.AddSeconds(_expirationPeriodSec) < DateTime.Now)
{
updatedTime = DateTime.Now;
}
_entriesLastTimes.AddOrUpdate(token, k => updatedTime ?? lastLoggedTime,
(k, v) => updatedTime ?? v);
return updatedTime.HasValue;
}
_entriesLastTimes.AddOrUpdate(token, k => DateTime.Now, (k, v) => v);
return true;
}
}
答案 1 :(得分:3)
您可以在此处查看类似log4net问题的答案:
log4net - any filter for logging only the Nth message?
在那个答案中,我提出了一个自定义的log4net Filter实现,它允许在可配置的时间段内重复消息被限制。
对于NLog,最简单的方法可能是编写自定义包装器target。自定义Wrapper目标实现将检查传入的日志消息,如果当前消息与最新消息不同(或者如果已经过了一定时间,则转发)。然后,您可以使用此自定义包装器包装任何现有目标。
请注意,我实际上并没有编写Wrapper目标,或者我会尝试提供更多信息。