您的位置:首页 > 编程语言 > Java开发

Java 一些记录日志系统

2016-11-05 14:56 169 查看
在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息。 
Java世界中,有很多的日志工具库来实现日志功能,避免我们重复造轮子,下面我们就来逐一了解日志工具。

1. 最常用的 在本地测试用的 System.out.println();

这种方式使用起来非常简单,但是缺点却是非常多的: 
- 输出内容不可控 
- 可读性差 
- 大量的IO操作使程序变慢

public class TestLogger {
public static boolean debug = false;
public static void main(String[] args) {

for (int count = 0; count < 4; count++) {
if (count % 2 == 0) debug = true;
else debug = false;

if (debug) System.out.println("系统消息: 第 " + count + "次打印。");
}
}
}



2. JDK的Logging

从JDK1.4开始,JDK自带了一套日至系统,其最大的优点是不需要任何其他类库的支持,只要有JDK就可以运行,但是其易用性、功能和扩展性很差,因此在商业上很少使用。 

JDK Logging把日志分为9个级别,分别为:ALL、FINEST、FINER、FINE、CONFIG、INFO、WARNING、SERVER、OFF,等级依次升高,较高等级屏蔽较低等级。 
public class TestJDKLogger {
public static final Logger logger = Logger.getLogger(TestJDKLogger.class.toString());

public static void main(String[] args) {
logger.info("jdk loggin info : a msg.");
}
}

其中的Logger是:java.util.logging.Logger

1. 对于JDK自带的Logging,会有一个对应的配置文件
logging.properties
,位置在
$JAVA_HOME/jre/lib/logging.properties
,我们首先看一个原始的配置文件。可以看到里面设置了默认的等级为
INFO
,因此
INFO
等级以下的信息就不会输出,要想输出其他等级的信息需要修改这里的level信息。

创建一个LogManager

默认是java.util.logging.LogManager,但是也可以自定义,修改系统属性"java.util.logging.manager"即可,源码如下(manager就是LogManager):
try {
cname = System.getProperty("java.util.logging.manager");
if (cname != null) {
try {
Class clz = ClassLoader.getSystemClassLoader().loadClass(cname);
manager = (LogManager) clz.newInstance();
} catch (ClassNotFoundException ex) {
Class clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
manager = (LogManager) clz.newInstance();
}
}
} catch (Exception ex) {
System.err.println("Could not load Logmanager \"" + cname + "\"");
ex.printStackTrace();
}
if (manager == null) {
manager = new LogManager();
}


加载配置文件

默认是jre目录下的lib/logging.properties文件,也可以自定义修改系统属性"java.util.logging.config.file”,源码如下:
String fname = System.getProperty("java.util.logging.config.file");
if (fname == null) {
fname = System.getProperty("java.home");
if (fname == null) {
throw new Error("Can't find java.home ??");
}
File f = new File(fname, "lib");
f = new File(f, "logging.properties");
fname = f.getCanonicalPath();
}
InputStream in = new FileInputStream(fname);
BufferedInputStream bin = new BufferedInputStream(in);
try {
readConfiguration(bin);
} finally {
if (in != null) {
in.close();
}
}


创建Logger,并缓存起来,放置到一个Hashtable中,并把LogManager设置进新创建的logger中


3. Log4j

Log4j是目前应用最广泛的日志控件,它把日志分为ALL、TRACE、DEBUG、INFO、WARNING、ERROR、FITAL、OFF等几个等级,等级依次升高,依然是高等级屏蔽低等级。使用Log4j需要下载相应的jar包

log4j

maven依赖如下:

<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>

使用方式:

第一步:编写log4j.properties配置文件,放到类路径下

log4j.rootLogger = debug, console
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} %m%n
第二步:代码中如下使用

public class Log4jTest {
private static final Logger logger=Logger.getLogger(Log4jTest.class);
public static void main(String[] args){
if(logger.isTraceEnabled()){
logger.debug("log4j trace message");
}
if(logger.isDebugEnabled()){
logger.debug("log4j debug message");
}
if(logger.isInfoEnabled()){
logger.debug("log4j info message");
}
}
}

补充:

1 上述方式默认到类路径下加载log4j.properties配置文件,如果log4j.properties配置文件不在类路径下,则可以选择如下方式之一来加载配置文件

使用classLoader来加载资源PropertyConfigurator.configure(Log4jTest.class.getClassLoader().getResource(“properties/log4j.properties”));

使用log4j自带的Loader来加载资源PropertyConfigurator.configure(Loader.getResource(“properties/log4j.properties”));

第一种情况:没有指定配置文件路径

1 第一步: 引发LogManager的类初始化
Logger.getLogger(Log4jTest.class)的源码如下:

static public Logger getLogger(Class clazz) {
return LogManager.getLogger(clazz.getName());
}


2 第二步:初始化一个logger仓库Hierarchy
Hierarchy的源码如下:
public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
private LoggerFactory defaultFactory;
Hashtable ht;
Logger root;
//其他略
}

LoggerFactory defaultFactory: 就是创建Logger的工厂
Hashtable ht:用来存放上述工厂创建的Logger
Logger root:作为根Logger
LogManager在类初始化的时候如下方式来实例化Hierarchy:
static {
Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
//略
}

new RootLogger作为root logger,默认是debug级别
最后把Hierarchy绑定到LogManager上,可以在任何地方来获取这个logger仓库Hierarchy

3 第三步:在LogManager的类初始化的过程中默认寻找类路径下的配置文件
通过org.apache.log4j.helpers.Loader类来加载类路径下的配置文件:
Loader.getResource("log4j.xml");
Loader.getResource("log4j.properties")

优先选择xml配置文件

4 第四步:解析上述配置文件
如果是xml文件则org.apache.log4j.xml.DOMConfigurator类来解析
如果是properties文件,则使用org.apache.log4j.PropertyConfigurator来解析
不再详细说明解析过程,看下解析后的结果:
设置RootLogger的级别
对RootLogger添加一系列我们配置的appender(我们通过logger来输出日志,通过logger中的appender指明了日志的输出目的地)

5 第五步:当一切都准备妥当后,就该获取Logger了
使用logger仓库Hierarchy中内置的LoggerFactory工厂来创建Logger了,并缓存起来,同时将logger仓库Hierarchy设置进新创建的Logger中

第二种情况,手动来加载不在类路径下的配置文件
PropertyConfigurator.configure 执行时会去进行上述的配置文件解析,源码如下:
public static void configure(java.net.URL configURL) {
new PropertyConfigurator().doConfigure(configURL,
LogManager.getLoggerRepository());
}


仍然先会引发LogManager的类加载,创建出logger仓库Hierarchy,同时尝试加载类路径下的配置文件,此时没有则不进行解析,此时logger仓库Hierarchy中的RootLogger默认采用debug级别,没有appender而已。

然后解析配置文件,对上述logger仓库Hierarchy的RootLogger进行级别的设置,添加appender

此时再去调用Logger.getLogger,不会导致LogManager的类初始化(因为已经加载过了)

第三种情况,配置文件在类路径下,而我们又手动使用PropertyConfigurator去加载
也就会造成2次加载解析配置文件,仅仅会造成覆盖而已(对于RootLogger进行从新设置级别,删除原有的appender,重新加载新的appender),所以多次加载解析配置文件以最后一次为准。


3.3 主要对象总结

LogManager: 它的类加载会创建logger仓库Hierarchy,并尝试寻找类路径下的配置文件,如果有则解析

Hierarchy : 包含三个重要属性:
LoggerFactory logger的创建工厂
Hashtable 用于存放上述工厂创建的logger
Logger root logger,用于承载解析文件的结果,设置级别,同时存放appender

PropertyConfigurator: 用于解析log4j.properties文件

Logger : 我们用来输出日志的对象
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java logger 日志