You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获ASP.NET Core中Serilog MQTT Sink抛出的异常?

解决Serilog MQTT Sink异常捕获问题

方案1:包装MQTT Sink做异常隔离

自定义一个Sink包装类,把原MQTT Sink包裹起来,在内部捕获异常,避免异常扩散到应用层级:

public class SafeMqttSinkWrapper : ILogEventSink
{
    private readonly ILogEventSink _innerMqttSink;

    public SafeMqttSinkWrapper(ILogEventSink innerSink)
    {
        _innerMqttSink = innerSink;
    }

    public void Emit(LogEvent logEvent)
    {
        try
        {
            _innerMqttSink.Emit(logEvent);
        }
        catch (Exception ex)
        {
            // 在这里处理异常,比如写入本地文件、输出控制台,注意别调用Serilog日志避免循环
            Console.WriteLine($"MQTT日志发送失败: {ex.Message}");
            // 可选:添加重试逻辑或标记Broker不可用状态
        }
    }
}

修改Serilog配置,用包装类替换原MQTT Sink:

builder.Host.UseSerilog((ctx, lc) => lc
    .WriteTo.Console()
    .WriteTo.Sink(new SafeMqttSinkWrapper(
        new MqttSink(publisherOptions, "top/log", new RenderedCompactJsonFormatter()))));

方案2:修复原Sink的async void反模式

原Sink的Emit用了async void,这会导致异步异常无法被上层捕获。可以重写Sink的异步逻辑,改用async Task并内部处理异常:

public class AsyncSafeMqttSink : ILogEventSink
{
    private readonly MqttPublisherOptions _publisherOptions;
    private readonly string _topic;
    private readonly ITextFormatter _formatter;
    private readonly IMqttClient _mqttClient;

    // 复制原MQTT Sink的构造逻辑,初始化_mqttClient等依赖
    public AsyncSafeMqttSink(MqttPublisherOptions options, string topic, ITextFormatter formatter)
    {
        _publisherOptions = options;
        _topic = topic;
        _formatter = formatter;
        // 这里初始化_mqttClient,和原Sink逻辑一致
    }

    private async Task EmitLogEventAsync(LogEvent logEvent)
    {
        try
        {
            var stringWriter = new StringWriter();
            _formatter.Format(logEvent, stringWriter);

            var applicationMessage = new MqttApplicationMessageBuilder()
                .WithTopic(_topic)
                .WithPayload(stringWriter.ToString())
                .Build();
            
            await _mqttClient.PublishAsync(applicationMessage);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"MQTT发布异常: {ex}");
            // 可添加重试、Broker状态标记等逻辑
        }
    }

    // 实现ILogEventSink的同步方法,转调异步逻辑
    public void Emit(LogEvent logEvent)
    {
        _ = EmitLogEventAsync(logEvent); // 用弃元操作避免编译器警告
    }
}

配置时直接使用这个自定义Sink:

builder.Host.UseSerilog((ctx, lc) => lc
    .WriteTo.Console()
    .WriteTo.Sink(new AsyncSafeMqttSink(publisherOptions, "top/log", new RenderedCompactJsonFormatter())));

方案3:用Serilog全局SelfLog捕获内部错误

如果不想修改Sink代码,可以启用Serilog的SelfLog,它会捕获Serilog自身处理日志时的所有异常:

// 在Program.cs启动初期配置
Serilog.Debugging.SelfLog.Enable(msg => 
{
    Console.WriteLine($"Serilog内部错误: {msg}");
    // 也可以写入本地文件
    // File.AppendAllText("serilog-error.log", $"{DateTime.Now}: {msg}\n");
});

这种方式快速简单,但只能记录异常信息,无法做重试等复杂处理。


内容的提问来源于stack exchange,提问作者pyrogen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:01:18