log4j入门(转) --- 很详细 也很简单容易懂

log4j入门(转)
Log4j实在是很熟悉,几乎所有的Java项目都用它啊。但是我确一直没有搞明白。终于有一天我受不了了,定下心去看了一把文档,才两个小时,我终于搞明白了。一般情况下Log4j总是和Apache Commons-logging一起用的,我也就一起介绍吧。多了个东西不是更麻烦,而是更简单!

在Log4J中存在几个概念首先介绍一下,最最重要的两个是Logger和Appender(请参考Log4J手册),其实是继承层次以及输出控制。

首先Log4J中总是存在一个rootLogger,即使没有显示配置也是存在的,并且默认输出级别为DEBUG。
其它的logger都继承自这个rootLogger(如果其他logger未单独定义其输出级别)。
Log4J中的层次是用‘.‘来分隔的,如log4j.logger.com.example.test,这里并不是说log4j.logger后面一定是具体的包名乃至类名,
这个名称可以自定义,我们甚至可以定义一个log4j.logger.A.B.C, 在com.example.test中的类里取名称为A.B的logger,如
Logger logger = Logger.getLogger("A.B")
上例中我们建立了3个logger实例,它们分别是"A"、"A.B"、"A.B.C"。每次我们在系统中取得logger时,并不是新建实例,这些实例是系统启动的时候就按照配置文件初始化好的(也可能时第一次引用的时候建立的,然后缓存其实例供以后使用,这部分还没有时间研究)。

限制appender叠加性
例1:
log4j.rootLogger=DEBUG, Console
log4j.logger.A=DEBUG, Console
log4j.logger.A.B=INFO, Console
对于logger A.B输出的任何日志会往控制台输出三次,原因是A.B继承A的以及A的父logger的所有appender,
这种继承关系仅仅是把父logger的appender添加到自己的appender列表中,父logger的输出level不会影响
子logger的输出。

例2:限制appender叠加
log4j.rootLogger=DEBUG, Console
log4j.logger.A=DEBUG, Console
log4j.logger.A.B=INFO, Console
log4j.additivity.A.B=false
logger A.B的日志仅会输出到自己Console中,不会继承任何父logger的appender。

控制appender的输出级别
若想对输出到appender中的日志级别进行限制的话,就需要用到threshold来控制。
log4j.threshold=ERROR 用来控制所有的appender,即输出到所有appender的日志,
不管原来是什么级别的,都不能低于threshold所规定的级别。

log4j.appender.Console.threshold=ERROR 用来控制指定的appender的输出级别。

Log4j的简单思想

Log4j真的很简单,简单到令人发指的地步。不是要记录日志吗?那就给你一个Log,然后你用Log来写东西就行了,先来一个完整类示例:

package test;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

public class Test {

        static Log log = LogFactory.getLog(Test.class);

        public void log(){

           log.debug("Debug info.");

           log.info("Info info");

           log.warn("Warn info");

           log.error("Error info");

           log.fatal("Fatal info");

        }

        /**

         * @param args

         */

        public static void main(String[] args) {

           Test test = new Test();

           test.log();

        }

}

别怕,看完这篇文章你就会觉得很简单了。

       Log4j默认把日志信息分为五个等级

       all<debug < info < warn < error < fatal<off

虽然可以自己添加等级,但是我觉得没有必要,五个够用了吧!你要写入信息的时候就把信息归为五个等级中的一个,然后调用相应的函数即可。

       分五个等级到底有什么用呢?日志信息到底写到哪里去了?

       “LogFactory.getLog(Test.class)”又是什么意思捏?接着往下看吧!(现在用这个Logger.getLogger(Test.class)吧)

Log4j的关键之处在于它的继承思想。也就是一个Log可以继承另外一个Log的属性(输出到哪里,日志等级,日志格式等等)。怎么继承?

Log4j是根据Log的名字来判断继承关系的,比如:

名字为“com.zhlmmc.lib”的Log就是“com.zhlmmc.lib.log”的parent,明白了吧!Log4j还有一个rootLogger,相当于Java的Object。

回过头来看“LogFactory.getLog(Test.class)”这里的“Test.class”事实上传进去的是Test这个类的完整路径(包名+类名),“test.Test”。这样如果存在“test”这个Log那么Test这个Log就继承它,否则就继承rootLogger。

       那具体的Log属性是在哪里定义的呢?

关于logger的两点说明
用同名参数调用Logger.getLogger(String name)将返回同一个logger的引用。故可以在一个地方配置logger,在另外一个地方获得配置好的logger,而无须相互间传递logger的引用。
logger的创建可以按照任意的顺序,即,父logger可以后于子logger被创建。log4j将自动维护logger的继承树。

常见的配置文件

虽然可以用xml或者在运行时用Java来配置Log4j,但还是properties文件好用啊!

log4j.rootLogger=info, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller‘s file name and line number.

log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

分析一下:

第一行,配置log4j.rootLogger你明白吧。应为它是根,总得配置一下,否则别的Log继承什么啊。其他的Log可以配置也可以不配置。等号后面的第一个参数表示日志级别,可以填五个级别中的一种,后面的参数都是让Log知道输出到哪里,如果你想让日志输出到两个地方就加两个输出参数,比如:

log4j.rootLogger=info, stdout, file

这里的info表示,该Log的日志级别为info,所有级别小于info的日志都不会被记录。比如使用这个配置文件的话,我刚开始举的那个类中

log.debug("Debug info.");

这句话是不起作用的,因为debug的级别小于info。这样就很容易控制什么信息在调试的时候要显示,什么信息在发布的时候要去掉。这些都不用改代码,很方便吧。

但,stdout和file又是什么呢?

接着往下看,就是配置stdout了,这个名字是随便取的,你可以叫它A:

log4j.appender.A=org.apache.log4j.ConsoleAppender

那么上面的rootLogger的参数stdout也要改成A,其他用到的地方当然也要改。这里的关键不是名字,而是appender类型,比如这里的“ConsoleAppender”,看明白了吧,输出到Console。后面两行都是设置日志格式的,一般情况下你就照抄吧。既然是最简入门关注于理解Log4j的工作原理,我就不介绍file类型的appender了,一搜一大把。

在实际的项目开发中,很可能遇到所引用的包用Log4j来记录日志,比如Hibernate。那么在这里你可以很容易的控制这个包如何记录日志。比如在上面的配置文件中加一行:

log4j.logger.org.hibernate=fatal

       那么所有org.hibernate包下面的类就只会显示很少的信息,因为fatal的级别最高啊。

部署

别怕,这可不是部署Tomcat。把log4j的包和commons-logging的包(加在一起才两个)放到classpath下面。然后把配置文件保存为log4j.properties,也放在classpath下面(如果用Eclipse的话,放在src目录下即可)。然后你就可以跑了。

默认的log4j初始化过程
Logger类的静态初始化块(static initialization block)中对log4j的环境做默认的初始化。注意:如果程序员已经通过设置系统属性的方法来配置了log4j环境,则不需要再显式地调用XXXConfigurator.configure()方法来配置log4j环境了。

Logger的静态初始化块在完成初始化过程时将检查一系列log4j定义的系统属性。它所做的事情如下:

检查系统属性log4j.defaultInitOverride,如果该属性被设置为false,则执行初始化;否则(只要不是false,无论是什么值,甚至没有值,都是否则),跳过初始化。
把系统属性log4j.configuration的值赋给变量resource。如果该系统变量没有被定义,则把resource赋值为"log4j.properties"。注意:在apache的log4j文档中建议使用定义log4j.configuration系统属性的方法来设置默认的初始化文件是一个好方法。
试图把resource变量转化成为一个URL对象url。如果一般的转化方法行不通,就调用org.apache.log4j.helpers.Loader.getResource(resource, Logger.class)方法来完成转化。
如果url以".xml"结尾,则调用方法DOMConfigurator.configure(url)来完成初始化;否则,则调用方法PropertyConfigurator.configure(url)来完成初始化。如果url指定的资源不能被获得,则跳出初始化过程。

Log4j的编码习惯
让每个类都拥有一个private static的Logger对象,用来输出该类中的全部日志信息
使用xml文件来完成对log4j环境的配置。在项目的main class中的静态初始化块里放log4j环境的配置代码。注意:在一个项目中,log4j环境只需要被配置一次,而不是在每个使用了logger的类里都需要调用一次
用MyClass.class作为参数创建该类的静态Logger对象
时间: 2024-08-04 01:11:49

log4j入门(转) --- 很详细 也很简单容易懂的相关文章

很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序

很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用make更新函数库文件 后序 近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出来,方便学习. 后记,看完发现这篇文章和<Linux环境下的C编程指南>

关于OnPaint函数的工作原理(很详细,很实用) [转载]

地址:http://blog.csdn.net/foreverhuylee/article/details/21889025 用了两年的VC,其实对OnPaint的工作原理一直都是一知半解.这两天心血来潮,到BBS上到处发帖询问,总算搞清楚了,现在总结一下. 对于窗口程序,一般有个特点:窗口大部分的区域保持不变,只有不分区域需要重新绘制.如果将整个窗口全部刷新的画,就做了许多不必要的工作,因而,MFC采用了一套基于无效区的处理机制.在分析无效区处理之前,我们要明白一个现实,现在的机器还不够牛,如

分布式架构的演进,分析的很详细,很到位

作者:李小翀链接:https://www.zhihu.com/question/22764869/answer/31277656来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 首先推荐4本书 大型分布式网站架构设计与实践 http://item.jd.com/11529266.html 大型网站技术架构:核心原理与案例分析 http://item.jd.com/11322972.html 大型网站系统与Java中间件实践 http://item.jd.com/11

完整登录流程包含第三方登录,很详细值得推荐

这是我从网上找到的一张关于第三方登录的流程图,很详细也很明确,收藏一下 原文地址:https://www.cnblogs.com/caijiabao/p/10165009.html

[转]Java多线程学习(总结很详细!!!)

Java多线程学习(总结很详细!!!) 此文只能说是java多线程的一个入门,其实Java里头线程完全可以写一本书了,但是如果最基本的你都学掌握好,又怎么能更上一个台阶呢? 本文主要讲java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的线程函数用法.概述等.首先让我们来了解下在操作系统中进程和线程的区别: 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程.(进程是资源分配的最小单位) 线程:同一类线程共享代码和数据空间,

讲的很详细的一篇关于object equals() &amp; hashCode() 的文章

转: 讲的很详细的一篇关于object equals() & hashCode() 的文章 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: 1 public native int hashCode(); 根据这个方法的声明可知,该方法返回一个int类型的数值,并且是本地方法,因此在Object类中并没有给出具体的实现. 为何Object类需要这样一个方法?它有什么作用呢?今天我们就来具体探讨一下hashCode方

转: angularjs学习总结(~~很详细的教程)

1 前言 前端技术的发展是如此之快,各种优秀技术.优秀框架的出现简直让人目不暇接,紧跟时代潮流,学习掌握新知识自然是不敢怠慢. AngularJS是google在维护,其在国外已经十分火热,可是国内的使用情况却有不小的差距,参考文献/网络文章也很匮乏.这里便将我学习AngularJS写成文档,一方面作为自己学习路程上的记录,另一方面也给有兴趣的同学一些参考. 首先我自己也是一名学习者,会以学习者的角度来整理我的行文思路,这里可能只是些探索,有理解或是技术上的错误还请大家指出:其次我特别喜欢编写小

Intel 编译器 内存安全检查 真心的很详细 转

Managing Memory Errors with Intel? Parallel Inspector XE ___________________________________________________________________ Intel? Academic Community Disclaimer The information contained in this document is provided for informational purposes only a

Intel 编译器 静态安全检查 真心的很详细 转

Static Security Analysis with Intel? Parallel Inspector XE ___________________________________________________________________ Intel? Academic Community Disclaimer The information contained in this document is provided for informational purposes only