• NLog自定义Target之MQTT


    NLog是.Net中最流行的日志记录开源项目(之一),它灵活免费开源

    官方支持文件网络(Tcp、Udp)、数据库控制台等输出

    社区支持ElasticSeq等日志平台输出

    实时日志需求

    在工业物联网等特定场景下需要实时获取日志信息

    工业物联网领域常用的是mqtt协议

    那我们就使用NLog 自定义一个Target,将日志输出到MqttServer

    Web通过Mqtt(websocket)实时获取日志,而不是传统的通过WebApi轮询日志

    NLog自定义Target

    1. 官方文档介绍了如何自定义Target,可以获取到一串日志消息,无法获取结构化消息
    2. 需要时用使用自定义Field来完成这部分工作
    /// <summary>
    /// Additional field details
    /// </summary>
    [NLogConfigurationItem]
    public class Field
    {
        /// <summary>
        /// Name of additional field
        /// </summary>
        [RequiredParameter]
        public string Name { get; set; }
    
        /// <summary>
        /// Value with NLog <see cref="NLog.Layouts.Layout"/> rendering support
        /// </summary>
        [RequiredParameter]
        public Layout Layout { get; set; }
    
        /// <summary>
        /// Custom type conversion from default string to other type
        /// </summary>
        /// <remarks>
        /// <see cref="System.Object"/> can be used if the <see cref="Layout"/> renders JSON
        /// </remarks>
        public Type LayoutType { get; set; } = typeof(string);
    
        /// <inheritdoc />
        public override string ToString()
        {
            return $"Name: {Name}, LayoutType: {LayoutType}, Layout: {Layout}";
        }
    }
    
    1. 重写Write方法
    protected override void Write(LogEventInfo logEvent)
    {
        //default fields
        Dictionary<string, object> logDictionary = new()
        {
            { "timestamp", logEvent.TimeStamp },
            { "level", logEvent.Level.Name },
            { "message", RenderLogEvent(Layout, logEvent) }
        };
    
        //customer fields
        //这里都处理为字符串了,有优化空间
        foreach (var field in Fields)
        {
            var renderedField = RenderLogEvent(field.Layout, logEvent);
    
            if (string.IsNullOrWhiteSpace(renderedField))
                continue;
    
            logDictionary[field.Name] = renderedField;
        }
    
        SendTheMessage2MqttBroker(JsonConvert.SerializeObject(logDictionary));
    }
    

    使用

    下面将使用Nlog.Target.MQTT,演示通过web实时查看应用程序的日志

    1. 创建WebApi项目
    2. 引用NLog.Target.MQTT

    1. 配置文件
    <extensions>
        <add assembly="NLog.Web.AspNetCore"/>
        <!--<add assembly="NLog.Targets.MQTT"/>-->
        <add assembly="NLog.Targets.MQTT"/>
    </extensions>
    
    <!-- the targets to write to -->
    <targets>
        <!-- MQTT Target  -->
        <target xsi:type="MQTT" name="mqtt" host="localhost" port="1883" username="UserName"  password="Password" topic="log"
                layout="${longdate}|${event-properties:item=EventId_Id:whenEmpty=0}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}|${callsite}" >
            <field name="machine" layout="${machinename}" />
            <field name="processid" layout="${processid}" />
            <field name="threadname" layout="${threadname}" />
            <field name="logger" layout="${logger}" />
            <field name="callsite" layout="${callsite-linenumber}" />
            <field name="url" layout="${aspnet-request-url}" />
            <field name="action" layout="${aspnet-mvc-action}" />
            <field name="level" layout="${level:uppercase=true}" />
            <field name="message" layout="${message}" />
            <field name="exception" layout="${exception:format=toString}" />
        </target>
    </targets>
    
    <!-- rules to map from logger name to target -->
    <rules>
        <logger name="*" minlevel="Trace" writeTo="mqtt" />
    </rules>
    
    1. 配置MQTTServer和NLog
    // ...
    // NLog: Setup NLog for Dependency injection
    builder.Logging.ClearProviders();
    builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
    builder.Host.UseNLog();
    
    //AddHostedMqttServer
    builder.Services.AddHostedMqttServer(mqttServer =>
        {
            mqttServer.WithoutDefaultEndpoint();
        })
        .AddMqttConnectionHandler()
        .AddConnections();
    
    //Config Port
    builder.WebHost.UseKestrel(option =>
    {
        option.ListenAnyIP(1883, l => l.UseMqtt());
        option.ListenAnyIP(80);
    });
    var app = builder.Build();
    
    // ...
    //UseStaticFiles html js etc.
    app.UseStaticFiles();
    app.UseRouting();
    
    //Websocket Mqtt
    app.UseEndpoints(endpoints =>
    {
        //MqttServerWebSocket
        endpoints.MapConnectionHandler<MqttConnectionHandler>("/mqtt", options =>
        {
            options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
        });
    });
    // ...
    
    1. Web连接MqttServer
    // ...    
    <script src="./jquery.min.js"></script>
    <script src="./mqtt.min.js"></script>
    <script src="./vue.js"></script>
    // ...
    
    var client = mqtt.connect('ws://' + window.location.host + '/mqtt', options);
    client.on('connect',
        function() {
            client.subscribe('log',
                function(err) {
                    if (!err) {
                        console.log("subed!");
                    } else {
                        alert("subed error!");
                    }
                });
        });
    client.on('message',
        function(topic, message) {
            if (topic === 'log') {
                if (app.logs.length > 50)
                    app.logs.length = 0;
                app.logs.unshift($.parseJSON(message.toString()));
            }
        });
    // ...
    
    1. 输出日志
    // ...  
    _logger.LogDebug("LogDebug!");
    _logger.LogError(new Exception("Exception Message!"), "LogError!");
    
    //new thread output log after 500ms
    Thread thread = new Thread(ThreadProc);
    thread.Name = "My Thread";
    thread.Start();
    // ...
    
    1. 实时查看日志
      访问index.html

    2. 通过Mqtt客户端订阅日志

    源码

    在这里NLog.Targets.MQTT:https://github.com/iioter/NLog.Targets.MQTT

    相关链接

    [1] NLog.Targets.MQTT:https://github.com/iioter/NLog.Targets.MQTT

    [2] IoTGateway-Doc:http://iotgateway.net/blog/NLog

    [3] NLog自定义Target:https://github.com/NLog/NLog/wiki/How-to-write-a-custom-target

    交流

    公众号:工业物联网网关 QQ群:712105424
  • 相关阅读:
    rac进行image copy备份,以及异机单机switch to copy方式恢复
    Python爬取的网页,需要解码怎么办
    【腾讯云原生降本增效大讲堂】云原生产业发展态势分析
    C++ 14 常用新特性
    Generative AI 新世界 | 文生图领域动手实践:预训练模型的微调
    PT_随机变量函数的分布_随机变量线性函数的正态分布
    论文于祥读及复现——《VDO-SLAM: A Visual Dynamic Object-aware SLAM System》
    国内有什么比较好用的量化交易接口?
    2.9 GBDT模型(上篇)
    降水数据下载地址汇总
  • 原文地址:https://www.cnblogs.com/whdong/p/16395611.html