NLog自定义Target之MQTT
NLog是.Net中最流行的日志记录开源项目(之一),它灵活、免费、开源
官方支持文件、网络(Tcp、Udp)、数据库、控制台等输出
社区支持Elastic、Seq等日志平台输出
实时日志需求
在工业物联网等特定场景下需要实时获取日志信息
工业物联网领域常用的是mqtt协议
那我们就使用NLog 自定义一个Target,将日志输出到MqttServer
Web通过Mqtt(websocket)实时获取日志,而不是传统的通过WebApi轮询日志
NLog自定义Target
- 官方文档介绍了如何自定义Target,可以获取到一串日志消息,无法获取结构化消息
- 需要时用使用自定义Field来完成这部分工作
///
/// Additional field details
///
[NLogConfigurationItem]
public class Field
{
///
/// Name of additional field
///
[RequiredParameter]
public string Name { get; set; }
///
/// Value with NLog rendering support
///
[RequiredParameter]
public Layout Layout { get; set; }
///
/// Custom type conversion from default string to other type
///
///
/// can be used if the renders JSON
///
public Type LayoutType { get; set; } = typeof(string);
///
public override string ToString()
{
return $"Name: {Name}, LayoutType: {LayoutType}, Layout: {Layout}";
}
}
- 重写Write方法
protected override void Write(LogEventInfo logEvent)
{
//default fields
Dictionary 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实时查看应用程序的日志。
- 创建WebApi项目
- 引用NLog.Target.MQTT
- 配置文件
- 配置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("/mqtt", options =>
{
options.WebSockets.SubProtocolSelector = MqttSubProtocolSelector.SelectSubProtocol;
});
});
// ...
- Web连接MqttServer
// ...
// ...
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()));
}
});
// ...
- 输出日志
// ...
_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();
// ...
-
实时查看日志
访问index.html -
通过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 |
---|---|
![]() |
![]() |