• Java常用日志框架--JUL


    1. 日志文件分类

    1.1.调试日志

    调试日志在开发过程中调试程序,输出的日志。

    2.1系统日志

    系统日志是用来记录系统中硬件、软件和系统相关问题的信息。同时还可以监视系统中发生的事件。用户可以通过它来检查错误发生的原因,或者寻找收到攻击时留下的痕迹。系统日志包括系统日志、应用日志和安全日志这几种分类。

    2. 日志框架概述

    2.1 日志框架的作用

    (1)控制日志输出的内容和格式。
    (2)控制日志输出的位置。
    (3)日志文件相关的优化,如异步、归档、压缩。
    (4)日志系统的维护。
    (5)面向接口开发–日志的门面。

    2.2 市面流行的日志框架

    JUL java util logging: Java原生日志框架
    Log4j: Apache的一个开源项目
    Logback: 由Log4j之父做的另一个开源项目,一个可靠、通用且灵活的java日志框架
    Log4j2: Log4j官方的第二个版本,各个方面都是与Logback及其相似。具有插件式结构、配置文件优化等特征,Spring Boot1.4 版本以后就不再支持log4j,所以第二个版本应运而生

    2.3 日志门面技术

    日志门面技术 JCL、SLF4j

    2.4 为什么要使用日志门面技术

    4.1 降低代码和日志框架的耦合性:日志门面技术需要配合日志框架使用,并且可以做到在不改动代码的情况下,可以切换日志框架。

    不同的项目调用不同的日志框架
    抽取出方法c,其实内部调用的还是各自记录日志的方法。
    在这里插入图片描述

    3. 日志框架详解

    3.1 JUL简介

    JUL是Java自带的框架,使用时不需要另外引用第三方的类库,相对其他框架使用简单,主要是使用在小型应用中,我看公司的代码比较老的项目用的是这个框架。

    3.2 JUL组件介绍

    在这里插入图片描述
    Logger:被称为记录器,应用程序通过获取Logger对象,调用其API来发布日志信息。Logger通常被认为是访问日志系统的入口程序。
    Handler:处理器,每个Logger都会关联一个或者是一组Handler,Logger会将日志交给关联的Handler去做处理,由Handler负责将日志做记录。Handler具体实现了日志的输出位置,比如可以输出到控制台或者文件中等等。
    Filter:过滤器,根据需要定制哪些信息会被记录,哪些信息会被略过。
    Formatter:格式化组件,它负责对日志中的数据和信息进行转换和格式化,所以它决定了我们日志输出最终的形式。
    Level:日志的输出级别,每条日志消息都有一个关联的级别。我们根据输出级别的设置,用来展现最终所呈现的日志信息。

    3.3 JUL组件案例

    3.3.1 JUL组件案例

    1)Logger对象的创建方式:不能直接new 对象,用getLogger方法获取logger对象。

    //com.form.project.test.LogDemoCtroller为当前类的全路径
     Logger logger = Logger.getLogger("com.form.project.test.LogDemoCtroller");
    
    • 1
    • 2

    2)日志的两种输出方式:

    //方式一:直接调用日志级别相关的方法,方法中传递日志输出信息
    logger.info("输出info信息1");
    
    //方式二:调用通用的log方法,然后在里面通过level类型来定义日志的级别参数,以及搭配日志输出信息的参数。
    logger.log(Level.INFO,"输出info信息2");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3)日志中的占位符

            /**
             * 我们可以使用字符串拼接的方式输出学生信息 姓名 年龄
             */
            String name = "张三";
            int age = 23;
            logger.log(Level.INFO,"学生的姓名为:"+name+";年龄为:"+age);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    但是字符串拼接的方式程序效率低,可读性不强,维护成本高,所以我们可以使用占位符的方式来进行操作。

    		//0表示是第一个占位符 1表示第二个占位符
    		String name = "张三";
            int age = 23;
            logger.log(Level.INFO,"学生的姓名:{0},年龄:{1}",new Object[]{name,age});
    
    • 1
    • 2
    • 3
    • 4

    3.3.2 JUL日志的级别

    1)JUL日志的级别

              SEVERE:(最高级)错误 ----最高级的日志级别
              WARNING:警告
              INFO:(默认级别)消息
              CONFIG:配置
              FINE:详细信息(少)
              FINER:详细信息(中)
              FINEST:详细信息(多)----最低级的日志级别
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
     		 两个特殊的级别
             OFF: 可用来关闭日志记录
             ALL:  启用所有消息的日志记录
    
    • 1
    • 2
    • 3
    /**
    * 我们可以看到第二个参数是数值,数值的意义在于,如果我们设置的日志的级别是INFO--800
    * 那么最终展现的日志信息,必须是数值大于800的所有日志信息
    * 即打印出的级别为:INFO、WARNING、SEVERE
    **/
    //部分日志级别源码:
     	public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
    
        public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
    
        public static final Level INFO = new Level("INFO", 800, defaultBundle);
    
        public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
    
        public static final Level FINE = new Level("FINE", 500, defaultBundle);
    
        public static final Level FINER = new Level("FINER", 400, defaultBundle);
    
        public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2)默认的日志级别
    默认的日志级别为info,我们下面代码程序中有7个日志级别,但是输出只有3个日志级别,说明默认的日志级别是info,这样就是输出了info及以上的信息。

     Logger logger = Logger.getLogger("com.form.project.test.LogDemoCtroller");
            logger.severe("severe信息");
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
     输出:
     九月 17, 2022 5:30:32 下午 com.form.project.test.LogDemoCtroller test02
     严重: severe信息
     九月 17, 2022 5:30:32 下午 com.form.project.test.LogDemoCtroller test02
     警告: warning信息
     九月 17, 2022 5:30:32 下午 com.form.project.test.LogDemoCtroller test02
     信息: info信息       
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3)自定义日志级别

            Logger.getLogger("com.form.project.test.LogDemoCtroller");
            //将默认的日志打印方式关闭掉
            //参数设置为flase,我们打印日志的方式就不会按照父logger默认的方式进行操作
            logger.setUseParentHandlers(false);
    
            //处理器Handler
            //在此我们使用的是控制台日志处理器,取得处理器对象
            ConsoleHandler handler = new ConsoleHandler();
            //创建日志格式化组件对象
            SimpleFormatter formatter = new SimpleFormatter();
    
            //在处理器中设置输出格式
            handler.setFormatter(formatter);
            //在记录器中添加处理器
            logger.addHandler(handler);
    
            //设置日志的打印级别
            //此处必须将日志记录器和处理器的级别进行统一的设置,才会达到日志显示相应级别的效果
            logger.setLevel(Level.ALL);
            handler.setLevel(Level.ALL);
            
            logger.severe("severe信息");
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
    输出:
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    严重: severe信息
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    警告: warning信息
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    信息: info信息
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    配置: config信息
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    详细: fine信息
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    较详细: finer信息
    九月 17, 2022 8:25:50 下午 com.form.project.test.LogDemoCtroller test02
    非常详细: finest信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    3.3.3 JUL文件日志

    1)JUL文件日志的打印

        @Test
        public void test03() throws IOException {
            /*
              将日志输出到具体的磁盘文件中
              这样做相当于是做了日志的持久化操作
             */
            Logger logger = Logger.getLogger("com.form.project.test.LogDemoCtroller");
            logger.setUseParentHandlers(false);
    
            //文件日志处理器
            FileHandler fileHandler = new FileHandler("/Users/chezhewei/Desktop/mylog.log");
    
            //创建日志格式化组件对象
            SimpleFormatter formatter = new SimpleFormatter();
    
            //在处理器中设置输出格式
            fileHandler.setFormatter(formatter);
            //在记录器中添加处理器
            logger.addHandler(fileHandler);
    
            logger.severe("severe信息");
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在桌面生成了log日志文件,如图所示
    请添加图片描述
    文件中的内容为:

    九月 17, 2022 8:50:03 下午 com.form.project.test.LogDemoCtroller test03
    严重: severe信息
    九月 17, 2022 8:50:03 下午 com.form.project.test.LogDemoCtroller test03
    警告: warning信息
    九月 17, 2022 8:50:03 下午 com.form.project.test.LogDemoCtroller test03
    信息: info信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    日志的打印只是将控制台处理器变成了文件处理器,也可以同时设置控制台处理和文件处理,也就是同时添加多个处理器。

     public void test03() throws IOException {
            /*
              将日志输出到具体的磁盘文件中
              这样做相当于是做了日志的持久化操作
             */
            Logger logger = Logger.getLogger("com.form.project.test.LogDemoCtroller");
            logger.setUseParentHandlers(false);
    
            //文件日志处理器
            FileHandler fileHandler = new FileHandler("/Users/chezhewei/Desktop/mylog.log");
            //创建日志格式化组件对象
            SimpleFormatter formatter = new SimpleFormatter();
            //在处理器中设置输出格式
            fileHandler.setFormatter(formatter);
            //在记录器中添加处理器
            logger.addHandler(fileHandler);
    
    		//同时设置在控制台和文件中进行打印
    		ConsoleHandler handler = new ConsoleHandler();
    		//在处理器中设置输出格式
            handler.setFormatter(formatter);
            //在记录器中添加处理器
            logger.addHandler(handler);
    
            logger.severe("severe信息");
            logger.warning("warning信息");
            logger.info("info信息");
            logger.config("config信息");
            logger.fine("fine信息");
            logger.finer("finer信息");
            logger.finest("finest信息");
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    3.3.4 JUL Logger的父子关系

    Logger之间的"父子"关系,这种父子关系不是继承关系,是通过树状结构存储的(代码包的层级)。
    RootLogger是所有logger对象的顶层logger,logger1的父类也为RootLogger。
    JUL在初始化时,会创建一个顶层RootLogger作为所有Logger的父Logger
    查看源码:
    owner.rootLogger = owner.new RootLogger();
    rootLogger是LogManager的内部类
    java.util.logging.LogManager$RootLogger默认名称为 空串
    父子关系同时也是节点之间的挂载关系
    LoggerContext cx = getUserContext();//LoggerContext 一种用来保存节点的Map关系
    private LogNode node;//节点

    Logger logger1 = Logger.getLogger("com.form.project.test");//父(父logger的父亲是RootLogger)
    Logger logger2 = Logger.getLogger("com.form.project.test.LogDemoCtroller");//子
    
     //System.out.println(logger2.getParent() == logger1);//输出为true
     System.out.println("logger1的父logger引用为:"+logger1.getParent()+";父亲的名称为"+logger1.getParent().getName());
     System.out.println("logger2的父logger引用为:"+logger2.getParent()+";父亲的名称为"+logger2.getParent().getName());
     输出为:
     logger1的父logger引用为:java.util.logging.LogManager$RootLogger@1c72da34;父亲的名称为
     logger2的父logger引用为:java.util.logging.Logger@6b0c2d26;父亲的名称为com.tang.project1.test
    
    
      /*
      父亲所做的设置,也能够同时作用于儿子
      对logger1做的日志打印相关的设置,然后我们使用logger2进行日志的打印
       */
      //父类做输出
       logger1.setUseParentHandlers(false);
       ConsoleHandler handler = new ConsoleHandler();
       SimpleFormatter formatter = new SimpleFormatter();
       handler.setFormatter(formatter);
       logger1.addHandler(handler);
    
       logger1.setLevel(Level.ALL);
        handler.setLevel(Level.ALL);
    
        //子类做打印
        logger2.severe("severe信息");
        logger2.warning("warning信息");
        logger2.info("info信息");
        logger2.config("config信息");
        logger2.fine("fine信息");
        logger2.finer("finer信息");
        logger2.finest("finest信息");
    输出如下:
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    严重: severe信息
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    警告: warning信息
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    信息: info信息
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    配置: config信息
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    详细: fine信息
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    较详细: finer信息
    九月 17, 2022 9:46:04 下午 com.form.project.test.LogDemoCtroller test04
    非常详细: finest信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    3.3.5 JUL 配置文件位置

    1)系统默认配置文件
    以上所有的配置和相关的操作,都是以java硬编码的形式进行的我们可以使用更加清晰,更加专业的一种做法,就是使用配置文件。如果我们没有自己添加配置文件,则会使用系统默认的配置文件。
    系统默认的配置文件在:jre–>lib–>logging.properties
    默认配置文件信息解释:
    请添加图片描述
    请添加图片描述
    2)使用自定义配置文件
    使用自定义配置文件:

        @Test
        public void test06() throws IOException {
            InputStream inputStream = new FileInputStream("自定义配置文件地址");
            //取得日志管理器对象
            LogManager logManager = LogManager.getLogManager();
            //读取自定义配置文件
            logManager.readConfiguration(inputStream);
            Logger logger1 = Logger.getLogger("com.form.project.test.LogDemoCtroller");
            logger1.severe("severe信息");
            logger1.warning("warning信息");
            logger1.info("info信息");
            logger1.config("config信息");
            logger1.fine("fine信息");
            logger1.finer("finer信息");
            logger1.finest("finest信息");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    自定义配置文件的输出:
    请添加图片描述
    追加日志:
    请添加图片描述

    3.3 JUL日志框架使用方式总结(原理解析)

    1) 初始化LogManager,LogManager加载logging.properties配置文件,添加Logger到LogManager
    2)从单例的LogManager获取Logger
    3)设置日志级别level.在打印的过程中使用到了日志记录的LogRecord类
    4)Filter作为过滤器提供了日志级别之外更细粒度的控制。
    5)Handler日志处理器。决定日志的输出位置.例如控制台、文件。。。
    6)Formatter是用来格式化输出的

  • 相关阅读:
    利用torch.nn实现softmax回归Fashion-MNIST数据集上进行训练和测试
    基于Spring Boot+vue的民宿预定管理系统的设计与实现
    JVM笔记:GC 日志分析
    谷粒学苑_第一天
    MySQL基础篇【子查询】
    四、网络请求与路由
    微信小程序家政预约系统+后台管理系统
    SAP,ABAP:ALV变式复制
    两种常见矩形框旋转方法推导及其C++实现
    网络协议学习:第一天
  • 原文地址:https://blog.csdn.net/trh_csdn/article/details/126899096