java日志:一、JUL使用

本文详细介绍了Java原生日志框架JUL的基本概念、使用方法及配置过程。包括日志级别设置、自定义配置文件、日志记录器的父子关系等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java日志:一、JUL使用

1 介绍

JUL全称java util Logging,是java原生的日志框架,使用时不需要引入三方类库,相对其他日志框架使用方便。

2 架构介绍

Application->Logger->Handler->Outside World

Loggers:被称为记录器,应用程序通过获取Logger对象,调用其API来发布日志信息。Logger通常是应用程序访问日志系统的入口程序。
Appenders:也被称为Handlers,每个Logger都会关联一组Handlers,Logger会将日志交给关联Handlers处理,由Handlers负责将日志做记录。Handlers在此是一个抽象,其具体的实现决定了日志记录的位置可以是控制台、文件、网络上的其他日志服务或操作系统日志等。
Layouts:也被称为Formatters,它负责对日志事件中的数据进行转换和格式化。Layouts决定了数据在一条日志记录中的最终形式。
Level:每条日志消息都有一个关联的日志级别。该级别粗略知道了日志消息的重要性和紧迫,可以将Level和Loggers,Appenders做关联以便于过滤消息。
Filter:过滤器,根据需要定制哪些信息会被记录,哪些信息会被放过。

3 简单使用

package com.base6;
import java.util.logging.Level;
import java.util.logging.Logger;

public class JUL {
    public static void main(String[] args) {
        JUL j=new JUL();
        Class<? extends JUL> c=j.getClass();
        System.out.println(c.getName());
        //1.获取日志记录器对象
        Logger logger=Logger.getLogger(c.getName());
        //2.日志记录输出
        logger.info("你好吗");
        //通用方法进行日志记录
        logger.log(Level.INFO,"我很好");
        //通过占位符方式,输出变量值
        String name ="xiaoxu";
        Integer age = 34;
        logger.log(Level.WARNING,"用户信息:{0},{1}",new Object[]{name,age});
    }
}

在这里插入图片描述
4 日志级别

package com.base6;
import java.util.logging.Level;
import java.util.logging.Logger;

public class JUL {
    public static void main(String[] args) {
        JUL j=new JUL();
        Class<? extends JUL> c=j.getClass();
        System.out.println(c.getName());
        //1.获取日志记录器对象
        Logger logger=Logger.getLogger(c.getName());
        logger.severe("severe");
        logger.warning("warning");
        logger.info("info");
        logger.config("config");
        logger.fine("fine");
        logger.finer("finer");
        logger.finest("finest");
    }
}

在这里插入图片描述
jul默认的日志级别是info,低于该级别的不会输出。

5 自定义配置日志级别

配置文件日志打印时,需要注意,文件路径要存在,否则抛出NoSuchFileException
在当前路径下,新建一个文件夹logs,里面放置一个空的jul1.log文件
在这里插入图片描述

package com.base6;
import java.io.File;
import java.io.IOException;
import java.util.logging.*;

public class JUL {
    public static void main(String[] args) throws IOException {
        JUL j=new JUL();
        Class<? extends JUL> c=j.getClass();
        System.out.println(c.getName());
        //1.获取日志记录器对象
        Logger logger=Logger.getLogger(c.getName());

        //关闭系统默认配置
        logger.setUseParentHandlers(false);

        //自定义配置日志级别
        //创建ConsoleHandler  控制台输出
        ConsoleHandler consoleHandler=new ConsoleHandler();

        //创建简单格式转换对象
        SimpleFormatter simpleFormatter=new SimpleFormatter();

        //进行关联
        consoleHandler.setFormatter(simpleFormatter);
        logger.addHandler(consoleHandler);

        //配置日志级别
        logger.setLevel(Level.WARNING);
        consoleHandler.setLevel(Level.WARNING);

        //获取当前文件路径
        File f=new File("");
        System.out.println(f.getAbsolutePath());
        System.out.println(System.getProperty("user.dir"));

        //场景FileHandler 文件输出
        FileHandler fileHandler=new FileHandler("./logs/jul1.log");
        //进行关联
        fileHandler.setFormatter(simpleFormatter);
        logger.addHandler(fileHandler);

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

在这里插入图片描述
多次执行也只会有一次的记录:
在这里插入图片描述
6 Logger对象父子关系
在这里插入图片描述
在这里插入图片描述

package com.base6;
import java.io.File;
import java.io.IOException;
import java.util.logging.*;

public class JUL {
    public static void main(String[] args) throws IOException {
        JUL j=new JUL();
        Class<? extends JUL> c=j.getClass();
        //父子关系类似包结构,比如这里logger1是com.base6,logger2是com,子包会默认继承父包
        //没有定义父包,比如这里的com,就默认继承 RootLogger   
        Logger logger1=Logger.getLogger(c.getName());
        Logger logger2=Logger.getLogger("com");

        //所有日志记录器的顶级父元素:LogManager$RootLogger,name:""
        System.out.println(logger1.getParent()==logger2);
        System.out.println("logger2 Parent:"+logger2.getParent()+",name:"+logger2.getParent().getName());
        //关闭默认配置
        logger2.setUseParentHandlers(false);
        //设置logger2日志级别
        ConsoleHandler consoleHandler=new ConsoleHandler();
        SimpleFormatter simpleFormatter=new SimpleFormatter();
        consoleHandler.setFormatter(simpleFormatter);
        logger2.addHandler(consoleHandler);

        //配置日志具体级别
        logger2.setLevel(Level.WARNING);
        consoleHandler.setLevel(Level.WARNING);

        logger1.severe("severe");
        logger1.warning("warning");
        logger1.info("info");
        logger1.config("config");
        logger1.fine("fine");
        logger1.finer("finer");
        logger1.finest("finest");
    }
}

7 JUL配置文件

查看getLogger源码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
进入getLogManager:
在这里插入图片描述

final void ensureLogManagerInitialized() {
    final LogManager owner = this;
    if (initializationDone || owner != manager) {
        // we don't want to do this twice, and we don't want to do
        // this on private manager instances.
        return;
    }

    // Maybe another thread has called ensureLogManagerInitialized()
    // before us and is still executing it. If so we will block until
    // the log manager has finished initialized, then acquire the monitor,
    // notice that initializationDone is now true and return.
    // Otherwise - we have come here first! We will acquire the monitor,
    // see that initializationDone is still false, and perform the
    // initialization.
    //
    synchronized(this) {
        // If initializedCalled is true it means that we're already in
        // the process of initializing the LogManager in this thread.
        // There has been a recursive call to ensureLogManagerInitialized().
        final boolean isRecursiveInitialization = (initializedCalled == true);

        assert initializedCalled || !initializationDone
                : "Initialization can't be done if initialized has not been called!";

        if (isRecursiveInitialization || initializationDone) {
            // If isRecursiveInitialization is true it means that we're
            // already in the process of initializing the LogManager in
            // this thread. There has been a recursive call to
            // ensureLogManagerInitialized(). We should not proceed as
            // it would lead to infinite recursion.
            //
            // If initializationDone is true then it means the manager
            // has finished initializing; just return: we're done.
            return;
        }
        // Calling addLogger below will in turn call requiresDefaultLogger()
        // which will call ensureLogManagerInitialized().
        // We use initializedCalled to break the recursion.
        initializedCalled = true;
        try {
            AccessController.doPrivileged(new PrivilegedAction<Object>() {
                @Override
                public Object run() {
                    assert rootLogger == null;
                    assert initializedCalled && !initializationDone;

                    // Read configuration.
                    owner.readPrimordialConfiguration();

                    // Create and retain Logger for the root of the namespace.
                    owner.rootLogger = owner.new RootLogger();
                    owner.addLogger(owner.rootLogger);
                    if (!owner.rootLogger.isLevelInitialized()) {
                        owner.rootLogger.setLevel(defaultLevel);
                    }

                    // Adding the global Logger.
                    // Do not call Logger.getGlobal() here as this might trigger
                    // subtle inter-dependency issues.
                    @SuppressWarnings("deprecation")
                    final Logger global = Logger.global;

                    // Make sure the global logger will be registered in the
                    // global manager
                    owner.addLogger(global);
                    return null;
                }
            });
        } finally {
            initializationDone = true;
        }
    }
}

在这里插入图片描述
在这里插入图片描述
打上断点,deBug刚才的代码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击下一步开始调试:
在这里插入图片描述
首先进去加载,当前有无配置类(这里没有):
在这里插入图片描述
然后判断有无自定义的配置文件(这里也没有):
在这里插入图片描述
没有,就读取java.home(也就是JDK安装的路径),找到jre,再找到lib目录:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

############################################################
#  	Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.  
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#  	Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler 
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
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

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format 
# to print one-line log message like this:
#     <level>: <log message> [<date/time>]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE

复制一份放在resources目录下:
在这里插入图片描述
自定义修改如下:

handlers= java.util.logging.ConsoleHandler

.level= WARNING

# default file output is in user's home directory.
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

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = WARNING
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

加载自定义配置文件:

package com.base6;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.*;

public class JUL {
    @Test
    public void testLogProperties() throws IOException {
        JUL j=new JUL();
        Class<? extends JUL> c=j.getClass();
        //读取配置文件,通过类加载器
        InputStream i=JUL.class.getClassLoader().getResourceAsStream("logging.properties");
        //创建LogManager
        LogManager logManager=LogManager.getLogManager();
        //通过LogManager加载配置文件
        logManager.readConfiguration(i);

        //创建日志记录器
        Logger l=Logger.getLogger(c.getName());

        l.severe("severe");
        l.warning("warning");
        l.info("info");
        l.config("config");
        l.fine("fine");
        l.finer("finer");
        l.finest("finest");
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
再次执行,效果如下:
在这里插入图片描述
在这里插入图片描述

#RootLogger 顶级父元素指定的默认处理器为:ConsoleHandler
handlers= java.util.logging.ConsoleHandler

#RootLogger  顶级父元素默认的日志级别为:WARNING
.level= WARNING

java.util.logging.FileHandler.pattern = ./logs/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

#向控制台输出的 handler对象
#指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = WARNING
#指定handler对象的日志消息格式对象
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

全局搜索ConsoleHandler的代码:ctrl+shift+A
在这里插入图片描述
在这里插入图片描述
修改字符集如下:

#向控制台输出的 handler对象
#指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = WARNING
#指定handler对象的日志消息格式对象
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
#指定handler对象的字符集
java.util.logging.ConsoleHandler.encoding = UTF-8

在这里插入图片描述
在这里插入图片描述

#指定日志消息格式
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

在这里插入图片描述
日志文件的追加:

#RootLogger 顶级父元素指定的默认处理器为:ConsoleHandler
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler

#RootLogger  顶级父元素默认的日志级别为:WARNING
.level= WARNING

#向日志文件输出的handler对象
#指定日志文件路径
java.util.logging.FileHandler.pattern = ./logs/java%u.log
#指定文件内容大小
java.util.logging.FileHandler.limit = 50000
#指定日志文件数量
java.util.logging.FileHandler.count = 1
#指定handler对象日志消息格式对象
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
#指定以追加方式添加日志内容
java.util.logging.FileHandler.append = true

#向控制台输出的 handler对象
#指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = WARNING
#指定handler对象的日志消息格式对象
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
#指定handler对象的字符集
java.util.logging.ConsoleHandler.encoding = UTF-8
#指定日志消息格式
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

重新执行:
在这里插入图片描述
8 自定义Loggers

#RootLogger 顶级父元素指定的默认处理器为:ConsoleHandler
handlers= java.util.logging.ConsoleHandler,java.util.logging.FileHandler

#RootLogger  顶级父元素默认的日志级别为:WARNING
.level= WARNING

#自定义Logger使用:包名+handlers
com.base6.handlers = java.util.logging.ConsoleHandler
com.base6.level = SEVERE

#关闭默认配置
com.base6.useParentHandlers = false


#向日志文件输出的handler对象
#指定日志文件路径
java.util.logging.FileHandler.pattern = ./logs/java%u.log
#指定文件内容大小
java.util.logging.FileHandler.limit = 50000
#指定日志文件数量
java.util.logging.FileHandler.count = 1
#指定handler对象日志消息格式对象
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
#java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
#指定以追加方式添加日志内容
java.util.logging.FileHandler.append = true

#向控制台输出的 handler对象
#指定 handler 对象的日志级别
java.util.logging.ConsoleHandler.level = WARNING
#指定handler对象的日志消息格式对象
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
#指定handler对象的字符集
java.util.logging.ConsoleHandler.encoding = UTF-8
#指定日志消息格式
java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"
package com.base6;
import org.testng.annotations.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.*;

public class JUL {
    @Test
    public void testLogProperties() throws IOException {
        JUL j=new JUL();
        Class<? extends JUL> c=j.getClass();
        //读取配置文件,通过类加载器
        InputStream i=JUL.class.getClassLoader().getResourceAsStream("logging.properties");
        //创建LogManager
        LogManager logManager=LogManager.getLogManager();
        //通过LogManager加载配置文件
        logManager.readConfiguration(i);

        //创建日志记录器
        Logger l=Logger.getLogger(c.getName());

        l.severe("severe");
        l.warning("warning");
        l.info("info");
        l.config("config");
        l.fine("fine");
        l.finer("finer");
        l.finest("finest");

        Logger l2=Logger.getLogger("test");
        l2.severe("severe test");
        l2.warning("warning test");
        l2.info("info test");
    }
}

在这里插入图片描述
9 日志原理解析

1 初始化LogManager
1.1 LogManager加载logging.properties配置
1.2 添加Logger到LogManager

2 从单例LogManager获取Logger

3 设置级别Level,并指定日志记录LogRecord

4 Filter提供了日志级别之外更细粒度的控制

5 Handler是用来处理日志输出位置

6 Formatter用来格式化LogRecord

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值