zoukankan      html  css  js  c++  java
  • Java中的日志框架

    需求

    使用日志框架有三点需求:

    1、期望日志能保存在文件中,方便时候排错。

    2、开发环境的日志记录会更多方便调试。

    3、生产环境需要记录重要的信息。

     

    Log4j

    可用于普通maven项目,也可以用于springboot项目。

    Log4j提供了简单的API调用,强大的日志格式定义以及灵活的扩展性。

    可以自定义Appender来满足日志输出的需求。

     

    日志级别

    从低到高

    DEBUG INFO WARN ERROR FATAL

     

    pom依赖

    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.8.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.8.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl -->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.8.2</version>
    </dependency>

    目录结构

    - src
     - main
      - java
      - resources
         log4j.properties

    配置文件

    log4j.properties

    log4j.rootLogger=debug, stdout, A, D, E
     
    ### Output to the console ###
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %t [%p] %c{1} (%F:%L) %m%n
     
    ### Output to the log file ###
    log4j.appender.A=org.apache.log4j.RollingFileAppender
    log4j.appender.A.File=D:/logs/firestorm.log
    log4j.appender.A.MaxFileSize=1000KB
    log4j.appender.A.MaxBackupIndex=1
    log4j.appender.A.layout=org.apache.log4j.PatternLayout
    log4j.appender.A.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %t [%p] %c{1} (%F:%L) %m%n
     
    ### 输出DEBUG 级别以上的日志 ###
    log4j.appender.D=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.D.File=D://logs/debug/debug.log
    log4j.appender.D.Append=true
    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.SSS} %t [%p] %c{1} (%F:%L) %m%n
     
    ### 输出ERROR 级别以上的日志 ###
    log4j.appender.E=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.E.File=D://logs/error/error.log
    log4j.appender.E.Append=true
    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.SSS} %t [%p] %c{1} (%F:%L) %m%n

    Appender

    指定日志输出目的地,可以是控制台也可以是文件。

    • 输出到控制台的org.apache.log4j.ConsoleAppender

    • 输出到文件的org.apache.log4j.DailyRollingFileAppender

     

    ConversionPattern

    指定日志的输出格式

    %p:输出日志信息的优先级,即DEBUG,INFO,WARN,ERROR,FATAL。
    %d:输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,如:%d{yyyy/MM/dd HH:mm:ss,SSS}。
    %r:输出自应用程序启动到输出该log信息耗费的毫秒数。
    %t:输出产生该日志事件的线程名。
    %l:输出日志事件的发生位置,相当于%c.%M(%F:%L)的组合,包括类全名、方法、文件名以及在代码中的行数。例如:test.TestLog4j.main(TestLog4j.java:10)。
    %c:输出日志信息所属的类目,通常就是所在类的全名。
    %M:输出产生日志信息的方法名。
    %F:输出日志消息产生时所在的文件名称。
    %L::输出代码中的行号。
    %m::输出代码中指定的具体日志信息。
    %n:输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"%x:输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
    %%:输出一个"%"字符。
    另外,还可以在%与格式字符之间加上修饰符来控制其最小长度、最大长度、和文本的对齐方式。如:
    %20c:指定输出category的名称,最小的长度是20,如果category的名称长度小于20的话,默认的情况下右对齐。
    %-20c:"-"号表示左对齐。
    %.30c:指定输出category的名称,最大的长度是30,如果category的名称长度大于30的话,就会将左边多出的字符截掉,但小于30的话也不会补空格。

    性能问题

    Java的IO是阻塞式的,频繁的往文件中写入日志,对系统性能有较大的影响。

     

    性能最差的是ImmediateFlush=true的时候(关闭了缓存),而性能最好的就是开启日志异步AsyncAppender处理的时候

     

    开启缓存

    1、好处:提升系统响应性能;

    2、不足:当系统因为异常而崩溃,又或者jvm被强行关闭,从而导致缓存中的数据丢失,日志不存在,无法及时确定异常原因。

     

    具体实施

    • 当ImmediateFlush=true时候,表示每一条打印日志请求都会被立即输出,也就是立刻同步到磁盘中去。在高并发下,系统性能受到很大的影响,IO和磁盘读写数大大提升。

    • 当ImmediateFlush=false时候,与上面正好相反,表示每一条打印日志请求不会被立即输出,会使用java.io.OutputStreamWriter的缓存,缓存大小为1024字节。

    • 当ImmediateFlush=false、BufferedIO=true、BufferSize=8192时候,表示使用java.io.BufferedWriter缓存,缓存大小为默认8192字节,每一条打印请求不会立即输出,当缓存达到8192字节后才会输出到文件。这样一来,大大减少了IO和磁盘读写操作,提升了系统的性能。

     

    log4j.appender.HOOKFILE=com.***.***.HookFileAppender
    log4j.appender.HOOKFILE.File=D://logs/debug/debug.log
    log4j.appender.HOOKFILE.Append=true
    log4j.appender.HOOKFILE.Threshold=DEBUG
    ### 开启缓存 ###
    log4j.appender.D.BufferedIO=true
    log4j.appender.D.ImmediateFlush=false
    log4j.appender.D.BufferSize=8192
    ### 开启缓存 ###
    log4j.appender.HOOKFILE.layout=org.apache.log4j.PatternLayout
    log4j.appender.HOOKFILE.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS} %t [%p] %c{1} (%F:%L) %m%n

     

    钩子

    jvm运行结束,日志信息没有保存到磁盘中,还存在于缓存中

    以下的程序可以保证数据保存到文件。

    public class HookFileAppender extends FileAppender {
        public HookFileAppender(){
            super();
            //添加钩子程序
            Runtime.getRuntime().addShutdownHook(new Log4jHockThread());
        }
        public HookFileAppender(Layout layout, String filename) throws IOException {
            super(layout,filename);
            //添加钩子程序
            Runtime.getRuntime().addShutdownHook(new Log4jHockThread());
        }
        public HookFileAppender(Layout layout, String filename, boolean append) throws IOException {
            super(layout,filename,append);
            //添加钩子程序
            Runtime.getRuntime().addShutdownHook(new Log4jHockThread());
        }
        public HookFileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
                     int bufferSize) throws IOException {
            super(layout,filename,append,bufferedIO,bufferSize);
            Runtime.getRuntime().addShutdownHook(new Log4jHockThread());
        }
     
        class Log4jHockThread extends Thread{
            @Override
            public void run() {
                //jvm结束之前,运行flush操作,将日志写入磁盘;
                if(qw != null){
                    qw.flush();
                }
            }
        }
    }

    具体使用

    import fabric.edu.sdk.ca.CaManager;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
     
    /**
     * @author wzm
     * @version 1.0.0
     * @date 2020/1/24 15:25
     **/
    public class MyTest {
     
        private static final Log log = LogFactory.getLog(CaManager.class);
     
        public static void main(String[] args) {
            log.info("hello");
            log.debug("hello");
            log.error("hello");
            log.warn("hello");
        }
    }

    打印

    2020/01/26 15:01:43.005 main [INFO] CaManager (MyTest.java:17) hello
    2020/01/26 15:01:43.006 main [DEBUG] CaManager (MyTest.java:18) hello
    2020/01/26 15:01:43.006 main [ERROR] CaManager (MyTest.java:19) hello
    2020/01/26 15:01:43.007 main [WARN] CaManager (MyTest.java:20) hello

    logback

    xxx

     

  • 相关阅读:
    UVa 11988
    UVa 442
    .MySQL数据库技术
    Mysql数据库技术
    JDBC技术
    JDBC技术
    JavaSE编程基础
    JavaSE编程基础
    JavaSE编程基础
    web安全性测试
  • 原文地址:https://www.cnblogs.com/jockming/p/12234306.html
Copyright © 2011-2022 走看看