网站正常运行中有时出现异常在所难免,查看系统运行日志分析问题并能够根据错误信息快速解决问题尤为重要,ABP对于系统运行日志这块已经做了很好的处理,默认采用的Log4Net已经足够满足开发过程中的需要了(当然有需要的话也可以更换为其它日志组件)。

  ABP官网地址:https://aspnetboilerplate.com/

一、日志文件

  ABP框架默认使用了Log4Net日志组件,日志记录在txt文件中,也可以替换成其它日志组件诸如Nlog,方便将日志文件信息直接记录到数据库中,具体情形使用具体组件。

  

  当一个文件达到了在Log4Net配置中设置好的文件大小上限时,在文件名后按照数字倒排后开始继续增加文件。

  

  当需要查看错误信息时,直接在日期最近的文件中找出错误信息即可,但是这个过程比较繁琐,还需要从日志文件中去查看,并且日志文件中虽然做了分类,哪些是正常信息,哪些是错误信息,但是不太直观,因此,可以考虑直接将日志文件在页面中呈现,对信息进一步加工,方便直接查看。

  

  参考了AbpZero中的部分代码并根据实际需要进行整合,开始在页面中设计日志展示层。

二、页面展示日志信息

1、系统日志服务应属于整个系统中相对其他业务模块独立的一部分,因此,首先在应用层中新建一个Logging文件夹并创建一个日志应用层服务接口与其实现。在接口中声明两个方法,直接查看当前最近的日志文件中的日志信息以及从服务器下载所有的日志文件。

/// <summary>
/// 网站运行日志应用层服务
/// </summary>
public interface IWebSiteLogAppService : IApplicationService
{
/// <summary>
/// 获取最近的一个日志文件
/// </summary>
/// <returns></returns>
GetLatestWebLogsOutput GetLatestWebLogs(); /// <summary>
/// 下载所有的日志文件
/// </summary>
/// <returns></returns>
FileDto DownloadWebLogs();
}

  首先考虑直接获取最近的日志文件信息,直接读取即可,遵循的规则是读取指定文件夹下指定文件后缀名更改日期为最大的文件然后从中读取日志信息,并返回到前端。

public GetLatestWebLogsOutput GetLatestWebLogs()
{
var directory = new DirectoryInfo(AppConsts.LogFilePath); if (!directory.Exists)
{
return new GetLatestWebLogsOutput
{
LatestWebLogLines = new List<string>()
};
} var lastLogFile = directory.GetFiles("*.txt", SearchOption.AllDirectories)
.OrderByDescending(f => f.LastWriteTime)
.FirstOrDefault(); if (lastLogFile == null)
{
return new GetLatestWebLogsOutput();
} var lines = AppFileHelper.ReadLines(lastLogFile.FullName).Reverse().Take().ToList();
var logLineCount = ;
var lineCount = ; foreach (var line in lines)
{
if (line.StartsWith("DEBUG") ||
line.StartsWith("INFO") ||
line.StartsWith("WARN") ||
line.StartsWith("ERROR") ||
line.StartsWith("FATAL"))
logLineCount++; lineCount++; if (logLineCount == ) break;
} return new GetLatestWebLogsOutput
{
LatestWebLogLines = lines.Take(lineCount).Reverse().ToList()
};
}

2、在前端处理日志信息,Mvc层中新增一个控制器,并写一个方法调用日志服务获取最近的日志文件信息,并处理好权限问题及页面左侧菜单的展示。

/// <summary>
/// 系统维护控制器
/// </summary>
[AbpMvcAuthorize]
public class MaintenanceController : SurroundControllerBase
{
private readonly IWebSiteLogAppService _webSiteLogAppService; public MaintenanceController(IWebSiteLogAppService webSiteLogAppService)
{
_webSiteLogAppService = webSiteLogAppService;
} /// <summary>
/// 首页
/// </summary>
/// <returns></returns>
public IActionResult Index()
{
return View();
} /// <summary>
/// 获取最近日志信息
/// </summary>
/// <returns></returns>
public JsonResult GetLatestWebLogs()
{
var getLatestWebLogsOutput = _webSiteLogAppService.GetLatestWebLogs();
return Json(getLatestWebLogsOutput);
}
}

  增加一个视图文件并开始编写前端代码获取日志文件,利用abp前端封装好的ajax请求快速的获取日志文件,然后通过layui中提供的徽章进行加工处理,如此一来,通过颜色快速区分哪些是错误信息,哪些信息权重更大,更值得关注,此处引用了一个lodash.js,该js中提供了许多的辅助方法。

function getFormattedLogs(logLines) {
var resultHtml = '';
$.each(logLines, function (index, logLine) {
resultHtml += '<span>' + _.escape(logLine)
.replace('DEBUG', '<span class="layui-badge layui-bg-gray">DEBUG</span>')
.replace('INFO', '<span class="layui-badge layui-bg-green">INFO</span>')
.replace('WARN', '<span class="layui-badge layui-bg-orange">WARN</span>')
.replace('ERROR', '<span class="layui-badge">ERROR</span>')
.replace('FATAL', '<span class="layui-badge">FATAL</span>') + '</span><br/>';
});
return resultHtml;
}

  通过刷新按钮获取最近的日志信息。

  

三、下载日志文件

  也可以直接下载日志文件去分析,当然,从使用频率讲,这个功能的权重远低于直接页面查看,但是细想一下,如果说一个异常发生,没有及时去页面中查看,那么就得去成堆的日志中翻找,反而凸显其作用了。

public FileDto DownloadWebLogs()
{
var logFiles = GetAllLogFiles(); var zipFileDto = new FileDto("WebSiteLogs.zip", MimeTypeNames.ApplicationZip); using (var outputZipFileStream = new MemoryStream())
{
using (var zipStream = new ZipArchive(outputZipFileStream, ZipArchiveMode.Create))
{
foreach (var logFile in logFiles)
{
var entry = zipStream.CreateEntry(logFile.Name);
using (var entryStream = entry.Open())
{
using (var fs = new FileStream(logFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 0x1000, FileOptions.SequentialScan))
{
fs.CopyTo(entryStream);
entryStream.Flush();
}
}
}
} _tempFileCacheManager.SetFile(zipFileDto.FileToken, outputZipFileStream.ToArray());
} return zipFileDto;
} private List<FileInfo> GetAllLogFiles()
{
var directory = new DirectoryInfo(AppConsts.LogFilePath);
return directory.GetFiles("*.*", SearchOption.TopDirectoryOnly).ToList();
}

  将日志文件全部读取出来,然后打包存储在缓存中,前端点击下载按钮时后台返回压缩包的标识信息供前端直接下载,此处在控制器中加入一个文件管理的控制器,来作为系统中大部分文件下载的渠道。

var waitIndex = parent.layer.load();
abp.ajax({
type:"Get",
url: "@Url.Action("DownloadWebLogs", "Maintenance")",
abpHandleError: false
}).done(function (file) {
location.href = '@Url.Action("DownloadTempFile", "File")' + abp.utils.formatString("?fileToken={0}&fileType={1}&fileName={2}", file.fileToken, file.fileType, file.fileName);
}).fail(function (jqXHR) {
parent.layer.msg(jqXHR.message, { icon: });
}).always(function () {
parent.layer.close(waitIndex);
});

  点击日志下载,浏览器开始执行下载任务。   

  

  至此,系统日志的页面查看就完成了,对于加入诸如查询等更加丰富的功能,可以再进行扩展,也可以考虑直接使用已有的组件更方便的呈现的日志信息而无需手动实现,诸如LogDashBoard等,可以很快速的接入到系统中。 

  代码地址:https://gitee.com/530521314/Partner.Surround.git

2019-08-03,望技术有成后能回来看见自己的脚步

X-Admin&ABP框架开发-系统日志的更多相关文章

  1. X-Admin&ABP框架开发-消息通知

    业务型网站使用过程中,消息通知是一个不可或缺的功能,采用站内通知.短信通知.邮件通知.微信通知等等各种方式都有,ABP框架对这部分工作已经封装的很好了,站在巨人的肩膀上,一览全貌,带来的就是心情舒畅. ...

  2. X-Admin&ABP框架开发-版本管理

    多租户系统中,针对于不同租户开放不同功能,或是按照不同功能进行收费管理,需要从宿主本身去管理租户的版本信息,如同酒店人员对不同房间收取不同费用,依据房间内部设施,房间大小等设置不同收费标准.Abp系统 ...

  3. X-Admin&ABP框架开发-代码生成器

    在日常开发中,有时会遇到一些相似的代码,甚至是只要CV一次,改几个名称,就可以实现功能了,而且总归起来,都可以由一些公用的页面更改而来,因此,结合我日常开发中使用到的页面,封装一个适合自己的代码生成器 ...

  4. X-Admin&ABP框架开发-设置管理

    在网站开发中,设置是不可缺少的一环,如用户设置.系统设置.甚至是租户设置等.ABP对于设置的管理已经做了很好的处理,我们可以借助巨人的力量来完成我们的冒险. ABP官网地址:https://aspne ...

  5. X-Admin&ABP框架开发-RBAC

    在业务系统需求规划过程中,通常对于诸如组织机构.用户和角色等这种基础功能,通常是将这部分功能规划到通用子域中,这也说明了,对于这部分功能来讲,是系统的基石,整个业务体系是建立于这部分基石之上的,当然, ...

  6. X-Admin&ABP框架开发-数据字典

    在业务型的系统开发中,我们需要维护各种个样的类型,比如客户类型.客户行业.商品类型等等,这些类型往往信息量不多,并且相似度极高,如果采用一类型一表去设计,将会造成极大的工作量,通过将这部分类型的信息进 ...

  7. X-Admin&ABP框架开发-租户管理

    软件即服务概念的推动,定制化到通用化的发展,用一套代码完成适应不同企业的需求,利用多租户技术可以去做到这一点.ABP里提供了多租户这一概念并且也在Zero模块中实现了这一概念. 一.多租户的概念 单部 ...

  8. 高薪诚聘熟悉ABP框架的.NET高级开发工程师(2016年7月28日重发)

    招聘单位是ABP架构设计交流群(134710707)群主阳铭所在的公司-上海运图贸易有限公司 招聘岗位:.NET高级开发工程师工作地点:上海-普陀区 [公司情况]上海运图贸易有限公司,是由易迅网的创始 ...

  9. ABP框架实践基础篇之开发UI层

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 说明 其实最开始写的,就是这个ABP框架实践基础篇.在写这篇博客之前,又回头复习了一下ABP框架的理论,如果你还没学习,请查看AB ...

随机推荐

  1. 【docker学习二】CentOS7.5+Docker 镜像(容器)的使用

    承接上篇:https://mp.csdn.net/postedit/82744127 上文介绍了容器与镜像的基本操作,这里总结下容器的使用. 先在官网找到一个镜像: https://hub.docke ...

  2. 有用的java学习网站

    1.在线编译运行Java代码的网站 https://www.compilejava.net/ 2. 综合学习网站: http://www.tutorialspoint.com/,可以在线执行多种编程语 ...

  3. C# 异步转同步 TaskCompletionSource

    本文通过TaskCompletionSource,实现异步转同步 首先有一个异步方法,如下异步任务延时2秒后,返回一个结果 private static async Task<string> ...

  4. Fabric1.4源码解析:客户端安装链码

          看了看客户端安装链码的部分,感觉还是比较简单的,所以在这里记录一下.       还是先给出安装链码所使用的命令好了,这里就使用官方的安装链码的一个例子: #-n 指定mycc是由用户定义 ...

  5. c#基础三

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  6. Disruptor 详解 二

    Disruptor 的大名从很久以前就听说了,但是一直没有时间:看完以后才发现其内部的思想异常清晰,很容易就能前移到其他的项目,所以仔细了解一下还是很有必要的这.篇博客将主要从源码角度分析,Disru ...

  7. 使用gets函数常见问题

    C语言面试经常会考如下一道题,哪里有错误: #include <stdio.h>    int main()  {     char string[100] = {'\0'};       ...

  8. Managing Network Usage

    This lesson describes how to write applications that have fine-grained control over their usage of n ...

  9. 简单的量子算法(一):Hadamard 变换、Parity Problem

    Hadamard Transform Hadamard 变换在量子逻辑门中提过,只不过那时是单量子的Hadamard门,负责把\(|1\rangle\)变成\(|-\rangle\),\(|0\ran ...

  10. exe崩溃用windbgattach后有宝贵现场,可看程序退出线程等,千万不要清屏

    exe崩溃用windbgattach后有宝贵现场,可看程序退出线程等,千万不要清屏