本文将使用一个Nuget的一个组件库来实现一个简单强大的日志记录功能,包采用线程安全实现,所有的记录在后台完成,即使您在前台调用100万次方法,耗时也不过1000ms(具体时间依照电脑性能决定),支持日志等级,并提供了一个控件用于分析所有的日志消息。

在visual studio 中的Nuget管理器中可以下载安装,也可以直接在Nuget控制台输入下面的指令安装:

Install-Package HslCommunication

Nuget安装教程:http://www.cnblogs.com/dathlin/p/7705014.html

联系作者及加群方式(激活码在群里发放):http://www.hslcommunication.cn/Cooperation

本组件提供了一个日志功能,实现了常用的3中日志模式:

  • 单日志文件模式,日志始终都向该文件写入,需要程序中自行清除或手动编写代码清空,不然文件会很大。
  • 根据文件大小存储的多文件模式,一个日志文件写入达到某个数值时,创建新文件写入。
  • 根据时间日期的多文件模式,每条日志将根据写入的时间日志来判断文件名,比如创建按每天存储的日志。

我也曾使用过.net中大名鼎鼎的log4net日志组件,一般使用起来确实方便,但是我在诸如实现上述的需求的时候就特别麻烦,而且log4net功能众多,大多数功能并不是我所需要的,我就需要一个实现txt日志的存储方式,简单高效,多种模式即可。于是就自行开发了一个简单高效的日志组件,并集成到了该通信库中,本日志组件还提供了一个分析控件及窗口,可以对一个长长的日志文件进行分析统计(只对本组件生成的日志有效),快速定位需要查找的日志信息,支持使用正则表达式来筛选,本日志组件也提供了分级存储。

Demo程序下载 HslCommunicationDemo.zip

使用之前先要进行命名控件的引用,如下:

using HslCommunication.LogNet;

  

实例化

首先先实例化一个对象,如果您用于整个application的日志存储,可以定义成静态对象。或者直接定义在form窗口的下面也可以。此处先实例化单文件存储的机制

private ILogNet logNet = new LogNetSingle("D:\\123.txt");

  

我们通常的做法是日志文件存储在exe程序目录下的Logs文件夹中,无论在服务器端还是客户端都是非常适用的,所以

private ILogNet logNet = new LogNetSingle(Application.StartupPath + "\\Logs\\123.txt");

  

写日志

接下来你就可以在窗口的其他地方进行写入日志了,本组件提供了5个等级的日志写入功能,名称参考了常规的日志等级,有 DEBUG , INFO, WARN , ERROR , FATAL ,根据需要进行存储,还提供了对exception异常的方法支持和自定义的描述化文本写入,该文本不属于日志范畴,在日志分析中会被忽略,如下代码演示几种不同的写入(写入的方式采用统一的接口实现,对于三种日志模式都是适用的):

        private void userButton1_Click(object sender, EventArgs e)
{
// 一般日志写入
logNet.WriteDebug("调试信息");
logNet.WriteInfo("一般信息");
logNet.WriteWarn("警告信息");
logNet.WriteError("错误信息");
logNet.WriteFatal("致命信息");
logNet.WriteException(null, new IndexOutOfRangeException()); // 带有关键字的写入,关键字建议为方法名或是类名,方便分析的时候归类搜索
logNet.WriteDebug("userButton1_Click", "调试信息");
logNet.WriteInfo("TestForm", "一般信息");
logNet.WriteWarn("随便什么", "警告信息");
logNet.WriteError("userButton1_Click", "错误信息");
logNet.WriteFatal("userButton1_Click", "致命信息");
logNet.WriteException("userButton1_Click", new IndexOutOfRangeException());
}

写入异常时会被自动赋予 FATAL 等级。写入效果如下:

下面再说明写入描述文本的时候发生的事情:

logNet.WriteDescrition("这是一条描述文本");

 

描述性文本的前面会再新增一行作为明显的区分。描述性文本不列入到日志分析工具中,会被自动被过滤。

 

设置等级

为什么要实现日志分级呢?有两个巨大的好处。第一个好处是方便在日志追述的时候进行筛选,比如我需要查看日志中致命错误的时候就尤为重要,可以进行快速的筛选。第二个好处就是用于开发的时候调试使用,有时候我们为了快速的找到程序问题的时候,会对程序运行中各种数据状态,系统状态进行输出,然后分析日志得出结论。当你已经写了很多很多的

logNet.WriteDebug("调试信息");

代码后,准备发布使用的时候不想输出这种仅用于调试的时候的日志,总不可能取消所有的调试日志吧?效率太低,万一以后需要恢复输出就麻烦了,所以本日志组件支持写入日志的时候的等级设置,如果我们把日志的等级设置为INFO级别,那么所有的DEBUG级别的日志都不会存储,所以我们在发布软件的时候,只要设置等级就行。

下面再来说明下如何设置日志存储等级。使用方法:

logNet.SetMessageDegree(HslMessageDegree.DEBUG);//所有等级存储
logNet.SetMessageDegree(HslMessageDegree.INFO);//除DEBUG外,都存储
logNet.SetMessageDegree(HslMessageDegree.WARN);//除DEBUG和INFO外,都存储
logNet.SetMessageDegree(HslMessageDegree.ERROR);//只存储ERROR和FATAL
logNet.SetMessageDegree(HslMessageDegree.FATAL);//只存储FATAL
logNet.SetMessageDegree(HslMessageDegree.None);//不存储任何等级

选择上面的一行代码执行就行。

自定义事件

组件默认存储所有的等级,如果需要设置,在实例化后即可设置等级。日志组件支持一个事件,在所有的日志进行存储前(被日志等级过滤掉的不会触发)会报告事件,可以用于其他操作或是控制台的显示等等,注意: 如果在事件关联方法中直接访问UI线程,会异常

这个事件有个非常大的好处,可以统一输出显示你的程序中所有地方的日志,方便统一的控制和处理。

logNet.BeforeSaveToFile += LogNet_BeforeSaveToFile;
private void LogNet_BeforeSaveToFile(object sender, HslEventArgs e)
{
// 如果需要UI显示,就要取消注释下方的代码 //if(InvokeRequired)
//{
// Invoke(new Action(() =>{
// LogNet_BeforeSaveToFile(sender, e);
// }));
// return;
//} string degree = e.HslMessage.Degree.ToString();//获取等级
DateTime time = e.HslMessage.Time;//获取时间
string text = e.HslMessage.Text;//日志文本
int threadId = e.HslMessage.ThreadId;//记录日志的线程id
}

  

这个事件在2019年2月10日 16:36:41上新增了一个额外的功能,就是允许你手动取消当前日志的存储

        private void LogNet_BeforeSaveToFile( object sender, HslEventArgs e )
{
e.HslMessage.Cancel = checkBox1.Checked;
}

假设这样设置后,所有的日志都不存储到文件中去。

        private void LogNet_BeforeSaveToFile( object sender, HslEventArgs e )
{
if (e.HslMessage.Degree != HslMessageDegree.INFO)
{
e.HslMessage.Cancel = checkBox1.Checked;
}
}

如果这么写,就是只存储INFO等级的日志信息。

过滤指定的关键字日志存储

有些日志数据可能我们想要触发BeforeSaveToFile事件,但是不能存储到日志文件里,那么可以直接按照如下的配置进行设置,会过滤掉存储到文件中,如下就是过滤掉关键字的信息

logNet.FiltrateKeyword( "123" );

按文件大小存储的实例化

若要按照文件大小进行存储,例如日志存储2M后,自动生成新的文件,然后存满2M后生成新文件,如此重复,则需要指定文件的 存储路径大小 ,这种方式存储的文件名称不可控制,自动定义为 Logs_20170903170604.txt 的格式,会以当前时间自动命名,如下举例了实例化一个2M大小的对象:

ILogNet logNet = new LogNetFileSize(Application.StartupPath + "\\customer1", 2 * 1024 * 1024);

  

只要定义了对象,就可以按照上述写入日志的代码来写了。

按时间日期存储的实例化

也是一种多文件的存储机制,和按照大小的存储非常类似,此处可以配置按照每小时生成新的文件,每天新的文件,每月新的文件,每季度新的文件,每年新的文件,生成的文件名称也是固定的,需要指定 路径存储模式

ILogNet logNet = new LogNetDateTime(Application.StartupPath + "\\customer2",GenerateMode.ByEveryHour);//按每小时
ILogNet logNet = new LogNetDateTime(Application.StartupPath + "\\customer2", GenerateMode.ByEveryDay);//按每天
ILogNet logNet = new LogNetDateTime(Application.StartupPath + "\\customer2", GenerateMode.ByEveryMonth);//按每月
ILogNet logNet = new LogNetDateTime(Application.StartupPath + "\\customer2", GenerateMode.ByEverySeason);//按每季度
ILogNet logNet = new LogNetDateTime(Application.StartupPath + "\\customer2", GenerateMode.ByEveryYear);//按每年

  

单文件模式

单文件的模式在上述已经作为演示说明过了,但是单文件模式提供了两个额外的方法:

  • 获取该文件日志中所有的内容
  • 清空该文件的所有数据

具体的代码如下所示:

LogNetSingle logNetSingle = logNet as LogNetSingle;
if (logNetSingle != null)
{
string logData = logNetSingle.GetAllSavedLog();//获取所有的日志信息
logNetSingle.ClearLog();//清除所有的日志信息
}

  

日志查看器

如果只提供了一个日志的写入而没有分析工具,那么本组件就是没什么竞争力的,本日志组件提供了一个大杀器,日志分析控件!您可以集成到您自己的系统中,该控件只需要接受一个 日志源字符串 (就是日志文件的所有字符串数据,服务器读取文件发送给远程客户端就可以现实远程查看日志分析!棒不棒!)原先的 ClientServerProject 项目中已经带有了2个日志查看器,一个服务器端使用了本组件提供的标准form窗口,客户端使用了日志分析控件实现远程查看功能,具体代码可以参照 ClientServerProject 项目的代码。

功能概述

  • 对日志文件中的所有等级日志进行分析,每种等级多少个
  • 可以同时根据日志等级和时间区段来筛选日志,比如查看某一时间段的 DEBUG 等级日志
  • 可以进行可视化分析,查看日志数据的时间分布情况
  • 在可视化的界面,如果某个区间段的某日数量特别高,鼠标移动上去后还可以自动跳转

此处直接演示一个组件标准的日志查看窗口,这个窗口也可以在wpf项目中显示:

        private void userButton13_Click(object sender, EventArgs e)
{
// 日志查看器
using (HslCommunication.LogNet.FormLogNetView form = new HslCommunication.LogNet.FormLogNetView())
{
form.ShowDialog();
}
}

效果上图

查看日志信息

上图中点击了 信息 按钮后,显示的图形发生了变化,只显示了 信息 等级日志

光标移动到某一区间后,下方会有该区间的日志数量和时间范围,双击后的操作就您自己去发现了。^_^

控件的方式,新建一个窗口,将组件的控件给拖进去,如果这个组件在工具箱不显示,那么需要将dll文件拖到工具箱。

至于显示信息代码:

        private void FormLogNetTest_Load(object sender, EventArgs e)
{
// 该source可以是本地读取的文件,也可以是网络发送过来的数据
string source = Encoding.UTF8.GetString(System.IO.File.ReadAllBytes("123.txt")); // 传入路径
logNetAnalysisControl1.SetLogNetSource(source);
}

C# 日志记录分级功能使用 按照日期,大小,或是单文件存储的更多相关文章

  1. python内置函数print输出到文件,实现日志记录的功能

    # bulid time 2018-6-22 import os import time def log(*args, **kwargs): # *kargs 为了通用 可不传 rule = &quo ...

  2. 基于java.util.logging实现轻量级日志记录库(增加根据当前类class初始化,修复线程池模型(javaEE)下的堆栈轨迹顺序与当前调用方法不一致问题)

    前言: 本章介绍自己写的基于java.util.logging的轻量级日志记录库(baseLog). 该版本的日志记录库犹如其名,baseLog,是个实现日志记录基本功能的小库,适合小型项目使用,方便 ...

  3. mysql数据库安全性配置——日志记录

    一:开启数据库日志记录 (1)在查看数据库是否开启日志记录,默认是OFF,即关闭状态.(可在数据库中执行该查询语句,也可在服务器端执行) show variables like 'log_bin'; ...

  4. 【干货】.NET开发通用组件发布(四) 日志记录组件

    组件介绍和合作开发 http://www.cnblogs.com/MrHuo/p/MrHuoControls.html 日志记录组件功能介绍 通过基类Logger,实现了文本记录日志和数据库记录日志两 ...

  5. asp.net Web项目中使用Log4Net进行错误日志记录

      使用log4net可以很方便地为应用添加日志功能.应用Log4net,开发者可以很精确地控制日志信息的输出,减少了多余信息,提高了日志记录性能.同时,通过外部配置文件,用户可以不用重新编译程序就能 ...

  6. 使用 ssm 实现登录日志记录

    使用 ssm 实现登录日志记录 学习总结 一.基础准备 1. 实现效果 2. 数据表 2.1 登陆日志信息表 2.3 员工表 二.代码实现 1. SysLogLogin 实体类 2. LogAspec ...

  7. Hibernate使用Log4j日志记录(使用xml文件)

    日志记录使程序员能够将日志详细信息永久写入文件. Log4j和Logback框架可以在hibernate框架中使用来支持日志记录. 使用log4j执行日志记录有两种方法: 通过log4j.xml文件( ...

  8. 如何自行给指定的SAP OData服务添加自定义日志记录功能

    有的时候,SAP标准的OData实现或者相关的工具没有提供我们想记录的日志功能,此时可以利用SAP系统强大的扩展特性,进行自定义日志功能的二次开发. 以SAP CRM Fiori应用"My ...

  9. IOS异常日志记录与展现功能

    在平常的APP开发过程中经常碰到程序遇到异常闪退的问题,通过日志可以把相关的详细错误信息进行记录,本实例要记录不管在哪个页面出错都要进行记录,这边使用到的日志记录插件CocoaLumberjack,以 ...

随机推荐

  1. List添加map,后添加的map覆盖前面的问题

    List resultList = new ArrayList(); Map map = new HashMap(); while(rs.next()){ String userid = rs.get ...

  2. newcoder 小A的柱状图(单调栈)题解

    题目描述 柱状图是有一些宽度相等的矩形下端对齐以后横向排列的图形,但是小A的柱状图却不是一个规范的柱状图,它的每个矩形下端的宽度可以是不相同的一些整数,分别为a[i] 每个矩形的高度是h[i] ,现在 ...

  3. HAOI(多省联考)2019退役记

    等着回头写 算了今天先写点 Day -1 打扫下机房,不想写题,不想考试.... Day 0 上午颓了一上午 下午看下考场结果去早了 ZYZ 全员进队! Day 1 上来T1,01Tire!,开码,半 ...

  4. Learning-Python【26】:反射及内置方法

    反射的概念 可以用字符串的方式去访问对象的属性,调用对象的方法(但是不能去访问方法),Python 中一切皆对象,都可以使用反射. 反射有四种方法: hasattr:hasattr(object, n ...

  5. CSS自定义样式

    CSS自定义样式 1. 自定义字体 先将字体文件放到web服务器上,需要时自动下载到用户计算机上 属性:@font-face 例: @font-face{ font-family:myFont; sr ...

  6. Codeforces Round #FF (Div. 2) D. DZY Loves Modification 优先队列

    D. DZY Loves Modification time limit per test 2 seconds memory limit per test 256 megabytes input st ...

  7. js Infinity 属性

    Infinity 属性用于存放表示正无穷大的数值. 说明 无法使用 for/in 循环来枚举 Infinity 属性,也不能用 delete 运算符来删除它. Infinity 不是常量,可以把它设置 ...

  8. python 获取subprocess进程执行后返回值

    test.py #coding=utf- import subprocess compilePopen = subprocess.Popen('gcc haha',shell=True,stderr= ...

  9. map的循环删除操作

    1.错误示例 Map<String,InterfaceOutParam> outCodes1 = outParamList.stream().collect(Collectors.toMa ...

  10. python3中 getpass模块使用

    getpass在IDLE中报错 CMD中可以使用 import getpass usr = getpass.getuser print(usr) 返回值为当前windows登陆用户名