网站正常运行中有时出现异常在所难免,查看系统运行日志分析问题并能够根据错误信息快速解决问题尤为重要,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. mysql索引结构

    mysql中索引的数据结构: 1.基本上所有的索引都是B-Tree结构,一部分还有HASH索引. 2.索引分类(功能) 主键索引:一张表中最多有一个主键索引,而且该字段值不能为NULL,不能重复. 唯 ...

  2. 正则RegExp对象的用法

    RegExp实例方法: 1.Test() RegExpObject.test(string) 判断string中是否有与表达式匹配的字符串,有则返回true,否则返回false 例如 var patt ...

  3. spring boot 2.0 thymeleaf调试时正常,打包后运行报错. 找不到模板文件.

    使用th:fragment  定义模板 使用 th:replace  来添加模板到需要的地方. 使用时发现一个非常奇怪的问题. 本机idea 调试环境一切正常, 但是打成jar包以后报错,提示找不到对 ...

  4. 删除git中缓存的用户名和密码

    我们使用Git命令去clone Gitlab仓库的代码时,第一次弹框提示输入账号密码的时候输错了,然后后面就一直拒绝,不再重复提示输入账号密码,怎么破? git报错信息 运行一下命令缓存输入的用户名和 ...

  5. kuangbin专题 专题一 简单搜索 Dungeon Master POJ - 2251

    题目链接:https://vjudge.net/problem/POJ-2251 题意:简单的三维地图 思路:直接上代码... #include <iostream> #include & ...

  6. Spring Boot2(十二):手摸手教你搭建Shiro安全框架

    一.前言 SpringBoot+Shiro+Mybatis完成的. 之前看了一位小伙伴的Shiro教程,跟着做了,遇到蛮多坑的(´இ皿இ`) 修改整理了一下,成功跑起来了.可以通过postman进行测 ...

  7. python3+pyQt5+QtDesignner实现窗口化猜数字游戏

    描述:使用QtDesignner设计界面,pyQt5+python3实现主体方法制作的猜数字游戏. 游戏规则:先选择游戏等级:初级.中级.高级.魔鬼级,选择完游戏等级后点击“确定”,然后后台会自动生成 ...

  8. centos下安装色彩scrapy

    一.安装Python2.7.6 更新CentOS lib库文件 yum -y update 安装开发工具包 yum groupinstall -y development 安装扩展包 yum inst ...

  9. 哈工大计算机网络Week2-网络应用数据交换

    目录 网络应用数据交换 P2P应用:原理与文件分发 纯P2P架构 文件分发:客户机/服务器 vs. P2P CS 为什么是这样的?不应该传送和发出难道是并行的??? P2P P2P文件分发典型例子:B ...

  10. 20131222-Dom省市加载-第二十七天

    [1]省市选择 <head> <title></title> <script type="text/javascript"> win ...