自己写的日志框架--linkinLog4j--实现基本的框架功能
OK,上面一步我们已经知道了日志框架的必要性,然后我们也对比了直接不用日志框架来记录日志的种种弊端。现在我们开始就来一步一步的实现自己的日志框架。
大体的思路如下:
1,实现多种日志级别,通过设值不同的日志级别来控制项目中日志的输出等级,所以这里就要写一个等级的枚举,这个枚举就定义LinkinLogLevel好了。
2,开始写自己的日志核心类,定义LinkinLog4j类。然后这里要初始化日志对象,然后提供一系列的输出日志的方法,比如info(),debug()等。
3,要控制等级,比如调用info()方法,那么就应该按照约定来输出INFO级别以上的日志,自动屏蔽掉INFO等级之下的输出。
4,每个输出日志的方法最终都要调用一个输出日志的方法,定义log()方法,该方法将一系列的日志内容(类名,等级,日志信息等)输出到控制台上。
OK,大致的思路有了,我们现在开始写代码,现在我们写代码。
日志等级定义枚举代码如下:
package test.junit4test; import java.util.HashMap;
import java.util.Map; /**
* @创建作者: LinkinPark
* @创建时间: 2016年2月23日
* @功能描述: 日志等级枚举。
* <p>
* Log4J中的所有的等级如下:all→trace→debug→info→warn→error→fatal→off
* 这里自己模拟的等级如下:all→debug→info→error→off
* </p>
*/
public enum LinkinLogLevel
{
ALL(Integer.MIN_VALUE, "ALL"), DEBUG(10000, "DEBUG"), INFO(20000, "INFO"), ERROR(30000, "ERROR"),
OFF(Integer.MAX_VALUE, "OFF"); private final int status;
private final String desc; private LinkinLogLevel(int status, String desc)
{
this.status = status;
this.desc = desc;
} public int getStatus()
{
return status;
} public String getDesc()
{
return desc;
} public String toString()
{
return status + "";
} /**
* @创建时间: 2016年2月24日
* @相关参数: @return
* @功能描述: 将所有的枚举封装一个Map返回
*/
public static Map<Integer, LinkinLogLevel> getLevelMap()
{
Map<Integer, LinkinLogLevel> levelMap = new HashMap<>(5, 1);
LinkinLogLevel[] values = LinkinLogLevel.values();
for (LinkinLogLevel linkinLogLevel : values)
{
levelMap.put(linkinLogLevel.getStatus(), linkinLogLevel);
}
return levelMap;
} }
日志框架核心类LinkinLog4j的代码如下:
package test.junit4test; import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.Objects; public class LinkinLog4j
{
private static final Map<Integer, LinkinLogLevel> levelMap; static
{
levelMap = LinkinLogLevel.getLevelMap();
} // 定义2个属性,一个是每个日志文件的名称,一个是每个日志文件的等级
private final String name;
private final int level; /***************** 定义一系列构造器 ***********************************/
public LinkinLog4j(Class<?> klass, LinkinLogLevel level)
{
this(klass.getName(), level.getStatus());
} public LinkinLog4j(Class<?> klass)
{
this(klass.getName(), LinkinLogLevel.ALL.getStatus());
} public LinkinLog4j(String name, int level)
{
this.name = name;
this.level = level;
} /***************** 定义一系列输出日志的方法 ***********************************/
public void info(String message)
{
info(message, null);
} public void info(String message, Throwable cause)
{
log(LinkinLogLevel.INFO.getStatus(), message, cause);
} public void debug(String message)
{
debug(message, null);
} public void debug(Throwable cause)
{
debug(null, cause);
} public void debug(String message, Throwable cause)
{
log(LinkinLogLevel.DEBUG.getStatus(), message, cause);
} public void error(String message)
{
error(message, null);
} public void error(String message, Throwable cause)
{
log(LinkinLogLevel.ERROR.getStatus(), message, cause);
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param level
* @相关参数: @param message
* @相关参数: @param cause
* @功能描述: 核心日志方法,输出日志内容到控制台
* <p>
* 判断日志类定义的日志级别,控制一些日志方法的执行和不执行
* 依次将日志的信息一步一步的添加到StringBuilder中然后输出
* TODO
* 1,这里最好使用责任链默认,上一步操作保持对下一步操作对象的封装,实现解耦
* 2,重定向输出,现在默认是控制台,将来重写writeLog方法,实现将日志输出到某一个文件下
* </p>
*/
private void log(int level, String message, Throwable cause)
{
if (isLevelEnabled(level))
{
return;
}
StringBuilder builder = new StringBuilder(32);
appendLogName2Log(builder, name);
appendLevel2Log(builder, level);
appendMessqge2Log(builder, message);
appendCauseInfo2Log(builder, cause);
writeLog(builder);
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param level 日志类中调用的各种输出日志方法的等级
* @相关参数: @return true:忽略该输出日志方法,false:执行该输出日志方法
* @功能描述: 控制一些日志的输出还是忽略
* <p>
* 日志类自己配置的日志等级VS日志类中调用的各种输出日志方法的等级
* </p>
*/
private boolean isLevelEnabled(int level)
{
if (level < this.level)
{
return true;
}
return false;
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param builder
* @相关参数: @param level
* @功能描述: 追加日志等级
*/
private void appendLevel2Log(StringBuilder builder, int level)
{
builder.append("[").append(levelMap.get(level).getDesc()).append("]").append(" ");
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param builder
* @相关参数: @param name
* @功能描述: 追加日志名字
*/
private void appendLogName2Log(StringBuilder builder, String name)
{
builder.append("[").append(name).append("]-");
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param builder
* @相关参数: @param message
* @功能描述: 追加日志内容信息
*/
private void appendMessqge2Log(StringBuilder builder, String message)
{
builder.append(message);
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param builder
* @相关参数: @param cause
* @功能描述: 追加日志异常
*/
private void appendCauseInfo2Log(StringBuilder builder, Throwable cause)
{
if (Objects.nonNull(cause))
{
builder.append("<");
builder.append(cause.getMessage());
builder.append(">");
builder.append(System.getProperty("line.separator"));
StringWriter writer = new StringWriter();
PrintWriter printer = new PrintWriter(writer);
cause.printStackTrace(printer);
printer.close();
builder.append(writer.toString());
}
} /**
* @创建时间: 2016年2月24日
* @相关参数: @param str 所有的日志输出的内容
* @功能描述: 控制台输出日志
*/
public void writeLog(StringBuilder str)
{
System.out.println(str.toString());
} }
OK,现在代码写完了,我们自己写2个测试类来测试下我们的日志框架有没问题。
1,现在我们测试正常输出日志情况,LinkinLog4jTest代码如下:
package test.junit4test; import org.junit.Test; public class LinkinLog4jTest
{ LinkinLog4j log = new LinkinLog4j(LinkinLog4jTest.class, LinkinLogLevel.INFO); @Test
public void testLog()
{
log.debug("debug()。。。");
log.info("info()。。。");
log.error("error()。。。");
} }
看下junit控制台输出:
看下eclipse控制台输出:
[test.junit4test.LinkinLog4jTest]-[INFO] info()。。。
[test.junit4test.LinkinLog4jTest]-[ERROR] error()。。。
OK,上面我配置了LinkinLog4jTest的日志级别是INFO级别,所以自动忽略掉了debug()方法的日志输出。当然,我在初始化日志的时候也可以不传入日志等级,这样子的话就默认最低的等级,也就是输出所有的日志。
2,现在我们测试代码异常然后输出日志的情况。LinkinLog4jTest1代码如下:
package test.junit4test; import org.junit.Test; public class LinkinLog4jTest1
{ LinkinLog4j log = new LinkinLog4j(LinkinLog4jTest1.class); @Test
public void testLog()
{
try
{
throw new NullPointerException("测试异常日志空指针了呢");
}
catch (Exception e)
{
log.debug("testLog()方法抛出异常:" + e.getMessage());
}
log.debug("debug()。。。");
log.info("info()。。。");
log.error("error()。。。");
} }
junit绿条,然后控制台输出如下:
[test.junit4test.LinkinLog4jTest1]-[DEBUG] testLog()方法抛出异常:测试异常日志空指针了呢
[test.junit4test.LinkinLog4jTest1]-[DEBUG] debug()。。。
[test.junit4test.LinkinLog4jTest1]-[INFO] info()。。。
[test.junit4test.LinkinLog4jTest1]-[ERROR] error()。。。
OK,大致的日志框架我们都已经写完了,也实现了基本的功能,但是还是有好多的问题的。
1,这里我们初始化我们的每个日志类的时候就都要输出日志级别,如果不输出的话就默认最低,如何才能将初始化日志类的等级配置和代码解耦放到一个统一的地方来配置呢?使用XML统一配置就OK,也就是新增我们的日志配置文件来统一来配置和初始化我们的日志框架,给用户提供默认配置。
2,现在的框架我们都是打印日志到控制台,暂时还不支持打印日志到文件。
3,打印日志的一系列方法,最终调用同一个输出日志的方法,没有实现人为控制日志输出的功能。比如用户在打印日志的过程中,有些日志要输出这种样式,有些日志要输出那种样式,我们现在的框架暂时还不支持。
虽然日志功能在应用程序开发中是一个非常重要的部件,有些时候日志信息的好坏可以直接影响程序开发的进度。然而日志本身不涉及到任何业务逻辑,因而需要尽量减少它的侵入性,也就说它提供的接口应该尽量的简单。
为了实现接口的简单性,其中一种方法就是使用配置文件记录LinkinLog4j的配置信息,LinkinLog4j则根据配置信息初始化每一个LinkinLog4j实例。这些配置信息包括是否显示日志名称、时间信息;如果显示日志打印时间,其格式如何;默认的日志级别是什么;支持单独配置一些日志名称的日志级别;如果将日志打印到日志文件,则日志文件的名称和目录在哪里等信息。下一篇博客我将实现这里说的这些功能。
自己写的日志框架--linkinLog4j--实现基本的框架功能的更多相关文章
- 自己写的日志框架--linkinLog4j--框架可配置+提性能
OK,上一篇博客我们已经实现了日志框架的基本的功能,但是还有一个最大的问题就是日志输出地不能重定向,然后一些输出也不可控.那现在我们来实现一个比较完整的日志框架. 设计思路如下: 1,定义一堆常量Li ...
- Spring AOP 实现写事件日志功能
什么是AOP?AOP使用场景?AOP相关概念?Spring AOP组件?如何使用Spring AOP?等等这些问题请参考博文:Spring AOP 实现原理 下面重点介绍如何写事件日志功能,把日志保存 ...
- C#写文本日志帮助类(支持多线程)改进版(不适用于ASP.NET程序)
由于iis的自动回收机制,不适用于ASP.NET程序 代码: using System; using System.Collections.Concurrent; using System.Confi ...
- SQLite 预写式日志
SQLite在3.7.0版本引入了WAL (Write-Ahead-Logging),WAL的全称是Write Ahead Logging,它是很多数据库中用于实现原子事务的一种机制,引入WAL机制之 ...
- C#写文本日志帮助类(支持多线程)
代码: using System; using System.Configuration; using System.IO; using System.Threading.Tasks; namespa ...
- 预写式日志WAL
Chapter 25. 预写式日志(Write-Ahead Logging (WAL)) Table of Contents 25.1. WAL 的好处 25.2. WAL 配置 25.3. 内部 预 ...
- 【我们一起写框架】MVVM的WPF框架(五)—完结篇
前言 这篇文章是WPF框架系列的最后一篇,在这里我想阐述一下我对框架设计的理解. 我对框架设计的理解是这样的: 框架设计不应该局限于任何一种设计模式,我们在设计框架时,应该将设计模式揉碎,再重组:这样 ...
- 【我们一起写框架】MVVM的WPF框架(一)—序篇
前言 我想,有一部分程序员应该是在二三线城市的,虽然不知道占比,但想来应该不在少数. 我是这部分人群中的一份子. 我们这群人,面对的客户,大多是国内中小企业,或者政府的小部门.这类客户的特点是,资金有 ...
- 【我们一起写框架】MVVM的WPF框架(二)—绑定
MVVM的特点之一是实现数据同步,即,前台页面修改了数据,后台的数据会同步更新. 上一篇我们已经一起编写了框架的基础结构,并且实现了ViewModel反向控制Xaml窗体. 那么现在就要开始实现数据同 ...
- 【我们一起写框架】MVVM的WPF框架(三)—数据控件
这世上,没人能一次性写出完美无缺的框架:因为,任何一个框架都需要项目的淬炼,然后才能升华,趋近完美. 所以,框架是个反复修改的东西,最终形成的东西. 如果你学了一点技术,觉得自己可以写出框架了,觉得自 ...
随机推荐
- 快速了解Hibernate的使用
了解hibernate的使用 hibernate是作用于传统的mvc开发dao层的框架 在以往的开发中我们如何的编写dao的代码呢 1.原始的jdbc操作,在dao中到操作Connection/Sta ...
- jBPM学习之利用API完成流程实例
流程引擎对象ProcessEngine是jBPM4所有的Service API之源.在jBPM4中各种服务相互依存,但所有的Service API都从ProcessEngine中获得,由此可见Proc ...
- 【转】LDA数学八卦
转自LDA数学八卦 在 Machine Learning 中,LDA 是两个常用模型的简称: Linear Discriminant Analysis 和 Latent Dirichlet Alloc ...
- 使用xUnit为.net core程序进行单元测试(中)
第一部分: http://www.cnblogs.com/cgzl/p/8283610.html 下面有一点点内容是重叠的.... String Assert 测试string是否相等: [Fact] ...
- MYSQL:数据库安装 windows
最近在学习mysql,看到很多人在搭建mysql的时候遇到很多问题,我们在这里不讲安装版的配置过程,因为安装版的配置非常的简单.. windows下配置mysql 首先从官网下载社区版的安装包:最新版 ...
- Android基础_多媒体
一.MediaPlayer Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现 ...
- 学习web前端技术的笔记,仅供自己查阅备忘,移动对font-size的控制(并非原创)
假设根字体font-size的值是40px, 640/40=16,16就是px换算rem的值 function initHtmlFontSize(){ //获取可可视屏幕的宽度 var _width= ...
- 51nod1649- 齐头并进-最短路
1649 齐头并进 题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 在一个叫奥斯汀的城市,有n个小镇(从1到n编号),这些小镇通过 ...
- vue vue-style-loader !css-loader错误
最近在学习vue框架,使用webpack打包vue项目,在执行npm run start的时候 出现如下错误: This dependency was not found: * !!vue-style ...
- Linux-vmware tools安装与cdrom挂载(转)
昨天想直接复制虚拟机centos系统中命令行的内容到主机的txt文档上进行保存,发现不能实现虚拟机与主机之间的直接通讯,后来查资料发现原来是由于我的虚拟机没有安装vwmare tools的缘故. 一个 ...