NLog自定义Target之MQTT

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

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

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

实时日志需求

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

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

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

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

f9520f2213ed1c70cd33680cbdc6c6cc.gif

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 fieldsDictionary<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

003663326f0a3049cf73cb7ae5e34ac4.png

  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 =>
{//MqttServerWebSocketendpoints.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

604f30ca44d884e5298808c0a617b89e.png

8. 也可以通过Mqtt客户端订阅日志 

0e794d921b253c073c53c50bd768ef13.png

源码及相关链接

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

[2] Giteehttps://gitee.com/iioter/NLog.Targets.MQTT

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

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

感兴趣可以关注我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285781.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2016-1-27

2019独角兽企业重金招聘Python工程师标准>>> 1.前端的三大技能:1.1.描述网页内容html 1.2.描述网页样式css 1.3.描述网页行为js2.html和jsp区别在于静态和动态..bootsharp是目前比较火爆的css..angular是目前比较火爆的js.3.单点登陆(SSO):登陆一次就可以访问所有相…

【ArcGIS风暴】ArcGIS生成GlobeLand30土地利用数据集中国区域行列号shp格式对照图(附shp下载)

效果预览: 本文主要讲述了在ArcGIS中生成GlobeLand中国区域对照行列号的shp格式矢量数据,用途在于将自己的研究区跟行列号矢量图层直接叠加显示,快速找出自己所需要的图幅号,便于快速下载数据。同时为了方便使用,本文提供了对照图的下载。 文章目录 1. 创建文件数据库2. 创…

Android 节操视频播放器jiecaovideoplayer自定义播放音频使用:屏蔽全屏按钮,增加倒计时,当前时间/总时间

一、屏蔽全屏按钮 找到JCVideoPlayerStandard.java文件中的代码&#xff1a; private void fixAudio() {if (SrcType.equalsIgnoreCase("Audio")) {//如果是音频&#xff0c;始终显示coverImageView//thumbImageView.setVisibility(View.VISIBLE);coverImageView.se…

Android之Dialog提示Unable to add window -- token is not valid; is your activity running?

1、问题 Dialog奔溃提示Unable to add window -- token android.os.BinderProxy@b251dbc is not valid; is your activity running? 2、解决办法 传递context到dialog的时候,要记得先判断状态是不是isFinishing或者isDestroyed状态,这个时候就不要再去show相关的dialog了,…

nagios监控haproxy(借助脚本)

nagios监控haproxy&#xff08;借助脚本&#xff09; 修改后的脚本如下&#xff08;需添加指示灯的状态&#xff09; # vi haproxy.sh #!/bin/bash Portnetstat -ntpl | grep haproxy | awk -F[:" "] {print $5} if [ $Port "1080" ];then echo "OK …

一、Qt初尝试,做一个QT计算器《QT 入门到实战》

学习目标 了解 qt 的基本信息了解 qt 的下载及安装了解创建一个基本 qt 项目的流程了解信号与槽通过示例了解信号与槽的设置与编写了解控件添加的方式了解控件如何使用代码获取其文本了解控件如何使用代码设置其文本使用 connect 自定义信号与槽了解使用样式修饰控件外观了解使…

VS C#语言获取输入名称的汉语拼音简拼码和全拼码完整案例教程

结果预览: 扩展阅读: SQL语言获取拼音码:SQL Server编写函数获取汉字的拼音码(简拼) 文章目录 1. 拼音码类编写2. 界面设计3. 前端调用4. 结果展示1. 拼音码类编写 打开Visual Studio,新建一个Winform项目,再添加一个类文件,命名为PYM。 键入如下代码: using Syst…

iOS duplicate symbol for architecture arm64 解决办法

导致这个问题的原因有多种&#xff1a; 1.重复定义了const常量。 2.多个第三方库同时用到了某个函数库。 暂时列举这几种&#xff0c;以后遇到了其他原因再加。转载于:https://www.cnblogs.com/zhanglinfeng/p/5987077.html

WPF 实现星空效果

本文经原作者授权以原创方式二次分享&#xff0c;欢迎转载、分享。原文作者&#xff1a;普通的地球人原文地址&#xff1a;https://www.cnblogs.com/tsliwei/p/6282183.htmlGithub地址&#xff1a;https://github.com/WPFDevelopersOrg/WPFDevelopers效果前阵子看到ay的蜘蛛网效…

data类型的Url的格式

data类型的Url的格式 一、data类型的简介 所谓"data"类型的Url格式&#xff0c;是在RFC2397中提出的&#xff0c;目的对于一些“小”的数据&#xff0c;可以在网页中直接嵌入&#xff0c;而不是从外部文件载入。例如对于img这个Tag&#xff0c;哪怕 这个图片非常非…

C语言试题八十之统计单词个数

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 终端输入一…

SSIS 执行变量中的脚步输出列顺序与SQL查询列顺序不同

这个问题是朋友遇到的&#xff0c;做一个SSIS的程序将数据导入到txt。然后再用Oracle的工具导入到Oracle。但是在SSIS中执行变量脚步的时候&#xff0c;发现输出的列名称跟查询的列名称完全不同。比如Schema_id在查询的第三列&#xff0c;但是输出的时候到了第6列。 如图&#…

【ArcGIS风暴】ArcGIS自定义坐标系统案例教程---以阿尔伯斯投影(Albers)为例

在实际工作中,经常需要进行矢量数据或栅格数据的投影转换工作,但有时候ArcGIS中恰恰没有我们需要的坐标系,此时,就需要我们自定义坐标系。本文以阿尔伯斯投影(Albers)为例,讲解自定义投影的一般过程及注意事项。 文章目录 1. 确定投影名称2. 选择投影坐标系及修改参数4.…

C语言试题八十一之利用递归函数调用方式,将所输入的5个字符,相反顺序打印

📃个人主页:个人主页 🔥系列专栏:C语言试题200例目录 💬推荐一款刷算法、笔试、面经、拿大公司offer神器 👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 利用递归函…

Unity5 GI与PBS渲染从用法到着色代码

本文主要介绍Untiy5以后的GI&#xff0c;PBS&#xff0c;以及光源探头&#xff0c;反射探头的用法以及在着色器代码中如何发挥作用&#xff0c;GI是如何影响渲染的&#xff0c;主要分成三个部分&#xff0c;最开始说明PBS需要的材质与相应概念&#xff0c;二是Unity 里相应GI的…

Web前端笔试面试题汇总(转自github)

前言 本文总结了一些优质的前端面试题&#xff08;多数源于网络&#xff09;&#xff0c;初学者阅后也要用心钻研其中的原理&#xff0c;重要知识需要系统学习&#xff0c;透彻学习&#xff0c;形成自己的知识链。万不可投机取巧&#xff0c;只求面试过关是错误的&#xff01; …

Blazor University (31)表单 —— 验证

原文链接&#xff1a;https://blazor-university.com/forms/validation/验证源代码[1]DataAnnotationsValidator 是 Blazor 中的标准验证器类型。在 EditForm 组件中添加此组件将启用基于 System.ComponentModel.DataAnnotations.ValidationAttribute 的 .NET 属性的表单验证。…

CSDN,CNBLOGS博客文章一键转载插件 终于更新了!

之前&#xff0c;Shawn Chou等朋友一直建议插件支持cnblogs文章转载&#xff0c;但一直没时间修改插件&#xff0c;今天晚上抽时间将插件进行了升级&#xff0c;可以支持 CSDN,CNBLOGS博客文章的一键转载。时间仓促&#xff0c;难免有各种问题&#xff0c;欢迎提出建议&#xf…

ROS2_Control官方资料+运动控制

Getting Started — ROS2_Control: Rolling Dec 2023 documentation Getting Started Edit on GitHub Youre reading the documentation for a development version. For the latest released version, please have a look at Iron. Getting Started Installation Binar…

三、教你搞懂渐变堆叠面积图《手把手教你 ECharts 数据可视化详解》

注&#xff1a;本系列教程需要对应 JavaScript 、html、css 基础&#xff0c;否则将会导致阅读时困难&#xff0c;本教程将会从 ECharts 的官方示例出发&#xff0c;详解每一个示例实现&#xff0c;从中学习 ECharts 。 ECharts 官方示例&#xff1a;https://echarts.apache.o…