NLog自定义Target之MQTT

博客 动态
0 145
优雅殿下
优雅殿下 2022-06-21 10:00:47
悬赏:0 积分 收藏

NLog自定义Target之MQTT

NLog自定义Target之MQTT 实现自定义Nlog输出目标到Mqtt,通过Web订阅日志,解决物联网场景下日志不及时的问题。

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 injectionbuilder.Logging.ClearProviders();builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);builder.Host.UseNLog();//AddHostedMqttServerbuilder.Services.AddHostedMqttServer(mqttServer =>    {        mqttServer.WithoutDefaultEndpoint();    })    .AddMqttConnectionHandler()    .AddConnections();//Config Portbuilder.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 Mqttapp.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 500msThread 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
posted @ 2022-06-21 09:04 开源工业物联网网关 阅读(54) 评论(1) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员