java日志框架之JUL(Logging)

有时候,不是因为你没有能力,也不是因为你缺少勇气,只是因为你付出的努力还太少,所以,成功便不会走向你。而你所需要做的,就是坚定你的梦想,你的目标,你的未来,然后以不达目的誓不罢休的那股劲,去付出你的努力,成功就会慢慢向你靠近。

导读:本篇文章讲解 java日志框架之JUL(Logging),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

1、JUL简介

  • JUL全程 Java Util Logging,它是java原生的日志框架,使用时不需要另外引用第三方的类库
  • 相对其他的框架使用方便,学习简单,主要是使用在小型应用中。

2、JUL组件介绍

在这里插入图片描述

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

3、Logger入门使用

导包

import java.util.logging.Logger;
@Test
public void test01(){
    //Logger对象的创建方式,不能直接new对象
    //取得对象的方法参数,需要引入当前类的全路径字符串
    Logger logger = Logger.getLogger("com.xc.mylog.JULTest");
    
    //第一种方式: 直接调用日志级别相关的方法,方法中传递日志输出信息
    logger.info("输出info信息1");
    
    //第二种方式:调用通用的log方法,然后在里面通过Level类型来定义日志的级别参数,
    // 以及搭配日志输出信息的参数
    logger.log(Level.INFO,"输出info信息2");
    
    //日志添加参数
    String name = "zs";
    int age = 23;
    logger.log(Level.INFO,"学生的姓名:{0},年龄:{1}",new Object[]{name,age});
}

输出结果:

六月 20, 2022 9:23:41 下午 com.xc.mylog.JULTest test01
信息: 输出info信息1
六月 20, 2022 9:23:41 下午 com.xc.mylog.JULTest test01
信息: 输出info信息2
六月 20, 2022 9:23:41 下午 com.xc.mylog.JULTest test01
信息: 学生的姓名:zs,年龄:23

Process finished with exit code 0

4、Logger日志级别

日志级别源码类:java.util.logging.Level

  • 日志普通级别
//错误 --- 最高级的日志级别
public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
//WARNING : 警告
public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
//INFO : (默认级别)消息
public static final Level INFO = new Level("INFO", 800, defaultBundle);
//CONFIG : 配置
public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
//FINE : 详细信息
public static final Level FINE = new Level("FINE", 500, defaultBundle);
//FINER : 较详细信息
public static final Level FINER = new Level("FINER", 400, defaultBundle);
//FINEST : 非常详细信息 --- 最低级的日志级别
public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
  • 两个特殊级别
//OFF 可用来关闭日志记录
public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
//ALL 启用所有消息的日志记录
public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);

原理分析

  • 根据new Level第二个数值参数判断,如设置info级别,对应数值就是800
  • 那么>=800的SEVERE 、WARNING、INFO三个级别的都可以输出
  • 同理off大于Integer.MAX_VALUE没日志,大于Integer.MIN_VALUE输出所有日志
@Test
public void test02(){
    Logger logger = Logger.getLogger("com.xc.mylog.JULTest");
	//打印日志
    logger.severe("severe信息");
    logger.warning("warning信息");
    logger.info("info信息");
    logger.config("config信息");
    logger.fine("fine信息");
    logger.finer("finer信息");
    logger.finest("finest信息");
}

输出结果:

六月 20, 2022 9:39:49 下午 com.xc.mylog.JULTest test02
严重: severe信息
六月 20, 2022 9:39:49 下午 com.xc.mylog.JULTest test02
警告: warning信息
六月 20, 2022 9:39:49 下午 com.xc.mylog.JULTest test02
信息: info信息

Process finished with exit code 0

由输出结果可知,默认的输出级别为info

自定义日志的级别

  • 关闭按照父logger默认的方式去进行操作
  • 日志记录器和处理器的级别进行统一的设置,才会达到日志显示相应级别的效果
@Test
public void test03(){
    //日志记录器
    Logger logger = Logger.getLogger("com.xc.mylog.JULTest");

    //将默认的日志打印方式关闭掉
    //参数设置为false,我们打印日志的方式就不会按照父logger默认的方式去进行操作
    logger.setUseParentHandlers(false);

    //处理器Handler
    //在此我们使用的是控制台日志处理器,取得处理器对象
    ConsoleHandler handler = new ConsoleHandler();
    //创建日志格式化组件对象
    SimpleFormatter formatter = new SimpleFormatter();

    //在处理器中设置输出格式
    handler.setFormatter(formatter);
    //在记录器中添加处理器
    logger.addHandler(handler);

    //设置日志的打印级别
    //此处必须将日志记录器和处理器的级别进行统一的设置,才会达到日志显示相应级别的效果
    //logger.setLevel(Level.CONFIG);
    //handler.setLevel(Level.CONFIG);

    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信息");
}

输出结果:

六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
严重: severe信息
六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
警告: warning信息
六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
信息: info信息
六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
配置: config信息
六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
详细: fine信息
六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
较详细: finer信息
六月 20, 2022 9:47:02 下午 com.xc.mylog.JULTest test03
非常详细: finest信息

Process finished with exit code 0

日志持久化(保存到磁盘)

  • 用户使用Logger来进行日志的记录,Logger可以持有多个处理器Handler
  • 日志的记录使用的是Logger,日志的输出使用的是Handler
  • 可以输出到控制台也可以输出到文件,也可以两者兼备
@Test
public void test04() throws IOException {
    Logger logger = Logger.getLogger("com.xc.mylog.JULTest");
    logger.setUseParentHandlers(false);
    //文件日志处理器
    FileHandler handler = new FileHandler("D:\\test\\myLogTest.log");
    SimpleFormatter formatter = new SimpleFormatter();
    handler.setFormatter(formatter);
    logger.addHandler(handler);
    //也可以同时在控制台和文件中进行打印
    ConsoleHandler handler2 = new ConsoleHandler();
    handler2.setFormatter(formatter);
    logger.addHandler(handler2); //可以在记录器中同时添加多个处理器

    logger.setLevel(Level.ALL);
    //输出到文件的级别为all
    handler.setLevel(Level.ALL);
    //输出到控制台的解绑为config
    handler2.setLevel(Level.CONFIG);

    logger.severe("severe信息");
    logger.warning("warning信息");
    logger.info("info信息");
    logger.config("config信息");
    logger.fine("fine信息");
    logger.finer("finer信息");
    logger.finest("finest信息");
}

4、Logger之间的父子关系

  • JUL中Logger之间是存在”父子”关系的,这种父子关系不是我们普遍认为的类之间的继承关系
  • 关系是通过树状结构存储的
  • JUL在初始化时会创建一个顶层RootLogger作为所有Logger的父Logger
  • RootLogger对象作为树状结构的根节点存在的
  • 将来自定义的父子关系通过路径来进行关联
  • 父子关系,同时也是节点之间的挂载关系
@Test
public void test05(){

    /*
        从下面创建的两个logger对象看来
        我们可以认为logger1是logger2的父亲
     */

    //父亲是RootLogger,名称默认是一个空的字符串
    //RootLogger可以被称之为所有logger对象的顶层logger
    Logger logger1 = Logger.getLogger("com.xc");
    Logger logger2 = Logger.getLogger("com.xc.mylog");
    Logger logger3 = Logger.getLogger("com.xc.mylog.JULTest");

    System.out.println("logger1的父Logger引用为:"
            +logger1.getParent()+"; 名称为"+logger1.getName()+";" +
            " 父亲的名称为"+logger1.getParent().getName());

    System.out.println("logger2的父Logger引用为:"
            +logger2.getParent()+"; 名称为"+logger2.getName()+";" +
            " 父亲的名称为"+logger2.getParent().getName());

    System.out.println("logger3的父Logger引用为:"
            +logger3.getParent()+"; 名称为"+logger3.getName()+";" +
            " 父亲的名称为"+logger3.getParent().getName());
}

输出结果:

logger1的父Logger引用为:java.util.logging.LogManager$RootLogger@71bc1ae4; 名称为com.xc; 父亲的名称为
logger2的父Logger引用为:java.util.logging.Logger@6ed3ef1; 名称为com.xc.mylog; 父亲的名称为com.xc
logger3的父Logger引用为:java.util.logging.Logger@2437c6dc; 名称为com.xc.mylog.JULTest; 父亲的名称为com.xc.mylog
  • 父亲所做的设置,也能够同时作用于儿子
@Test
public void test06(){
    Logger logger1 = Logger.getLogger("com.xc.mylog");
    Logger logger2 = Logger.getLogger("com.xc.mylog.JULTest");
    //父亲设置级别为all
    logger1.setUseParentHandlers(false);
    ConsoleHandler handler = new ConsoleHandler();
    SimpleFormatter formatter = new SimpleFormatter();
    handler.setFormatter(formatter);
    logger1.addHandler(handler);
    handler.setLevel(Level.ALL);
    logger1.setLevel(Level.ALL);
    //儿子默认级别为info
    logger2.severe("severe信息");
    logger2.warning("warning信息");
    logger2.info("info信息");
    logger2.config("config信息");
    logger2.fine("fine信息");
    logger2.finer("finer信息");
    logger2.finest("finest信息");
}

输出结果:

六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
严重: severe信息
六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
警告: warning信息
六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
信息: info信息
六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
配置: config信息
六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
详细: fine信息
六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
较详细: finer信息
六月 20, 2022 10:08:47 下午 com.xc.mylog.JULTest test05
非常详细: finest信息

Process finished with exit code 0

5、Logger配置文件原理

Logger默认读取配置文件源码

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();
}
try (final InputStream in = new FileInputStream(fname)) {
    final BufferedInputStream bin = new BufferedInputStream(in);
    readConfiguration(bin);
}

默认会从java.home(jdk的jre文件夹)下的lib文件下的默认生成loggin.properties,如下

在这里插入图片描述

  • 自定义修改为只输出到日志文件中
  • 自定义日志是否追加,默认覆盖
@Test
public void test07() throws Exception {
    Logger logger = Logger.getLogger("com.xc.mylog.JULTest");
    logger.severe("severe信息");
    logger.warning("warning信息");
    logger.info("info信息");
    logger.config("config信息");
    logger.fine("fine信息");
    logger.finer("finer信息");
    logger.finest("finest信息");
}

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148614.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!