类别
标签
AspNetCore网页实时刷新日志信息

    日志输出是一个系统最重要的组成部分,日志输出的好坏决定了这个系统的稳定性及实用性,日志输出的方式有很多种,控制台、本地文件、程序输出等等这些都是比较常用的方式,但很少见过日志直接通过网页输出的,在一些项目种就有这类需求。

    那么哪类型的项目会有这种需求呢?比如写的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