JUL 使用手册【原创·个人私用】

首先一问:我们为什么需要日志系统?

我们之前一直都在使用System.out.println来打印信息,但是,如果项目中存在大量的控制台输出语句,会显得很凌乱,而且日志的粒度是不够细的,假如我们现在希望,项目只在debug的情况下打印某些日志,而在实际运行时不打印日志,采用直接输出的方式就很难实现了,因此我们需要使用日志框架来规范化日志输出。

Logger 是 JDK 自带的 日志框架,我觉得是挺方便的,能把这个学会,其实就已经很牛逼了 ~ 切记:它又被称为 JUL(Java Util Logging)

public class Main {
    public static void main(String[] args) {
      	// 首先获取日志打印器
        Logger logger = Logger.getLogger(Main.class.getName());
      	// 调用info来输出一个普通的信息,直接填写字符串即可
        logger.info("我是普通的日志");
    }
}

JDK 自带的日志

日志分为7个级别,详细信息我们可以在Level类中查看:

  • SEVERE(最高级别):用于表示严重错误,表示程序遇到了无法继续执行的致命错误。
  • WARNING:用于表示警告信息,表示程序遇到了一些可能会导致问题的情况,但不会影响程序的正常执行。
  • INFO(默认级别):用于表示常规消息,表示程序的正常运行状态或重要的操作。
  • CONFIG:用于表示配置信息,表示程序的配置项或设置。
  • FINE:用于表示详细信息,比INFO级别更详细,用于调试和追踪程序的执行过程。
  • FINER:用于表示更详细的信息,比FINE级别更详细,通常用于更详细的调试和追踪。
  • FINEST(最低级别):用于表示最详细的信息,提供程序执行过程中的所有细节,通常用于非常详细的调试和追踪。

我们之前通过info方法直接输出的结果就是使用的默认级别的日志,我们可以通过log方法来设定该条日志的输出级别:

public static void main(String[] args) {
    Logger logger = Logger.getLogger(Main.class.getName());
    logger.log(Level.SEVERE, "严重的错误", new IOException("我就是错误"));
    logger.log(Level.WARNING, "警告的内容");
    logger.log(Level.INFO, "普通的信息");
    logger.log(Level.CONFIG, "级别低于普通信息");
}

我们发现,级别低于默认级别的日志信息,无法输出到控制台,我们可以通过设置来修改日志的打印级别:

修改日志的打印级别

public static void main(String[] args) {
    Logger logger = Logger.getLogger(Main.class.getName());

    // 修改日志级别
    // 意思是 可以打印的信息级别 最低是 CONFIG
    logger.setLevel(Level.CONFIG);
    // 还可以设置 不使用父日志处理器
    // 父日志处理器的 日志级别是 INFO
    logger.setUseParentHandlers(false);
    // 以使用自定义的日志处理器,来决定能否对某条信息 进行输出
    // 这里是新建了 控制台处理器,是直接把处理后的信息直接输出到 控制台上的
    ConsoleHandler handler = new ConsoleHandler();
    handler.setLevel(Level.INFO);
    // 当你不适用 父日志处理器之后,自定义处理器是可以添加多个的
    // 然后 我们要输出的每条信息,它会按照 添加处理器的顺序 进行判断
    // 如果 第一个处理器可以处理,那么就轮不到 第二个处理器去处理!就是这样的规则!
    logger.addHandler(handler);
    
    // 添加输出到本地文件,它就会将输出到 test.log 中去
    FileHandler fileHandler = new FileHandler("test.log");
    fileHandler.setLevel(Level.CONFIG);
    logger.addHandler(fileHandler);
    // 由此,我们会发现 只要是 CONFIG 级别的信息,就都会被输出到 test.log 中去

    // 用 logger.log 进行不同级别的 信息输出!
    logger.log(Level.SEVERE, "严重的错误", new IOException("我就是错误"));
    logger.log(Level.WARNING, "警告的内容");
    logger.log(Level.INFO, "普通的信息");
    logger.log(Level.CONFIG, "级别低于普通信息");
}

修改打印(输出)格式

public static void main(String[] args) throws IOException {
    Logger logger = Logger.getLogger(Main.class.getName());
    logger.setUseParentHandlers(false);

    // 为了让颜色变回普通的颜色,通过代码块在初始化时将输出流设定为 System.out
    ConsoleHandler handler = new ConsoleHandler(){{
        setOutputStream(System.out);
    }};
    
    // 以创建匿名内部类的方式去实现自定义的格式
    handler.setFormatter(new Formatter() {
        @Override
        public String format(LogRecord record) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            String time = format.format(new Date(record.getMillis()));  //格式化日志时间
            String level = record.getLevel().getName();  // 获取日志级别名称
            // String level = record.getLevel().getLocalizedName();   // 获取本地化名称(语言跟随系统)
            String thread = String.format("%10s", Thread.currentThread().getName());  //线程名称(做了格式化处理,留出10格空间)
            long threadID = record.getThreadID();   //线程ID
            String className = String.format("%-20s", record.getSourceClassName());  //发送日志的类名
            String msg = record.getMessage();   //日志消息

          // \033[33m 作为颜色代码,30~37都有对应的颜色,38是没有颜色,IDEA能显示,但是某些地方可能不支持
            return "\033[38m" + time + "  \033[33m" + level + " \033[35m" + threadID
                    + "\033[38m --- [" + thread + "] \033[36m" + className + "\033[38m : " + msg + "\n";
        }
    });
    
    logger.addHandler(handler);

    logger.info("我是测试消息1...");
    logger.log(Level.INFO, "我是测试消息2...");
    logger.log(Level.WARNING, "我是测试消息3...");
}

设置信息过滤器

// 由于 SetFilter() 的参数 是接收只有 一个方法的
// 内容只要包含 "普通" 我们就肯定会过滤掉!
logger.setFilter(record -> !record.getMessage().contains("普通"));

读取 Properties 配置文件设置日志

读取配置文件来指定 输出格式

public class TestFormatter extends Formatter {
    @Override
    public String format(LogRecord record) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String time = format.format(new Date(record.getMillis()));  //格式化日志时间
        return time + " : " + record.getMessage() + "\n";
    }
}
java.util.logging.ConsoleHandler.formatter = com.test.TestFormatter

logging.properties

# RootLogger 的默认处理器为
handlers= java.util.logging.ConsoleHandler
# RootLogger 的默认的日志级别
.level= CONFIG

# 指定默认日志级别
java.util.logging.ConsoleHandler.level = ALL
# 指定默认日志消息格式
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# 指定默认的字符集
java.util.logging.ConsoleHandler.encoding = UTF-8
public static void main(String[] args) throws IOException {
    //获取日志管理器
    LogManager manager = LogManager.getLogManager();
    //读取我们自己的配置文件
    manager.readConfiguration(new FileInputStream("logging.properties"));
    //再获取日志打印器
    Logger logger = Logger.getLogger(Main.class.getName());
    logger.log(Level.CONFIG, "我是一条日志信息");   //通过自定义配置文件,我们发现默认级别不再是INFO了
}

Lombok 快速开启日志(重点)

@Log
public class Main {
    public static void main(String[] args) {
        System.out.println("自动生成的Logger名称:"+log.getName());
        log.info("我是日志信息");
    }
}

只需要添加一个@Log注解即可,添加后,我们可以直接使用一个静态变量log,而它就是自动生成的Logger。我们也可以手动指定名称:

@Log(topic = "打工是不可能打工的")
public class Main {
    public static void main(String[] args) {
        System.out.println("自动生成的Logger名称:"+log.getName());
        log.info("我是日志信息");
    }
}

MyBatis 使用自定义 Logger 日志

  1. 创建一个实现了org.apache.ibatis.logging.Log接口的类,用于将MyBatis的日志输出到JDK自带的Logger中。例如,可以创建一个名为JdkLogger的类。
import java.util.logging.Level;
import java.util.logging.Logger;

public class JdkLogger implements org.apache.ibatis.logging.Log {
    private Logger logger;

    public JdkLogger(String clazz) {
        logger = Logger.getLogger(clazz);
    }

    @Override
    public boolean isDebugEnabled() {
        return logger.isLoggable(Level.FINE);
    }

    @Override
    public void error(String s, Throwable e) {
        logger.log(Level.SEVERE, s, e);
    }

    @Override
    public void error(String s) {
        logger.log(Level.SEVERE, s);
    }

    @Override
    public void debug(String s) {
        logger.log(Level.FINE, s);
    }

    @Override
    public void trace(String s) {
        logger.log(Level.FINER, s);
    }

    @Override
    public void warn(String s) {
        logger.log(Level.WARNING, s);
    }
}
  1. 在MyBatis的配置文件中,配置使用JdkLogger作为日志实现。
<configuration>
    <!-- 其他配置项 -->
    <settings>
        <setting name="logImpl" value="top.muquanyu.mybatis.JdkLogger"/>
    </settings>
</configuration>

在上述配置中,logImpl设置为top.muquanyu.mybatis.JdkLogger,即使用我们自定义的JdkLogger作为日志实现。

这样配置后,MyBatis的日志将会通过JDK自带的Logger进行输出。你可以根据需要对JdkLogger进行扩展,以满足你的日志记录需求。

MyBatis 使用 STDOUT_LOGGING

STDOUT_LOGGING表示直接使用标准输出将日志信息打印到控制台

<configuration>
    <!-- 其他配置项 -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
</configuration>
public class TestMain {

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before(){
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(new FileInputStream("mybatis-config.xml"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test(){
        try(SqlSession sqlSession = sqlSessionFactory.openSession(true)){
            TestMapper mapper = sqlSession.getMapper(TestMapper.class);
            System.out.println(mapper.getStudentBySidAndSex(1, "男"));
            System.out.println(mapper.getStudentBySidAndSex(1, "男"));
        }
    }
}

MyBatis 使用 JUL

<setting name="logImpl" value="JDK_LOGGING" />

将其配置为JDK_LOGGING表示使用JUL进行日志打印,因为Mybatis的日志级别都比较低,因此我们需要设置一下logging.properties默认的日志级别:

handlers= java.util.logging.ConsoleHandler
.level= ALL
java.util.logging.ConsoleHandler.level = ALL
@Log
public class TestMain {

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before(){
        try {
            sqlSessionFactory = new SqlSessionFactoryBuilder()
                    .build(new FileInputStream("mybatis-config.xml"));
            LogManager manager = LogManager.getLogManager();
            manager.readConfiguration(new FileInputStream("logging.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test(){
        try(SqlSession sqlSession = sqlSessionFactory.openSession(true)){
            TestMapper mapper = sqlSession.getMapper(TestMapper.class);
            log.info(mapper.getStudentBySidAndSex(1, "男").toString());
            log.info(mapper.getStudentBySidAndSex(1, "男").toString());
        }
    }
}
posted @ 2024-01-13 08:58  小哞^同^学的技术博客  阅读(14)  评论(0编辑  收藏  举报