日志输出是一个系统最重要的组成部分,日志输出的好坏决定了这个系统的稳定性及实用性,日志输出的方式有很多种,控制台、本地文件、程序输出等等这些都是比较常用的方式,但很少见过日志直接通过网页输出的,在一些项目种就有这类需求。
那么哪类型的项目会有这种需求呢?比如写的c#服务程序,需要24小时运行计算处理的,然后通过网页进行参数配置类,或者数据监控的,这种场景需要实时查看服务的运行情况。
网页的实时日志输出就显的很有必要,我们通过实现ILoggerProvider 日志驱动接口来重写日志输出,代码如下
public class SignalRLoggerProvider: ILoggerProvider
{
private readonly SignalRConfiguration _config;
private readonly IHubContext<DataHub> _hubContext;
public SignalRLoggerProvider(SignalRConfiguration signalRConfiguration, IHubContext<DataHub>hubContext)
{
_config = signalRConfiguration;
_hubContext = hubContext;
}
public ILogger CreateLogger(string categoryName)
{
return new SignalRLogger(_config, _hubContext, categoryName);
}
public void Dispose(){}
}
public class SignalRLogger:ILogger
{
private readonly SignalRConfiguration _config;
private readonly string _categoryName;
private readonly IHubContext<DataHub> _hubContext;
public SignalRLogger(SignalRConfiguration signalRConfiguration,
IHubContext<DataHub> hubContext,
string categoryName)
{
_config = signalRConfiguration;
_categoryName = categoryName;
_hubContext = hubContext;
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel >= _config.LogLevel;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception exception, Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel)) return;
StringBuilder message = new StringBuilder();
message.Append(_categoryName);
message.AppendFormat("[{0}]", eventId);
message.Append(Environment.NewLine);
message.Append(formatter(state, exception));
_hubContext.Clients.All.SendAsync("ReceiveMessage", logLevel.ToString(), message.ToString());
}
}
这样我们就实现了日志的输出,最后将日志信息通过SignalR发送出去。
这样我们的SignalR的日志输出模块就完成了,接下来我们只需要在前端接口该日志信息,打印在网页上即可,代码如下
connection.on("ReceiveMessage", function (level, message) {
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
if (month < 10) {
month = '0' + month;
}
var day = date.getDate();
var hour = date.getHours();
var minute = date.getMinutes();
var second = date.getSeconds();
var millisecond = date.getMilliseconds();
var dateStr = year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + '.' + millisecond;
var html = '<div class="inline">';
var arr;
if (message.indexOf('\r\n') > -1) {
arr = message.split('\r\n');
}
else {
arr = message.split('\n');
}
switch (level) {
case 'Debug':
html = html + '<span class="item gray">dbug</span>:[' + dateStr + '] ' + arr[0] + '<br />';
break;
case 'Information':
html = html + '<span class="item green">info</span>:[' + dateStr + '] ' + arr[0] + '<br />';
break;
case 'Warning':
html = html + '<span class="item orange">warn</span>:[' + dateStr + '] ' + arr[0] + '<br />';
break;
case 'Error':
html = html + '<span class="item red">fail</span>:[' + dateStr + '] ' + arr[0] + '<br />';
break;
}
html = html + '<label>' + arr[1] + '</label>';
html = html + '</div>';
$('#log').append(html);
})
这样网页上就能够实时呈现出日志信息了,我们写一个线程不停的打印日志
Task.Run(() =>
{
var logger = app.Services.GetService<ILogger<Program>>();
Random rnd = new Random();
while (true)
{
int value = rnd.Next(0, 12);
if(value % 4 == 0)
{
logger.LogDebug($"Logger debug {value}");
}
else if (value % 4 == 1)
{
logger.LogInformation($"Logger information {value}");
}
else if (value % 4 == 2)
{
logger.LogWarning($"Logger warning {value}");
}
else if (value % 4 == 3)
{
logger.LogError($"Logger error {value}");
}
Thread.Sleep(2000);
}
});
最终呈现出来的效果如下图,效果还是非常不错的。
Demo代码已经提交到:
https://gitee.com/hcgit/hcfloggersignalr