Java日志框架简介
- 一.Java日志框架历史总体概述
- 二. JUL(Java Util Logging)简介
- JUL的日志级别
- 简单的输出INFO日志的示例:
- 输出各个级别的日志信息
- Logger的父子关系
- 使用配置文件来控制日志的输出级别
一.Java日志框架历史总体概述
Java框架现在主要是分为两个大的日志门面: JCL、slf4j
日志框架的实现主要是一下这几种 JUL(java原生自带)、logback()、log4j、log4j2
历史及总体简介等我稍后了解完毕之后在进行编写,稍后再继续编写吧,先说明怎么进行使用哈>>> ^_^
二. JUL(Java Util Logging)简介
JUL是sun公司推出的jdk原生的日志框架,使用JUL无需进行导入包
JUL的日志级别
JUL的日志主要分为一下几个级别:
SEVERE(最高值)
WARNING
INFO (默认级别)
CONFIG
FINE
FINER
FINEST(最低值)
* 还有两个特殊的级别:
OFF,可用来关闭日志记录。
ALL,启用所有消息的日志记录。
简单的输出INFO日志的示例:
首先获取日志记录器对象,其实这个里面随便填啥都能使用,但是不能填写空字符串. 默认的日志输出级别即为INFO级别,低于INFO级别的都不会进行输出
@Test
public void test1() {
// 获取日志记录器对象
Logger logger = Logger.getLogger("com.huqi.JULTest");
// 日志记录输出
logger.info("hello jul");
// 通用方法进行日志记录
logger.log(Level.INFO, "info msg");
System.out.printf("-------------------------------------------------------------");
String name = "胡琦";
Integer age = 24;
// 自带的占位符转换
logger.log(Level.INFO, "name = {0}, age = {1}", new Object[]{name, age});
}
输出各个级别的日志信息
@Test
public void test2() throws IOException {
// 获取日志记录器对象
Logger logger = Logger.getLogger("com.huqi.JULTest");
// 关闭jul默认的日志级别
logger.setUseParentHandlers(false);
// 一个日志格式处理器
SimpleFormatter simpleFormatter = new SimpleFormatter();
// 控制台处理器, 输出信息控制台
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setFormatter(simpleFormatter);
// 文件处理器, 输出到文件去
FileHandler fileHandler = new FileHandler("D:/test.log");
fileHandler.setFormatter(simpleFormatter);
// 将处理器添加到日志记录器对象中
logger.addHandler(consoleHandler);
logger.addHandler(fileHandler);
// 设置自己需要的细粒度,全部开启
logger.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
fileHandler.setLevel(Level.ALL);
// 现在可以输出所有的日志级别了
logger.fine("fine");
logger.finer("fine");
logger.finest("fine");
logger.info("fine");
logger.warning("fine");
logger.severe("fine");
logger.config("fine");
}
控制台打印的信息输出在D盘的日志文件
Logger的父子关系
/**
* logger 的父子关系
*/
@Test
public void test3() {
//分别获取父子包的两个日志对象
Logger logger1 = Logger.getLogger("com.huqi");
Logger logger2 = Logger.getLogger("com");
// true
System.out.println(logger1.getParent() == logger2);
// 获取日志记录器的顶级父元素 LogManager$RootLogger name = ""
// logger2 Parent: java.util.logging.LogManager$RootLogger@deb6432 ,name :
System.out.println("logger2 Parent: " + logger2.getParent() +
" ,name : " + logger2.getParent().getName());
// 关闭默认日志级别配置
logger2.setUseParentHandlers(false);
// 设置处理器
ConsoleHandler consoleHandler = new ConsoleHandler();
SimpleFormatter simpleFormatter = new SimpleFormatter();
consoleHandler.setFormatter(simpleFormatter);
logger2.addHandler(consoleHandler);
// 设置了父的日志级别全开
logger2.setLevel(Level.ALL);
consoleHandler.setLevel(Level.ALL);
// logger1继承了logger2的日志设置,可以进行输出所有的日志级别
// 现在可以输出所有的日志级别了
logger1.fine("fine");
logger1.finer("fine");
logger1.finest("fine");
logger1.info("fine");
logger1.warning("fine");
logger1.severe("fine");
logger1.config("fine");
}
使用配置文件来控制日志的输出级别
/**
* 加载自定义配置文件
*/
@Test
public void test4() throws IOException {
// 读取配置文件, 通过类加载器
InputStream resource = JULTest.class.getClassLoader().getResourceAsStream("logging.properties");
// 创建LogManager
LogManager logManager = LogManager.getLogManager();
// 通过LogManager配置文件
logManager.readConfiguration(resource);
// 创建日志记录器
Logger logger = Logger.getLogger("com.huqi");
logger.fine("fine");
logger.finer("fine");
logger.finest("fine");
logger.info("fine");
logger.warning("fine");
logger.severe("fine");
logger.config("fine");
}
logging.properties
# 默认的处理器: 控制台输出
handlers =java.util.logging.ConsoleHandler
# 默认的日志级别是info
.level = ALL
# 格式处理器
# 默认的处理器: 控制台输出 文件输出
handlers =java.util.logging.ConsoleHandler,java.util.logging.FileHandler
# 默认的日志级别是info
.level = ALL
java.util.logging.ConsoleHandler.formatter = org.springframework.boot.logging.java.SimpleFormatter
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.FileHandler.pattern = D://java%u.Log
java.util.logging.FileHandler.limit = 50000
java.utiL.logging.FiLeHandler.count = 1
java.utiL.logging.FileHandler.formatter = java.util.logging.XMLFormatter
org.hibernate.validator.internal.util.Version.level = WARNING
org.apache.coyote.http11.Http11NioProtocol.level = WARNING
org.apache.tomcat.util.net.NioSelectorPool.level = WARNING
org.apache.catalina.startup.DigesterFactory.level = SEVERE
org.apache.catalina.util.LifecycleBase.level = SEVERE
org.eclipse.jetty.util.component.AbstractLifeCycle.level = SEVERE
具体如何使用日志框架以及如何包装日志的工具类,可看参考此github链接的日志工具类,使用的是slfj+logback进行日志的输出.
https://gitee.com/huqidake/spring-boot-demo
可参考如下的代码进行配置,使用那个的是xml文件,同样也可以使用一个yml文件操作.
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
<property name="LOG_HOME" value="/home" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<!-- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%logger{50}] - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/TestWeb.log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
package com.huqi.log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.MessageFormat;
/**
* 日志工具类
* @author 胡琦
* @date 2021-07-24 星期六 16:03
*/
public class LoggerUtil {
private final static Logger LOGGER = LoggerFactory.getLogger(LoggerUtil.class);
public static void info(Logger logger, String template, String... args) {
if (logger.isInfoEnabled()) {
logger.info(joint(template, args));
}
}
public static void warn(Logger logger, String template, String... args) {
logger.warn(joint(template, args));
}
public static void warn(Throwable throwable, Logger logger, String template, String... args) {
logger.warn(joint(template, args), throwable);
}
public static void error(Logger logger, String template, String... args) {
logger.error(joint(template, args));
}
public static void error(Throwable throwable, Logger logger, String template, String... args) {
logger.error(joint(template, args), throwable);
}
/**
* 解析占位符,返回拼接好的字符串
*
*
* 我自己的实现方式
*
* // {
* private static final char PREFIX = 123;
* // }
* private static final char SUFFIX = 125;
*
* private static Set numSet = new HashSet(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
*
* private static String joint(String msg, String... msgs) {
* if (StringUtils.isBlank(msg) || msg == null || msgs.length == 0) {
* return msg;
* }
* final char[] chars = msg.toCharArray();
* StringBuilder stringBuilder = new StringBuilder();
* try {
* for (int i = 0; i < chars.length;) {
* char c = chars[i];
* if (c == PREFIX && chars[i+2] == SUFFIX) {
* Integer index = Integer.valueOf(Character.toString(chars[i + 1]));
* boolean contains = numSet.contains(index);
* if (contains) {
* stringBuilder.append(msgs[index]);
* }
* i = i+2;
* continue;
* }
* if (c == SUFFIX) {
* i++;
* continue;
* }
* stringBuilder.append(c);
* i++;
* }
* }catch (Exception e) {
* LOGGER.error("LoggerUtils joint error");
* return msg;
* }
* return stringBuilder.toString();
* }
*
*
* @param msg 模板参数 示例
* test1 = {0}, test2 = {1}
* 填充的参数从0开始,数字和花括号之间不能有空格
* @param args 需要填充的参数,
* @return
*/
private static String joint(String msg, String... args) {
try {
return MessageFormat.format(msg, args);
} catch (Exception e) {
LOGGER.error("日志打印异常", e);
}
return null;
}
}