NLog自定义LimitedFrequencyEmailTarget同步调用疑问:IIS部署也会如此吗?
问题解答
这种同步调用的情况部署到IIS后依然会发生,和是否在Visual Studio调试无关——这是由NLog的目标执行机制决定的,和运行环境没有关系。
原因分析
NLog的MailTarget本身是同步目标,即使你重写了Write(AsyncLogEventInfo)方法,默认情况下NLog并不会自动将这个方法的执行放到后台线程。从你提供的堆栈跟踪可以看到,调用链是从logger.Error直接同步走到了你的Write方法,没有经过任何线程调度逻辑,这说明当前目标是同步执行的,和宿主环境(调试/IIS)无关。
实现异步执行的方案
如果你希望logger.Error()能立即返回,让邮件发送逻辑在后台线程执行,可以通过以下两种方式实现:
1. 使用NLog自带的AsyncTargetWrapper(推荐)
在NLog配置文件中,给你的LimitedFrequencyEmailTarget添加异步包装器,NLog会自动将日志事件放入队列,由后台线程处理,调用线程会立即返回。示例配置:
<targets> <target xsi:type="AsyncWrapper" name="asyncLimitedEmail"> <target xsi:type="LimitedFrequencyEmailTarget" name="limitedEmail" smtpServer="xxx" smtpPort="xxx" from="xxx" to="xxx" /> </target> </target> <rules> <logger name="*" minlevel="Error" writeTo="asyncLimitedEmail" /> </rules>
2. 在派生类中手动实现异步逻辑
在你的Write方法里,手动将邮件发送逻辑放到后台线程执行,并正确调用异步完成回调:
protected override void Write(AsyncLogEventInfo logEvent) { Task.Run(() => { try { // 执行频率检查和邮件发送逻辑 if (CheckIfTooManyEmails(DateTime.Now, 0)) { // 频率超限,不发送邮件 logEvent.Continuation(null); return; } base.Write(logEvent.LogEvent); logEvent.Continuation(null); } catch (Exception ex) { // 传递异常给NLog处理 logEvent.Continuation(ex); } }); }
注意:手动实现需要自己处理线程安全、异常捕获和队列限流等问题,不如使用AsyncTargetWrapper可靠。
内容的提问来源于stack exchange,提问作者Zhijian Jim Luo
相关产品推荐
相关产品推荐

