【Java日志系列】JUL日志框架

目录

前言

一、JUL简介

二、JUL组件介绍

三、代码实例

1. 入门案例

2. 日志级别

3. 将日志输出到文件中

4. Logger的父子关系

5. 使用配置文件

5.1 默认配置文件位置

5.2 配置文件解析

5.3 自定义读取配置文件

5.4 自定义日志配置文件

总结


前言

  Java Util Logging (JUL) 是Java平台自带的一个日志框架,无需额外依赖第三方库即可使用。由于其集成度高、配置简单的特点,JUL在一些小型项目或初学者入门阶段非常受欢迎。本文将详细介绍JUL的基本概念、常用组件以及如何通过示例代码来理解和使用这些组件。此外,我们还会探讨如何通过配置文件来自定义日志行为,这对于实现更加灵活的日志管理至关重要。

一、JUL简介

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

二、JUL组件介绍

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

三、代码实例

1. 入门案例

// 入门案例
@Test
public void test01() {
    // Logger创建方式,参数为当前类全路径字符串com.demo.logger.jul.JULTest
    Logger logger = Logger.getLogger(JULTest.class.getCanonicalName());

    /*
        第一种方式:
            直接调用日志级别相关的方法,方法中传递日志输出信息
            假设现在我们要输出info级别的日志信息
     */
    logger.info("输出info信息");

    /*
        第二种方式:
            调用通用的log方法,然后在里面通过level类型来定义日志的级别参数,以及搭配日志输出信息的参数
     */
    logger.log(Level.WARNING, "输出warning信息");


    // 动态输出数据,生产日志,使用占位符的方式进行操作
    String name = "zhangsan";
    int age = 23;
    // logger.log(Level.INFO, "姓名:" + name + "年龄:" + age);
    logger.log(Level.INFO, "姓名:{0}年龄:{1}", new Object[]{name, age});

}

2. 日志级别

// 日志级别
@Test
public void test02() {
    /*
        日志的级别,总共七级
            Level.SEVERE:(最高级)错误
            Level.WARNING:警告
            Level.INFO:(默认级别)消息
            Level.CONFIG:配置级别
            Level.FINE:详细信息(少)
            Level.FINER:详细信息(中)
            Level.FINEST:(最低级)详细信息(多)

       两个特殊的级别:
            Level.OFF;可用来关闭日志记录
            Level.ALL:启用所有日志记录

        对于日志的级别,我们重点关注的是new对象时第二个参数,是一个数值:
            public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
            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);
            public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
        这个数值的意义在于:如果我们设置的日志级别是800,那么最终展现的日志信息,比如是数值大于800的所有日志信息。
     */

    Logger logger = Logger.getLogger(JULTest.class.getCanonicalName());

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

}

3. 自定义日志级别
  JUL对于日志级别的自定义有些麻烦,要先排除掉默认的Handler,然后替换为自定义的Handler。

// 自定义日志级别
@Test
public void test03(){
    //日志记录器
    Logger logger = Logger.getLogger(JULTest.class.getCanonicalName());

    //将默认的日志打印方式关闭掉
    //参数设置为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信息");

}

3. 将日志输出到文件中

  用户使用Logger来进行日志的记录,Logger可以持有多个处理器Handler(日志的记录使用的是Logger,日志的输出使用的是Handler)。添加了哪些handler对象,就相当于需要根据所添加的handler将日志输出到指定的位置上,例如控制台、文件等。

@Test
public void test04() throws IOException {
    /*
        将日志输出到具体的磁盘文件中
        这样做相当于是做了日志的持久化操作
     */
    Logger logger = Logger.getLogger(JULTest.class.getCanonicalName());
    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);
    handler.setLevel(Level.ALL); // 文件中的日志级别为ALL
    handler2.setLevel(Level.CONFIG); // 控制台的日志级别为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之间是存在"父子"关系的,值得注意的是,这种父子关系不是我们普遍认为的类之间的继承关系,这种关系是通过树状结构存储的。

@Test
public void test05(){
    /*
        从下面创建的两个logger对象看来
        我们可以认为logger1是logger2的父亲
     */

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

    Logger logger2 = Logger.getLogger("com.demo.test.JULTest");

    System.out.println(logger2.getParent()==logger1); //true

    // logger1的父Logger引用为:java.util.logging.LogManager$RootLogger@31ef45e3; 名称为com.demo.test; 父亲的名称为
    System.out.println("logger1的父Logger引用为:"
            +logger1.getParent()+"; 名称为"+logger1.getName()+"; 父亲的名称为"+logger1.getParent().getName());

    // logger2的父Logger引用为:java.util.logging.Logger@598067a5; 名称为com.demo.test.JULTest; 父亲的名称为com.demo.test
    System.out.println("logger2的父Logger引用为:"
            +logger2.getParent()+"; 名称为"+logger2.getName()+"; 父亲的名称为"+logger2.getParent().getName());


    /*
        父亲所做的设置,也能够同时作用于儿子
        对logger1做日志打印相关的设置,然后我们使用logger2进行日志的打印
     */
    //父亲做设置
    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);

    //儿子做打印,会输出ALL
    logger2.severe("severe信息");
    logger2.warning("warning信息");
    logger2.info("info信息");
    logger2.config("config信息");
    logger2.fine("fine信息");
    logger2.finer("finer信息");
    logger2.finest("finest信息");
}

5. 使用配置文件

5.1 默认配置文件位置

  如果我们没有自己添加配置文件,则会使用系统默认的配置文件。也就是说,如果我们没有指定配置文件的话,JUL也是会读取默认的配置文件,对于不同的JDK版本来说,读取的文件路径是不一样的,一般我们会认为其默认配置文件在java.homo目录中,jre文件夹下,lib目录中的logging.properties文件。但是,以我的JDK17为例,其配置文件所在的位置如下图所示:

5.2 配置文件解析

# RootLogger使用的处理器,在获取RootLogger对象时进行的设置
# 默认情况下,配置的是控制台处理器,只能在控制台上进行输出操作
# 如果想要其他的处理器,在处理器类后面通过以逗号的形式进行分割
handlers= java.util.logging.ConsoleHandler

# 根节点RootLogger的日志级别
# 默认情况下,这是全局的日志级别,如果不手动配置其他的日志级别,则默认输出下述配置的级别及更高的级别
.level= INFO

# 文件处理器属性的设置
# 输出日志文件的路径
java.util.logging.FileHandler.pattern = %h/java%u.log
# 输出日志文件的限制(默认50000个字节)
java.util.logging.FileHandler.limit = 50000
# 设置日志文件的数量
java.util.logging.FileHandler.count = 1
# 输出日志的格式
# 默认是以XML的方式输出
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# 控制台处理器的属性设置
# 控制台输出默认级别
java.util.logging.ConsoleHandler.level = INFO
# 控制台默认输出日志的格式
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# 也可以将日志级别设定到具体的某个包下
#com.xyz.foo.level = SEVERE

5.3 自定义读取配置文件

  可以将logging.properties文件稍作修改,验证有效性。

InputStream input = new FileInputStream("E:\\logging.properties");

//取得日志管理器对象
LogManager logManager = LogManager.getLogManager();

//读取自定义的配置文件
logManager.readConfiguration(input);

Logger logger = Logger.getLogger(JULTest.class.getCanonicalName());

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

5.4 自定义日志配置文件

  以下配置可以自定义FileHandler的设置:

# 自定义Logger
com.demo.logger.jul.handlers=java.util.logging.FileHandler
# 自定义Logger日志等级
com.demo.logger.jul.level=CONFIG
# 屏蔽掉父Logger的日志设置
com.demo.logger.jul.useParentHandlers=false

  默认使用的是XMLFormatter,我们可以改成容易读的:

java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

  文件默认保存在用户的home目录的java0.log文件。默认的日志文件是覆盖的方式,我们可以设置为追加的方式:

# 输出日志文件,是否追加
java.util.logging.FileHandler.append=true

总结

  本文通过一系列示例代码详细介绍了Java Util Logging的基本使用方法和高级特性,包括如何创建和使用Logger对象、设置日志级别、配置日志输出目的地以及利用父子关系来简化日志配置。此外,还介绍了如何通过自定义配置文件来实现更复杂的日志管理需求。掌握了这些知识后,开发者可以更加高效地管理和调试他们的Java应用程序。尽管JUL相比其他第三方日志框架可能功能有限,但在某些场景下,尤其是对于小型项目或特定需求的应用而言,它仍然是一个非常实用的选择。 

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

边城仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值