精华内容
下载资源
问答
  • Java 日志系统

    千次阅读 2018-07-24 16:26:44
    最开始出现的是log4j,也是应用最广泛的日志系统,成为了目前java日志系统事实上的标准,一切都是美好的 但java的开发主体sun公司认为自己才是正统,为了干掉log4j在jdk1.4中增加了jul(因为在java.util.logging包下...

    java的日志系统繁杂,今天趁着解决日志系统冲突的过程,顺带学习一下java的日志系统并做个记录

    日志演化历史

    • 最开始出现的是log4j,也是应用最广泛的日志系统,成为了目前java日志系统事实上的标准,一切都是美好的
    • 但java的开发主体sun公司认为自己才是正统,为了干掉log4j在jdk1.4中增加了jul(因为在java.util.logging包下)日志的实现,造成了目前开发者的混乱,迄今为止仍饱受诟病
    • 各个日志系统互相没有关联,替换和统一变的非常麻烦。A项目用log4j作为日志系统,但同时引了B项目,而B项目用jul作为日志系统,那么你的应用就得使用两个日志系统
    • 为了搞定这个坑爹的问题,开源社区apache提供了一个日志框架作为日志的抽象,叫commons-logging,也被称为jcl(java common logging),jcl对各种日志接口进行抽象,抽象出一个接口层,对每个日志实现都适配或者转接,这样这些提供给别人的库都直接使用抽象层即可,较好的解决了上述问题
    • 但这时,作为元老级日志log4j的作者觉得jcl不够好,再度出山,搞出了一个更加牛逼的新的日志框架slf4j(这个也是抽象层),同时针对slf4j的接口实现了一套日志系统,即传说中的logback
    • 同时这个作者心情一好,又把log4j进行了改造,就是所谓的log4j2,同时支持jcl以及slf4j

    JCL

    使用JCL一般(如果是log4j可以不需要)需要一个配置commons-logging.properties在classpath上,这个文件有一行代码:

    org.apache.commons.logging.LogFactory= org.apache.commons.logging.impl.LogFactoryImpl

    用于通知JCL想要使用哪个日志系统。用户只要修改LogFactory的实现,就能动态的切换日志系统

    SLF4J

    slf4j的设计相对较为精巧,作者将接口以及实现分开,其中slf4j-api中定义了接口,开发者需要关心的就是这个接口,无需再关心下层如何实现,同时各个是slf4j接口的实现者只要遵循这个接口,就能够做到日志系统间的无缝兼容

    • slf4j-api的实现目前比较出名的是接口开发者实现的logback,性能相较log4j来讲更加优秀,也支持占位符等新特性。
    • 同时为了兼容log4j,slf4j-log4j12实现了slf4j-api,作为log4j兼容的适配器,使得用户用起来像在用log4j
    • 为了兼容jul,slf4j-jdk14也实现了slf4j-api,作为jul兼容的适配器,使得用户用起来像在用jul
    • 有了实现,还需要一个桥接器,桥接器将对jcl的调用转接到slf4j上:

      • jul-to-slf4j把对jul的调用桥接到slf4j上
      • jcl-over-slf4j把对jcl的调用桥接到slf4j上
      • log4j-over-slf4j把对log4j的调用桥接到slf4j上

    日志系统的冲突

    多种日志系统并不意味着程序中只能存在一种日志系统,比如log4j与logback是完全可以共存的。
    目前日志系统的冲突主要分为两种:

    • 同一个日志系统的多个实现
    • 桥接接口与实现类

    1) 同一个日志系统的多个实现

    像slf4j接口实现的冲突,如:

    slf4j-log4j、logback、slf4j-jdk14、log4j2之间的冲突

    这点很好理解,这几个包都实现了slf4j的接口,同一接口只能有一个实现才能被jvm正确识别
    但日志系统仍然非常容易冲突,与传统的jar冲突相同,当jvm发现两个一模一样的实现的时候,它就不知道选择哪个或选择了一个错误的,就会提示ClassNotFound.

    2) 桥接jar与实现包
    在日志系统中,最常见的就是桥接jar包与实现包的冲突,如:

    • jul-to-slf4j 与 slf4j-jdk14
    • log4j-over-slf4j 与 slf4j-log4j
    • jcl-over-slf4j 与 jcl

    因为转接的实现就是将其余的日志系统调用进行一个转发,既然要转发,就必须要定义与原有对象相同的类名、包名,才能正确的被调用,所以桥接jar包就必然与实现包产生冲突。

    各个日志系统间的依赖关系

    依赖关系可以见下图:
    日志系统.png-13.5kB
    其中

    • slf4j为纯日志接口
    • logback/slf4j-jdk14/slf4j-log4j12/log4j2均可认为是slf4j的实现类
    • jul/log4j作为最早开始的日志系统,本身就是一种日志的实现,没有任何框架
    • jul-to-slf4j/log4j-to-slf4j/jcl-over-slf4j/作为桥接接口,可以将原有接口的内容进行接收,然后通过slf4j进行输出

    其余常见问题

    • slf4j的几个实现jar包一定会冲突,尤其要注意
    • slf4j-api和实现版本最好对应,尤其是1.6.x和1.5.x不兼容,直接升级到最新版本
    • log4j与logback可以同时使用,logback实现slf4j的接口,与log4j没有任何关系,完全可以同时使用
    • 建议选用slf4j + logback,或slf4j + log4j2
    • 日志系统在正常情况下是不会影响应用性能的,但应该注意量,太大量的日志会拖累性能

    转自:https://yq.aliyun.com/articles/57769#

    展开全文
  • Java日志系统

    2018-03-20 20:55:13
    最开始出现的是log4j,也是应用最广泛的日志系统,成为了目前java日志系统事实上的标准,一切都是美好的 但java的开发主体sun公司认为自己才是正统,为了干掉log4j在jdk1.4中增加了jul(因为在java.util.logging包下)...

    java的日志系统繁杂,今天趁着解决日志系统冲突的过程,顺带学习一下java的日志系统并做个记录

    日志演化历史

    • 最开始出现的是log4j,也是应用最广泛的日志系统,成为了目前java日志系统事实上的标准,一切都是美好的
    • 但java的开发主体sun公司认为自己才是正统,为了干掉log4j在jdk1.4中增加了jul(因为在java.util.logging包下)日志的实现,造成了目前开发者的混乱,迄今为止仍饱受诟病
    • 各个日志系统互相没有关联,替换和统一变的非常麻烦。A项目用log4j作为日志系统,但同时引了B项目,而B项目用jul作为日志系统,那么你的应用就得使用两个日志系统
    • 为了搞定这个坑爹的问题,开源社区apache提供了一个日志框架作为日志的抽象,叫commons-logging,也被称为jcl(java common logging),jcl对各种日志接口进行抽象,抽象出一个接口层,对每个日志实现都适配或者转接,这样这些提供给别人的库都直接使用抽象层即可,较好的解决了上述问题
    • 但这时,作为元老级日志log4j的作者觉得jcl不够好,再度出山,搞出了一个更加牛逼的新的日志框架slf4j(这个也是抽象层),同时针对slf4j的接口实现了一套日志系统,即传说中的logback
    • 同时这个作者心情一好,又把log4j进行了改造,就是所谓的log4j2,同时支持jcl以及slf4j

    JCL

    使用JCL一般(如果是log4j可以不需要)需要一个配置commons-logging.properties在classpath上,这个文件有一行代码:

    org.apache.commons.logging.LogFactory= org.apache.commons.logging.impl.LogFactoryImpl

    用于通知JCL想要使用哪个日志系统。用户只要修改LogFactory的实现,就能动态的切换日志系统

    SLF4J

    slf4j的设计相对较为精巧,作者将接口以及实现分开,其中slf4j-api中定义了接口,开发者需要关心的就是这个接口,无需再关心下层如何实现,同时各个是slf4j接口的实现者只要遵循这个接口,就能够做到日志系统间的无缝兼容

    • slf4j-api的实现目前比较出名的是接口开发者实现的logback,性能相较log4j来讲更加优秀,也支持占位符等新特性。
    • 同时为了兼容log4j,slf4j-log4j12实现了slf4j-api,作为log4j兼容的适配器,使得用户用起来像在用log4j
    • 为了兼容jul,slf4j-jdk14也实现了slf4j-api,作为jul兼容的适配器,使得用户用起来像在用jul
    • 有了实现,还需要一个桥接器,桥接器将对jcl的调用转接到slf4j上:
      • jul-to-slf4j把对jul的调用桥接到slf4j上
      • jcl-over-slf4j把对jcl的调用桥接到slf4j上
      • log4j-over-slf4j把对log4j的调用桥接到slf4j上

    日志系统的冲突

    多种日志系统并不意味着程序中只能存在一种日志系统,比如log4j与logback是完全可以共存的。
    目前日志系统的冲突主要分为两种:

    • 同一个日志系统的多个实现
    • 桥接接口与实现类

    1) 同一个日志系统的多个实现

    像slf4j接口实现的冲突,如:

    slf4j-log4j、logback、slf4j-jdk14、log4j2之间的冲突

    这点很好理解,这几个包都实现了slf4j的接口,同一接口只能有一个实现才能被jvm正确识别
    但日志系统仍然非常容易冲突,与传统的jar冲突相同,当jvm发现两个一模一样的实现的时候,它就不知道选择哪个或选择了一个错误的,就会提示ClassNotFound.

    2) 桥接jar与实现包
    在日志系统中,最常见的就是桥接jar包与实现包的冲突,如:

    • jul-to-slf4jslf4j-jdk14
    • log4j-over-slf4jslf4j-log4j
    • jcl-over-slf4jjcl

    因为转接的实现就是将其余的日志系统调用进行一个转发,既然要转发,就必须要定义与原有对象相同的类名、包名,才能正确的被调用,所以桥接jar包就必然与实现包产生冲突。

    各个日志系统间的依赖关系

    依赖关系可以见下图:
    日志系统.png-13.5kB
    其中

    • slf4j为纯日志接口
    • logback/slf4j-jdk14/slf4j-log4j12/log4j2均可认为是slf4j的实现类
    • jul/log4j作为最早开始的日志系统,本身就是一种日志的实现,没有任何框架
    • jul-to-slf4j/log4j-to-slf4j/jcl-over-slf4j/作为桥接接口,可以将原有接口的内容进行接收,然后通过slf4j进行输出

    其余常见问题

    • slf4j的几个实现jar包一定会冲突,尤其要注意
    • slf4j-api和实现版本最好对应,尤其是1.6.x和1.5.x不兼容,直接升级到最新版本
    • log4j与logback可以同时使用,logback实现slf4j的接口,与log4j没有任何关系,完全可以同时使用
    • 建议选用slf4j + logback,或slf4j + log4j2
    • 日志系统在正常情况下是不会影响应用性能的,但应该注意量,太大量的日志会拖累性能
    展开全文
  • JAVA日志系统

    2017-08-11 14:39:39
    JAVA日志系统@(JAVA)[java, 大数据]JAVA日志系统 一slf4j 一最简单示例 二常用示例 三其它示例 四一些注意事项 二log4j 一使用java向rsyslog发送日志 基本使用方法 不使用配置文件 三logging 四使用slf4jlog4j2向...

    JAVA日志系统

    @(JAVA)[java, 大数据]

    java有大量的框架用于日志输出,常见的包括slf4j, log4j, logback, logging等.

    一、slf4j

    slf4j只是一个门面(facet),它不包含具体的实现,而是将一些log4j,java.logging等实现包装成统一的接口。
    

      commons-logging和slf4j都是日志的接口,供用户使用,而没有提供实现!

      log4j,logback等等才是日志的真正实现。

      当我们调用接口时,接口的工厂会自动寻找恰当的实现,返回一个实现的实例给我服务。这些过程都是透明化的,用户不需要进行任何操作!

      这里有个小故事,当年Apache说服 log4j以及其他的日志来按照commons-logging的标准编写,但是由于commons-logging的类加载有点问题,实现起来也不友 好,因此log4j的作者就创作了slf4j,也因此而与commons-logging两分天下。至于到底使用哪个,由用户来决定吧。

      这样,slf4j出现了,它通过简单的实现就能找到符合自己接口的实现类,如果不是满足自己标准的日志,可以通过一些中间实现比如上面的slf4j-log4j12.jar来进行适配。

    好,言归正传,如何使用slf4j?

    (一)最简单示例

    最简单的情况是slf4j-simple提供的简单实现,功能非常简单的,但使用非常方便。
    1、pom.xml添加依赖

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.21</version>
        </dependency>
    

    2、使用slf4j

    private static Logger LOG = LoggerFactory.getLogger(RedisSlotCRC16Demo.class);
    LOG.info("Mean time to calculate 1000 slot is: " + getIntervalInMill(beginTime));
    

    (二)常用示例

    1、在pom.xml中添加以下内容

    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.0</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.0</version>
    </dependency>
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>
    

    2、创建log4j.properties文件,详细配置见http://www.cnblogs.com/lujinhong2/p/4637219.html

    注意文件必须在config目录下(对于maven项目,log4j.properties位于src/main/resources下面)

    ### set log levels ###
    log4j.rootLogger = debug ,  stdout ,  D ,  E
    
    ### 输出到控制台 ###
    log4j.appender.stdout = org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.Target = System.out
    log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{1}:%L - %m%n
    
    ### 输出到日志文件 ###
    log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.D.File = logs/log.log
    log4j.appender.D.Append = true
    ## 输出DEBUG级别以上的日志
    log4j.appender.D.Threshold = DEBUG 
    log4j.appender.D.layout = org.apache.log4j.PatternLayout
    log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
    
    ### 保存异常信息到单独文件 ###
    log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
     ## 异常日志文件名
    log4j.appender.E.File = ./error.log
    log4j.appender.E.Append = true
    ## 只输出ERROR级别以上的日志!!!
    log4j.appender.E.Threshold = ERROR 
    log4j.appender.E.layout = org.apache.log4j.PatternLayout
    log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %l:%c:%t:%r ] - [ %p ]  %m%n
    

    3、在java文件中调用

    package org.lujinhong.javademo.slf4jdemo;
    
    import java.io.File;
    import java.io.IOException;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @author jinhong-lu
     * @date 2015年7月9日 下午4:34:49
     * @Description:
     */
    public class Slf4jDemo {
        private static final Logger LOG = LoggerFactory.getLogger(Slf4jDemo.class);
    
    
        public static void main(String[] args) {
    
            // 使用此变量会生成文件成功
            String fileName = "1.txt";
            // 使用此变量会生成文件失败
            // String fileName = "/tt/1.txt";
            try {
                new File(fileName).createNewFile();
                LOG.info("create file " + fileName + "!");
            } catch (IOException e) {
                e.printStackTrace();
                LOG.error("create file " + fileName + " fail!!!!" + e.getMessage());
            }
    
        }
    
    }
    

    (三)其它示例

    首先,项目中必须要包括slf4j-api.jar,此外,还应该包括slf4j为具体实现所提供的适配器(如slf4j-log4j12.jar),以及那个具体实现的jar包(如log4j-1.**.jar)。

    我们以以下代码为例:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class Slf4jDemo {
    private static final Logger LOG = LoggerFactory.getLogger(Slf4jDemo.class);

    public static void main(String[] args) {
        LOG.error("Error Message!");
        LOG.warn("Warn Message!");
        LOG.info("Info Message!");
        LOG.debug("Debug Message!");
        LOG.trace("Trace Message!");
    }
    

    }
    由于所使用的具体实现不同,日志输出也有不同的结果。这也反应了通过使用slf4j,使得可以方便的替换日志系统。

    1、Slf4j-simple

    slf4j自带的一个简单实现,可用于小项目中,但无法配置日志级别等。

    官方文档中的描述为:Binding for Simple implementation, which outputs all events to System.err. Only messages of level INFO and higher are printed. This binding may be useful in the context of small applications.

    在项目的build_path中加入slf4j-1.6.6.jar与slf4j-simple-1.6.6.jar。

    输出结果如下:

    2 [main] ERROR Slf4jDemo - Error Message!
    2 [main] WARN Slf4jDemo - Warn Message!
    2 [main] INFO Slf4jDemo - Info Message!
    

    2、slf4j-jdk

    使用jkd自带的日志系统,在项目的build_path中加入slf4j-1.6.6.jar与slf4j-jdk14-1.6.6.jar。

    输出结果如下:

    二月 16, 2015 11:09:36 下午 Slf4jDemo main
    严重: Error Message!
    二月 16, 2015 11:09:36 下午 Slf4jDemo main
    警告: Warn Message!
    二月 16, 2015 11:09:36 下午 Slf4jDemo main
    信息: Info Message!
    

    3、slf4j-log4j
    log4j是目前用得最多的日志系统,它更适用于大型项目。
    在项目的build_path中加入slf4j-1.6.6.jar与slf4j-log4j-1.6.6.jar,以及log4j的具体实现,如log4j-1.2.16.jar。

    输出结果如下:

    log4j:WARN No appenders could be found for logger (Slf4jDemo).
    log4j:WARN Please initialize the log4j system properly.
    log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
    

    可以通过配置文件配置输出日志的级别。

    (四)一些注意事项

    1、注意build_path中不能有多个日志实现,否则会导致slf4j不知道该使用哪个实现(各个系统加载classpath的顺序会有差异的),从而出现以下错误

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/Users/liaoliuqing/99_Project/1_myCodes/5_JavaEEDemo/lib/slf4j-log4j12-1.6.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/Users/liaoliuqing/99_Project/1_myCodes/5_JavaEEDemo/lib/slf4j-jdk14-1.6.6.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
    log4j:WARN No appenders could be found for logger (Slf4jDemo).
    log4j:WARN Please initialize the log4j system properly.
    log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
    

    3、有个很大的坑:

    由于很多项目都会使用log4j作为日志框架,而在一个项目的引用包中的log4j配置文件有可能将自己定义的log4j.properties文件覆盖。

    如果发现自己的log4j配置文件不生效,则使用:

    java -Dlog4j.debug 主类

    来检查目前加载了哪个配置文件,然后将其删除即可。

    另外,即使使用了

    PropertyConfigurator.configure(“log4j2.properties”);
    指定配置文件,也有可能被第三方jar包使用同样语句覆盖了。

    二、log4j

    log4j有2个版本,1.x和2.x,2.x较为完善,但是目前大家都习惯了用1.x,而且很多开源项目都使用了1.x,所以一般使用1.x就可以了。

    关于2.x的使用,请参考http://www.cnblogs.com/lujinhong2/p/4637295.html

    1.x要注意版本的问题,一般使用1.2.17配合slfj的1.7.12版本即可,只要不相差太多都没问题。

    (一)使用java向rsyslog发送日志

    基本使用方法

    1、开通rsyslog远程UDP访问

    vi /etc/rsyslog.conf

    将下面两段前面的#号去掉

    #$ModLoad imudp  
    #$UDPServerRun 514  
    

    如果原来没有话则加上这2行

    2,建立存放log的文件地址
    vi /etc/rsyslog.conf
    加入以下两段

    local2.info       /var/log/login_info.log  
    local2.debug       /var/log/login_debug.log  
    

    3,开通防火墙
    将UDP端口514对外开放出来

    4,重启rsyslog
    service rsyslog restart

    5,log4j的配置
    将日志同时输出到syslog和console

    log4j.rootLogger =ALL,systemOut,SYSLOG
    log4j.appender.systemOut = org.apache.log4j.ConsoleAppender 
    log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout 
    log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n 
    log4j.appender.systemOut.Threshold = DEBUG 
    log4j.appender.systemOut.ImmediateFlush = TRUE 
    log4j.appender.systemOut.Target = System.out 
    log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender  
    log4j.appender.SYSLOG.syslogHost=192.168.172.114
    log4j.appender.syslog.Threshold=DEBUG  
    log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout  
    log4j.appender.SYSLOG.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n  
    log4j.appender.SYSLOG.Header=true
    log4j.appender.SYSLOG.Facility=local2   
    

    6、写java代码

    package com.lujinhong.demo.log4j;
    
    import org.apache.log4j.Logger;
    
    public class Log4jDemo {
        private static Logger LOG  =  Logger.getLogger(Log4jDemo. class );
    
      public static void main(String[] args) {
        //System.setProperty("LOGDIR","/Users/liaoliuqing/Downloads/");
        LOG.info("lujinhong !!INFO MESSAGE!!");
        LOG.error("ERROR MESSAGE!!!!");
        LOG.debug("DEBUG MESSAGE!");
        LOG.warn("WARN MESSAGE!!");
    
        new MyJavaClass().adder(2, 3);
      }
    }
    

    7,运行应用程序,可以在/var/log下看到不同级别的日志信息,如login_info.log和login_debug.log

    不使用配置文件

    有时候,log4j的配置文件会互相覆盖,真的很烦,因此可以将配置写到代码中去
    1、定义一个单例类,将相关配置写入:

    package com.lujinhong.demo.log4j;
    
    import org.apache.log4j.Level;
    import org.apache.log4j.Logger;
    import org.apache.log4j.PatternLayout;
    import org.apache.log4j.net.SyslogAppender;
    
    
    public class MySysLogger {
        //日志级别
        private static Level level = Level.INFO;
    
    
        private static Logger LOG = null;
    
        public static synchronized Logger getInstance() {
            if (LOG == null) {
                new MySysLogger();
            }
            return LOG;
        }
    
        private MySysLogger() {
    
            LOG = Logger.getRootLogger();
    
            LOG.setLevel(level);
            SyslogAppender appender = new SyslogAppender();
            appender.setName("ma30");
    
            appender.setSyslogHost("192.168.172.98");
            appender.setLayout(new PatternLayout(
                    "%r [%t] %-5p %c%x: - %m%n"));
            appender.setHeader(true);
            appender.setFacility("local7");
            //appender.setWriter(new PrintWriter(System.out));
            //如果是文件是RollingFileAppender:setWriter(new PrintWriter(new File("F:/test/_debug.log")));
            LOG.addAppender(appender);
        }
    }
    

    2、在需要日志输出的类中添加以下语句

    private static Logger LOG = MySysLogger.getInstance();
    

    然后就可以使用LOG变量进行日志输出了

    吐槽几句,log4j的坑啊….

    (1)CLASSPATH中不能有多个log4j的版本本,否则有有奇形怪状的NoSuchMethod, NoSuchFiled, NoClassDefineFound等异常。明明是太多了,还告诉你没有

    (2)与slf4j的搭建,必须版本一致,如slf4j-1.7.2对应log4j-1.2.17

    (3)配置文件啊,如果你引用的第三方包有log4j.properties,而又没有提供给你编辑,那恭喜你,慢慢调吧。把log4j的配置写入代码吧,不要用配置文件了

    (4) 如果你打算只使用log4j,而不使用slf4j作包装,切记classpath中只能有log4j,不能有log4j-over-slf4j-1.7.12.jar这种包,不然会出现各种各样的错误,如:
    NoSuchMethod, NoSuchFiled, NoClassDefineFound, IncompatibleClassChangeError: Implementing class

    三、logging

    直接一个示例

    (1)在你的代码中增加一个类,代码见后面。一般情况下只需要修改输出日志的文件名称就可以了。
    (2)在任何需要输出日志的类中添加一个变量,private static Logger LOG = MyLogger.getInstance();
    然后就可以使用LOG变量来做日志输出了。

    说明一下:
    1、storm从0.9.1后使用的日志架构是slf4j+logbakc,取代了原先的log4j。我们尝试使用log4j作日志框架,发现log4j.properties被storm某个jar包里面的配置覆盖了,导致自己定义的log4j.properties怎么都不生效,然后尝试logback也有类似问题,定义的cluster.xml没有给出worker进程的日志配置。
    2、使用java.util.logging配置文件也可以,便在分布式系统中的配置加载比较复杂,而且java.util.logging很坑,很容易写错,比如每一行的最后都不能有空格等。

    package com.netease.sytopology.util;

    import java.io.IOException;
    import java.util.logging.ConsoleHandler;
    import java.util.logging.FileHandler;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import java.util.logging.SimpleFormatter;
    /**
    * @author lujinhong
    * @date 2015年7月25日 下午3:19:56
    * @Description:
    */
    public class MyLogger {
    //文件路径及文件名
    private static String logFile = “/home/hadoop/storm/logs/userlog/ma30_filter.log”;
    //日志级别
    private static Level level = Level.INFO;
    //每个日志文件的大小,单位为M。
    private static int logFileSize = 100;
    //保存日志文件的数据
    private static int logFileCount = 10;
    //logger的名称
    private static String logName = “com.lujinhong.demo”;
    private static Logger LOG = null;

    public static synchronized Logger getInstance() {
    if (LOG == null) {
    new MyLogger();
    }
    return LOG;
    }

    private MyLogger() {
    LOG = Logger.getLogger(logName);
    FileHandler fileHandler = null;
    try {
    fileHandler = new FileHandler(logFile,logFileSize*1024*1024,logFileCount,true);
    } catch (SecurityException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    fileHandler.setLevel(level);
    fileHandler.setFormatter(new SimpleFormatter());
    LOG.removeHandler(new ConsoleHandler());
    LOG.addHandler(fileHandler);
    }

    }

    四、使用slf4j+log4j2向rsyslog发送日志

    (一)rsyslog配置

    1、在/etc/rsyslog.d中新建storm.conf

    内容如下:

    $WorkDirectory /home/data/log/
    
    $MaxMessageSize 64k
    
    $ModLoad imudp
    $UDPServerRun 514
    
    $template stromtemplate, "/home/data/log/storm_%STRUCTURED-DATA:R,ERE,1:.*category=\"(.+)\".*programname.*--end%_%$YEAR%%$MONTH%%$DAY%.log"
    
    $template stromformat, "[%TIMESTAMP:1:10:date-rfc3339% %TIMESTAMP:12:19:date-rfc3339%]  %syslogseverity-text:::uppercase% %STRUCTURED-DATA:R,ERE,2:.*category=\"(.+)\".*programname=\"(.+)\".*--end% %msg%\n"
    
    $EscapeControlCharactersOnReceive off
    $FileOwner hadoop
    $FileGroup hadoop
    $FileCreateMode 0644
    $DirCreateMode 0755
    $Umask 0022
    
    local7.*                        -?stromtemplate;stromformat
    local7.*  ~
    

    2、修改/etc/rsyslog.conf

    修改以下3行:

    *.*;auth,authpriv.none;cron.none,local7.none -/var/log/syslog
    kern.*,local7.noe                      -/var/log/kern.log
    *.=info;*.=notice;*.=warn;\
            auth,authpriv.none;\
            cron,daemon.none;\
            mail,news.none,local7.none      -/var/log/messages
    

    声明local7的日志不会发送到syslog, kern.log,message。否则日志量太大会撑爆。

    此时rsyslog就已经配置完成,它会将发送至local7的日志解释后放到/home/data/log中。

    (二)java程序中输出日志

    1、添加依赖

    以maven为例,添加以下内容:

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>log4j-over-slf4j</artifactId>
        <version>1.6.6</version>
    </dependency>
    

    其它编译方式则添加相应的jar包。

    2、准备配置文件

    在resources目录下创建log4j2.xml,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration status="warn" name="test" packages="">
        <Appenders>
            <Syslog name="test" format="RFC5424" host="192.168.1.100" port="514"
                protocol="UDP" appName="storm" includeMDC="true" mdcId="mdc"
                facility="LOCAL7" enterpriseNumber="18060" newLine="true" 
                messageId="Audit" id="App">
                <LoggerFields>
                    <KeyValuePair key="category" value="%c"/>             
                    <KeyValuePair key="programname" value="%C"/>
                </LoggerFields>
                </Syslog>           
        </Appenders>
        <Loggers>
            <Logger name="test" level="INFO">
            <AppenderRef ref="test"/>
         </Logger>
            <Root level="INFO">
                <AppenderRef ref="test"/>
            </Root>
        </Loggers>
    </Configuration>
    

    3、输出日志

    (1)先获取Logger对象

    public static Logger LOG = LoggerFactory.getLogger("mytest");
    

    其中参数建议为拓扑名称。

    (2)然后你就可以轻松的输出日志了

    logger.error("INFO ljh_test again!");
    logger.info("INFO ljh_test message info");
    logger.debug("INFO ljh_test message debug");
    logger.warn("INFO ljh_test message warn");
    

    完整代码如下:https://github.com/lujinhong/log4j2demo

    package com.lujinhong.demo.log4j2;
    
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class Log4j2RsyslogDemo {
    
        public static Logger logger = LoggerFactory.getLogger("mytest");
    
        public static void main(String[] args) {
    
            System.out.println("Hello World2!");
    
            logger.error("INFO ljh_test again!");
            logger.info("INFO ljh_test message info");
            logger.debug("INFO ljh_test message debug");
            logger.warn("INFO ljh_test message warn");
        }
    }
    
    展开全文
  • java日志系统

    2017-02-24 10:00:15
    左图是普通项目的日志系统结构 右图是hibernate的日志系统结构,hibernate贱人就是矫情,自己有一个接口是slf接口,要使用log4j就得转换接口,把slf接口转换成log4j接口,相当与使用一个接口转换器准备开一大项目的...

    这里写图片描述

    左图是普通项目的日志系统结构
    右图是hibernate的日志系统结构,hibernate贱人就是矫情,自己有一个接口是slf接口,要使用log4j就得转换接口,把slf接口转换成log4j接口,相当与使用一个接口转换器

    准备开一大项目的话,日志系统必不可少。Apache为了让众多的日志工具有一个相同操作方式,实现了一个通用日志工具包:commons-logging。而Log4j基本上是Java平台上最好的日志组件了。

    使用ommons-logging的Log接口,并由commons-logging在运行时决定使用哪种日志架构(如Log4j)。现在,Apache通用日志工具commons-logging和Log4j已经成为Java日志的标准工具。

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,969
精华内容 4,387
关键字:

java日志系统

java 订阅