【JAVA日志框架】JUL,JDK原生日志框架详解。

2023-12-17

前言

Java日志体系混乱?Java日志框架系列,清晰简洁整理好整个Java的日志框架体系。第一篇,JDK原生日志框架——JUL。

目录

1.概述

2.日志级别

3.配置

4.继承关系


1.概述

日志框架的核心问题:

日志是用来记录应用的一些运行信息的。假设没有日志框架,我们要在应用里手动实现日志相关功能,我们需要关注些什么?其实仔细想想无非两点:

  • 记录哪些信息?

  • 记录到哪里去?

当然作为日志框架来说,为了方便使用,它还要关注一点就是:

  • 如何进行方便的配置

java日志体系中是先有的log4j,后面才有了JDK自带的jul,两者是两套体系,互不兼容。但其实本质上jul就是抄的log4j,其架构上都是一模一样的。以上三点核心问题,我们看作为日志框架的开山鼻祖的log4j是怎样解决的:

log4j给出的答案是:

  • 记录哪些信息——日志级别(level)

  • 记录到哪里去——提供不同的输出方式(appender),文件、控制台、其它等等

  • 如何进行方便的配置——除硬编码外,提供配置文件

jul是一模一样的,其只是把appender改成了handler而已。

2.日志级别

package com.eryi;

import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;

import java.util.logging.Level;
import java.util.logging.Logger;

public class Test {
    @org.junit.Test
    public void test1() {
    	//级别由低到高,默认输出info以上级别
        Logger logger = Logger.getLogger("abc");
        logger.log(Level.FINEST,"FINEST level");
        logger.log(Level.FINER,"FINER level");
        logger.log(Level.FINE,"FINE level");
        logger.log(Level.CONFIG,"CONFIG level");
        logger.log(Level.INFO,"INFO level");
        logger.log(Level.WARNING,"WARNING level");
        logger.log(Level.SEVERE,"SEVERE level");
        logger.log(Level.FINEST,"FINEST level");
        System.out.println("hello");
    }
}

日志为什么是红色的?因为底层调用了system.erro,所以会输出的字体是红色的。

3.配置

可以用代码的方式对JUL进行配置:

public static void main(String[] args) {
        // 获取根记录器
        Logger rootLogger = Logger.getLogger("");

        // 移除默认处理器
        rootLogger.setUseParentHandlers(false);

        // 创建控制台处理器
        ConsoleHandler consoleHandler = new ConsoleHandler();
        
        // 设置级别
        consoleHandler.setLevel(Level.INFO);

        // 设置自定义格式器
        consoleHandler.setFormatter(new SimpleFormatter());

        // 设置自定义过滤器
        consoleHandler.setFilter(new CustomFilter());

        // 将处理器添加到根记录器
        rootLogger.addHandler(consoleHandler);

        // 输出日志
        Logger logger = Logger.getLogger(JULConfigExample.class.getName());
        logger.severe("Severe message");
        logger.warning("Warning message");
        logger.info("Info message");
        logger.config("Config message");
        logger.fine("Fine message");
        logger.finer("Finer message");
        logger.finest("Finest message");
    }

    // 自定义格式器
    static class SimpleFormatter extends Formatter {
        @Override
        public String format(LogRecord record) {
            return "[" + record.getLevel() + "] - " + record.getMessage() + "\n";
        }
    }

    // 自定义过滤器
    static class CustomFilter implements Filter {
        @Override
        public boolean isLoggable(LogRecord record) {
            // 在这里可以添加自定义的过滤逻辑
            return record.getLevel().intValue() >= Level.INFO.intValue();
        }
    }

当然更合理、更方便的方式肯定是配置文件。配置文件的示例模板在jre/lib目录下:

把它拷贝过来改一下:

#默认配置
handlers= java.util.logging.ConsoleHandler
.level= FINEST

#file hander配置
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

#console handler配置
java.util.logging.ConsoleHandler.level = FINEST
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# 具体包路径下的日志级别
com.eryi.level = FINEST

解读一下配置:

  1. 默认配置:

    • handlers : 指定默认的处理器,这里是 java.util.logging.ConsoleHandler ,表示使用控制台输出。

    • .level : 设置默认的日志级别,这里是 FINEST ,表示记录最详细的日志。

  2. File Handler配置:

    • java.util.logging.FileHandler.pattern : 设置文件处理器的日志文件的命名模式, %h 表示用户主目录, %u 表示一个唯一的数值, %g 表示循环计数器。这里是 %h/java%u.log

    • java.util.logging.FileHandler.limit : 设置文件处理器的每个日志文件的大小限制,这里是 50000 字节。

    • java.util.logging.FileHandler.count : 设置文件处理器循环的文件数,这里是 1 个。

    • java.util.logging.FileHandler.formatter : 设置文件处理器的日志格式,这里是 java.util.logging.XMLFormatter ,表示使用 XML 格式。

  3. Console Handler配置:

    • java.util.logging.ConsoleHandler.level : 设置控制台处理器的日志级别,这里是 FINEST

    • java.util.logging.ConsoleHandler.formatter : 设置控制台处理器的日志格式,这里是 java.util.logging.SimpleFormatter ,表示使用简单格式。

  4. 具体包路径下的日志级别:

    • com.eryi.level : 设置特定包路径下的日志级别,这里是 FINEST ,表示 com.eryi 包下的日志级别为最详细。

这里要说一下为什么有了.level的配置之后还推出了专门指定某个包路径下日志级别的配置。是因为logger之间是有父子关系的。.level会对根logger生效,其余logger是继承自根logger的,但肯定工程上不一定是全局日志级别都是一致的,会有需求需要单独定制某一个或者某一些的logger的日志级别。

使用效果如下:

4.继承关系

logger之间存在父子关系。

root logger是最顶层的父logger:

Logger a = Logger.getLogger("a");
Logger b = Logger.getLogger("b");
System.out.println(a.getParent());
System.out.println(b.getParent());

通过父名·子名定义父子关系:

Logger a = Logger.getLogger("a");
Logger b = Logger.getLogger("a.b");
System.out.println(a.getParent());
System.out.println(b.getParent()==a);

为什么在设计的时候会存在父子关系?

Java Util Logging(JUL)的Logger之间存在父子关系,这是为了实现日志记录的层次结构和更方便的配置管理。这种父子关系的设计使得日志记录器可以继承和继承配置。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【JAVA日志框架】JUL,JDK原生日志框架详解。 的相关文章

  • “_加载小部件时出现问题”消息

    加载小部件时 如果找不到资源或其他内容 则会显示 加载小部件时出现问题 就这样 惊人的 此消息保留在主屏幕上 甚至没有说明加载时遇到问题的小部件 我通过反复试验弄清楚了这一点 但我想知道发生这种情况时是否有任何地方可以找到错误消息 Andr
  • Android 2.2 SDK - Droid X 相机活动无法正常完成

    我注意到我在 Droid X 上调用的默认相机活动与我的 Droid 和 Nexus One 上的默认相机活动看起来不同 在 Droid 和 Nexus One 上选择 确定 后 活动将完成 Droid X 有一个 完成 按钮 它将带您返回
  • 添加动态数量的监听器(Spring JMS)

    我需要添加多个侦听器 如中所述application properties文件 就像下面这样 InTopics Sample QUT4 Sample T05 Sample T01 Sample JT7 注意 这个数字可以多一些 也可以少一些
  • 如何使用 SimpleDateFormat 解析多种格式的日期

    我正在尝试解析文档中的一些日期 用户似乎以类似但不完全相同的格式输入了这些日期 以下是格式 9 09 9 2009 09 2009 9 1 2009 9 1 2009 尝试解析所有这些内容的最佳方法是什么 这些似乎是最常见的 但我想让我困扰
  • 为什么 java 编译器不报告 Intellij 中多播表达式的未经检查的强制转换警告?

    为什么下面的代码没有报告 Intellij IDEA 的未经检查的警告jdk 1 8 0 121自从Supplier
  • Android 自定义视图不能以正确的方式处理透明度/alpha

    我正在绘制自定义视图 在此视图中 我使用两个不同的绘画和路径对象在画布上绘画 我基本上是在绘制两个重叠的形状 添加 Alpha 后 视图中重叠的部分比图像的其余部分更暗 这是不希望的 但我不知道如何解决它 这是我的代码片段 用于展示我如何在
  • 主线程如何在该线程之前运行?

    我有以下代码 public class Derived implements Runnable private int num public synchronized void setA int num try Thread sleep 1
  • Scala 为了在 JVM 上运行做出了哪些妥协?

    Scala 是一种很棒的语言 但我想知道如果它有自己的运行时 如何改进 IE 由于 JVM 的选择 做出了哪些设计选择 我所知道的两个最重要的妥协是 类型擦除 http java sun com docs books tutorial ja
  • 列表应该如何转换为具体的实现?

    假设我正在使用一个我不知道源代码的库 它有一个返回列表的方法 如下所示 public List
  • Java 数组的最大维数

    出于好奇 在 Java 中数组可以有多少维 爪哇language不限制维数 但是JavaVM规范将维度数限制为 255 例如 以下代码将无法编译 class Main public static void main String args
  • 如何将 Jfreechart(饼图)添加到 netbeans 的面板中

    我正在使用 netbeans gui 编辑器 并且正在尝试添加一个本身位于内部框架中的 Jfreechart 并且这个内部框架我想将其添加到面板中 正如您在此图中看到的那样 抱歉 我无法直接发布图像 因为我新手 http www flick
  • Java 收集返回顶级项目的映射的嵌套流

    我有以下模型 class Item String name List
  • 如何记录来自 Akka (Java) 的所有传入消息

    在 Scala 中 您可以使用 LoggingReceive 包装接收函数 如何通过 Java API 实现相同的目标 def receive LoggingReceive case x do something Scala API 有Lo
  • 为什么java中的for-each循环中需要声明变量

    for 每个循环的通常形式是这样的 for Foo bar bars bar doThings 但如果我想保留 bar 直到循环结束 我可以not使用 foreach 循环 Foo bar null Syntax error on toke
  • 无法捕获 Spring Batch 的 ItemWriter 中的异常

    我正在编写一个 Spring Batch 流程来将数据集从一个系统迁移到另一个系统 在这种情况下 这就像使用RowMapper实现在传递给查询之前从查询构建对象ItemWriter The ItemWriter称为save我的 DAO 上的
  • JVM:是否可以操作帧堆栈?

    假设我需要执行N同一线程中的任务 这些任务有时可能需要来自外部存储的一些值 我事先不知道哪个任务可能需要这样的值以及何时 获取速度要快得多M价值观是一次性的而不是相同的M值在M查询外部存储 注意我不能指望任务本身进行合作 它们只不过是 ja
  • 如何在Java中正确删除数组[重复]

    这个问题在这里已经有答案了 我刚接触 Java 4 天 从我搜索过的教程来看 讲师们花费了大量精力来解释如何分配二维数组 例如 如下所示 Foo fooArray new Foo 2 3 但我还没有找到任何解释如何删除它们的信息 从内存的情
  • 挂钩 Eclipse 构建过程吗?

    我希望在 Eclipse 中按下构建按钮时能够运行一个简单的 Java 程序 目前 当我单击 构建 时 它会运行一些 JRebel 日志记录代码 我有一个程序可以解析 JRebel 日志文件并将统计信息存储在数据库中 是否可以编写一个插件或
  • Java的-XX:+UseMembar参数是什么

    我在各种地方 论坛等 看到这个参数 并且常见的答案是它有助于高并发服务器 尽管如此 我还是找不到 sun 的官方文档来解释它的作用 另外 它是Java 6中添加的还是Java 5中存在的 顺便说一句 许多热点虚拟机参数的好地方是这一页 ht
  • Hibernate 和可序列化实体

    有谁知道是否有一个框架能够从实体类中剥离 Hibernate 集合以使它们可序列化 我查看了 BeanLib 但它似乎只进行实体的深层复制 而不允许我为实体类中的集合类型指定实现映射 BeanLib 目前不适用于 Hibernate 3 5

随机推荐