当前位置: 首页 > news >正文

网站建设 排名下拉wordpress新建栏目

网站建设 排名下拉,wordpress新建栏目,湖南网络广告策划推广,网站集约化建设难点1 日志技术概述 1.1 什么是日志技术 ​ 日志技术是一种记录和存储应用程序运行时信息的技术。它可以捕获应用程序的状态、事件、错误和警告等信息#xff0c;并将其保存到日志文件或其他存储介质中。日志技术可以帮助开发人员和运维团队了解应用程序的运行情况#xff0c;进…1 日志技术概述 1.1 什么是日志技术 ​ 日志技术是一种记录和存储应用程序运行时信息的技术。它可以捕获应用程序的状态、事件、错误和警告等信息并将其保存到日志文件或其他存储介质中。日志技术可以帮助开发人员和运维团队了解应用程序的运行情况进行故障排查、性能优化、安全监控和运营分析等工作。 以下是日志技术的一些关键概念和组成部分 日志级别日志级别用于标识日志的重要性和严重程度。常见的日志级别包括DEBUG、INFO、WARN、ERROR和FATAL等。开发人员可以根据需要选择适当的日志级别来记录不同类型的信息。日志格式日志格式定义了日志记录的结构和内容。它通常包括时间戳、日志级别、日志消息和其他相关信息。开发人员可以根据需求自定义日志格式以便更好地理解和分析日志。日志输出日志输出指定了日志记录的目标位置。常见的日志输出包括控制台输出、文件输出和远程日志服务器等。开发人员可以根据需要配置多个日志输出以便在不同环境下进行日志记录和分析。日志框架日志框架是一种用于记录和管理日志的软件库或工具。它提供了一组API和配置选项使开发人员能够方便地生成和处理日志。常见的日志框架包括Log4j、Logback和java.util.logging等。日志分析日志分析是指对大量日志数据进行处理和分析以提取有用的信息和洞察。日志分析工具可以帮助开发人员和运维团队发现潜在的问题、优化性能、监控安全和了解用户行为等。 1.2 我们接触过的日志 我们之前都是使用输出语句System.out.println打印日志的有什么问题呢 日志打印在控制台当我们关闭控制台以后日志就不见了不能方便的将日志记录到其他的位置如文件、数据库等想要取消或修改日志需要修改源代码 1.3 引入日志技术的作用 引入日志技术是为了更好地管理和跟踪应用程序的运行情况。以下是一些使用日志技术的好处 故障排查和调试当应用程序出现问题时日志可以提供有关错误和异常的详细信息帮助开发人员快速定位和解决问题。通过查看日志您可以了解应用程序在特定时间点的状态、执行路径和输入输出数据。监控和性能优化日志可以记录应用程序的性能指标、资源使用情况和系统状态。通过分析日志您可以识别性能瓶颈、优化代码和资源分配以提高应用程序的性能和可伸缩性。安全和合规性日志可以记录应用程序的安全事件、用户操作和敏感数据访问。这些日志可以用于监测潜在的安全威胁、追踪用户活动和满足合规性要求。运营和维护日志可以提供应用程序的运行情况、错误和警告信息。通过监视日志您可以及时发现并解决潜在的问题确保应用程序的稳定运行。分析和洞察通过对日志进行分析您可以了解应用程序的使用情况、用户行为和业务趋势。这些洞察可以帮助您做出更好的业务决策、改进产品功能和提供更好的用户体验。 ​ 引入日志技术可以帮助开发人员和运维团队更好地理解和管理应用程序的运行情况提高开发效率、减少故障修复时间并提供更好的用户体验。 1.4 日志技术的体系 日志技术的体系结构 日志门面接口、规则JCLJakarta Commons Logging 由Apache Jakarta提供、SLF4JSimple Logging Facade for Java、Log4j2 API日志实现框架JULjava util logging、Logback、Log4j、Log4j2-core 日志门面是设计日志框架的一套标准所有的日志框架都需要实现这些接口 Log4j实现的是JCL Logbook实现的是SLF4j Log4J2-core实现的是Log4j2 API 说明 ​ 因为对JCL接口不满意所以有人就搞出来了SLF4J因为对Log4j的性能不满意所以就出现了Logback ​ Logback是基于SLF4J的日志规范实现的日志框架 日志框架出现的历史顺序 Log4j -- JUL -- JCL - Slf4j -- Loback -- Log4j2 2 JUL ​ JULJava Util Logging是Java平台自带原生的日志框架。它是Java标准库的一部分不需要额外的依赖。JUL提供了一套简单的日志记录API可以用于在应用程序中记录日志信息。 2.1 JUL主要组件 JUL的主要组件包括 Logger日志记录器用于记录日志信息的主要组件。可以通过Logger.getLogger()方法获取Logger实例。Logger通常是应用程序访问日志系统的入口程序。Handler处理器也称为Appenders用于处理日志记录的输出。每个Loigger都会关联一组HandlersLogger会将日志交给关联的Handlers进行处理由Handler负责将日志做记录。可以将日志记录发送到不同的目标如控制台、文件、数据库等。Handler是一个抽象具体需要将日志发送到哪里还需要具体的实现Formatter格式化器也称为Layout用于格式化日志记录的输出。可以定义日志记录的格式包括日期、时间、日志级别、类名等信息。Level日志级别用于控制日志记录的级别。可以设置不同的日志级别如INFO、DEBUG、WARNING、ERROR等只有达到指定级别的日志记录才会被记录。Filters过滤器根据需要定制那些消息会被记录那些消息会被放过 ​ JUL的配置文件是一个文本文件通常命名为logging.properties。可以通过修改配置文件来配置日志记录的级别、输出目标、格式等。 2.2 JUL的使用 1获取Logger实例使用 Logger.getLogger() 方法获取Logger实例传入一个唯一的名称作为参数。通常使用类的全限定名作为名称。 public static final Logger LOGGER Logger.getLogger(类名);2配置日志级别可以通过修改配置文件 logging.properties来配置日志级别。在配置文件中可以为不同的包或类设置不同的日志级别。 配置文件可以放置在以下位置之一 在应用程序的根目录下。在src/main/resources目录下对于Maven或Gradle项目。在WEB-INF/classes目录下对于Web应用程序 logging.properties # 设置根日志级别为INFO .levelINFO# 设置com.clear包的日志级别为DEBUG com.clear.levelDEBUG3使用Logger实例的不同方法记录不同级别的日志信息。 演示 import java.util.logging.Logger;public class JULTest {// 获取Logger实例public static final Logger LOGGER Logger.getLogger(com.clear.JULTest);Testpublic void test1(){LOGGER.severe(server); // 严重LOGGER.warning(warning); // 警告LOGGER.info(info); // 信息} }2.3 日志级别 记录日志信息使用Logger实例的不同方法记录不同级别的日志信息。 常用的日志级别包括 SEVERE最高级别的日志表示严重错误。WARNING警告级别的日志表示潜在的问题。INFO信息级别的日志表示一般的运行信息。默认CONFIG配置级别的日志表示配置信息。FINE细粒度的调试信息。FINER更细粒度的调试信息。FINEST最细粒度的调试信息。 LOGGER.severe(This is a severe message); LOGGER.warning(This is a warning message); LOGGER.info(This is an info message); LOGGER.config(This is a config message); LOGGER.fine(This is a fine message); LOGGER.finer(This is a finer message); LOGGER.finest(This is a finest message);此外还有两个特殊的级别 ALL启用所有消息的日志记录OFF可以用来关闭日志记录 2.4 日志配置 // 获取Logger实例 public static final Logger LOGGER Logger.getLogger(com.clear.JULTest);Test public void test2() throws IOException {// 禁用父级处理器。日志消息将不会传递给父级处理器进行处理。LOGGER.setUseParentHandlers(false);// 创建了一ConsoleHandler实例ConsoleHandler consoleHandler new ConsoleHandler();// 设置其日志格式为SimpleFormatter。ConsoleHandler用于将日志消息输出到控制台。consoleHandler.setFormatter(new SimpleFormatter());// 设置日志级别所有级别的日志消息都将被记录。consoleHandler.setLevel(Level.ALL);// 创建一个FileHandler实例// 为了简单我们将异常抛出去FileHandler fileHandler new FileHandler(D:/test/jul.log,true);fileHandler.setFormatter(new SimpleFormatter());fileHandler.setLevel(Level.WARNING);LOGGER.setLevel(Level.ALL);// 将ConsoleHandler添加到LOGGER的处理器列表中以便将日志消息发送到控制台。LOGGER.addHandler(consoleHandler);// 将FileHandler添加到LOGGER的处理器列表中以便将日志消息发送到文件中LOGGER.addHandler(fileHandler);// 日志输出LOGGER.severe(severe);LOGGER.warning(warning);LOGGER.info(info);LOGGER.config(config);LOGGER.fine(fine);LOGGER.finer(finer);LOGGER.finest(finest); }2.5 Logger之间的父子关系 ​ 在JULJava Util Logging中日志记录器Logger之间可以建立父子关系。这种父子关系是通过日志记录器的名称来确定的即建立树状结构来存储父子关系。 ​ 父子关系的建立是通过日志记录器的名称来实现的。当创建一个新的日志记录器时可以指定其父级日志记录器的名称。如果没有指定父级日志记录器的名称则默认为根日志记录器RootLogger。 ​ 默认情况下子Logger会继承父Logger的属性。 任何一个logger都是单例的名字相同的只有一个 // 获取Logger实例 public static final Logger LOGGER Logger.getLogger(com.clear.JULTest);Test public void test3() {// 任何一个logger都是单例的名字相同的只有一个Logger logger Logger.getLogger(JULTest.class.getName());System.out.println(LOGGER.hashCode()); // 4959864System.out.println(logger.hashCode()); // 4959864System.out.println(LOGGER logger); // true }所有的Logger实例都是由LoggerManager统一管理的 Test public void test4(){Logger logger Logger.getLogger(com.clear.JULTest);// todo 如果没有指定父级日志记录器的名称则默认为根日志记录器RootLoggerSystem.out.println(默认父Loggerlogger.getParent()); // 默认父Loggerjava.util.logging.LogManager$RootLogger4bae78System.out.println(默认父Logger名字logger.getParent().getName()); // 默认父Logger名字// 父Logger// todo 父子关系的建立是通过日志记录器的名称来实现的Logger pLogger Logger.getLogger(com.clear);System.out.println(建立父子关系以后);System.out.println(父Loggerlogger.getParent()); // 父Loggerjava.util.logging.Logger1764bceSystem.out.println(父Logger名字logger.getParent().getName()); // 父Logger名字com.clearSystem.out.println(父Logger的父LoggerpLogger.getParent()); // 父Logger的父Loggerjava.util.logging.LogManager$RootLogger4bae78System.out.println(父Logger的父Logger名称pLogger.getParent().getName()); // 父Logger的父Logger名称 }默认情况下子Logger会继承父Logger的属性。 // 默认情况下子Logger会继承父Logger的属性。 Test public void test5(){Logger logger Logger.getLogger(com.clear.JULTest);// 父LoggerLogger pLogger Logger.getLogger(com.clear);// 父Logger的默认日志打印级别为infopLogger.info(info);pLogger.fine(fine);logger.setLevel(Level.ALL);// todo 设置父类Logger// 禁用父级处理器pLogger.setUseParentHandlers(false);ConsoleHandler consoleHandler new ConsoleHandler();consoleHandler.setFormatter(new SimpleFormatter());consoleHandler.setLevel(Level.ALL);pLogger.addHandler(consoleHandler);// 父Logger可以打印fine级别的信息了pLogger.info(info);pLogger.fine(fine);// todo 子Logger继承了父Logger的属性也可以打印fine级别的信息了logger.info(info);logger.fine(fine); }2.6 日志格式化 ​ 在JULJava Util Logging中可以使用格式化器Formatter来定义日志消息的输出格式。格式化器可以将日志消息的各个部分如日期、级别、类名、方法名、消息内容等组合成一个字符串并指定其输出的格式。 JUL提供了两种内置的格式化器 SimpleFormatter这是默认的格式化器它将日志消息格式化为一行文本。默认格式为[日期时间] [级别] [类名] [方法名] - [消息内容]。XMLFormatter这是一个将日志消息格式化为XML格式的格式化器。它将日志消息的各个部分作为XML元素并使用属性来表示其值。 可以通过以下方式来配置日志记录器的格式化器 在代码中使用Handler.setFormatter(Formatter formatter)方法来设置格式化器。例如handler.setFormatter(new SimpleFormatter())将handler的格式化器设置为SimpleFormatter。在配置文件中使用java.util.logging.ConsoleHandler.formatter属性来设置控制台处理器的格式化器。例如java.util.logging.ConsoleHandler.formatterjava.util.logging.SimpleFormatter表示将控制台处理器的格式化器设置为SimpleFormatter。在配置文件中使用java.util.logging.FileHandler.formatter属性来设置文件处理器的格式化器。例如java.util.logging.FileHandler.formatterjava.util.logging.XMLFormatter表示将文件处理器的格式化器设置为XMLFormatter。 除了使用内置的格式化器还可以自定义格式化器来满足特定的需求。自定义格式化器需要实现java.util.logging.Formatter接口并实现其中的format(LogRecord record)方法来定义日志消息的输出格式。 通过配置日志记录器的格式化器可以灵活地控制日志消息的输出格式以满足不同的需求和标准。 2.6.1 String的format方法 String类的format方法用于创建格式化的字符串以及连接多个字符串对象。 public static String format(String format, Object... args) {return new Formatter().format(format, args).toString(); }public static String format(Locale l, String format, Object... args) {return new Formatter(l).format(format, args).toString(); }在这个方法中我们可以定义字符串模板例如 String str String.format(hello %s,world);2.6.2 常用的转换符 转换符说明举例%s字符串类型“hello”%c字符类型‘a’%b布尔类型true%d整数类型十进制88%x整数类型十六进制FF%o整数类型八进制77%f浮点类型8.888%a十六进制浮点类型FF.35AE%e指数类型9.38e5%n换行符%tx日期与时间类型x代表不同的日期与时间转换符 2.6.3 特殊符号 标志说明举例结果为正数或负数添加符合因为一般整数不会主动加符号(“%d”, 15)150数字前面补0用于对齐(“%04d”, 99)0099空格在整数之前添加指定数量的空格(“%4d”, 99)99,以,对数字进行分组常用于显示金额(“%,f”, 9999.99)9,999,990000(使用括号包含负数(“%(f”, -99.99)(99.990000) 默认情况下我们的可变参数就是按照顺序依次替换但是如果我们想重复利用可变参数的情况 我们可以采用在转换符中加 数字$,完成匹配例如 System.out.printf(%1$s %1$s %1$s,小明); // 其中1$就代表第一个参数那么2$就代表第二个参数2.6.4 日期处理 前面的 %tx 中x就代表日期转换符 标志说明举例c包括全部日期和时间信息周四 10月 21 14:30:30 GMT08:00 2023F年-月-日格式2023-7-18D年/月/日格式2023/7/18rHH:MM:SS PM格式12时制8:20:30 下午THH:MM:SS格式12时制20:20:30RHH:MM格式24时制20:20b月份本地化7月y两位的年23Y四位的年2023m月7d日18H24小时制的时20l12小时制的时8M分55S秒55s秒为单位的时间戳23144232p上午还是下午下午 我们可以使用以下三个类去进行格式化其中可能存在不支持的情况比如LocalDateTime不支持c System.out.println(tc, new Date()); System.out.println(tc, ZonedDateTime.now()); System.out.println(tF, LocalDateTime.now();2.7 配置文件 JULJava Util Logging加载配置文件的源码解读如下 首先JUL使用LogManager类来管理日志记录器和配置信息。LogManager是一个单例类通过LogManager.getLogManager()方法获取实例。 当调用LogManager.getLogManager().readConfiguration(inputStream)方法时会执行以下步骤 a. LogManager类的readConfiguration方法会创建一个新的Properties对象用于存储配置信息。b. 使用Properties对象的load方法将配置文件的内容加载到Properties对象中。这里的inputStream参数是通过getClass().getClassLoader().getResourceAsStream(logging.properties)获取的它会从类路径中读取logging.properties文件的内容。c. 加载配置文件后LogManager会根据配置信息更新日志记录器的配置。具体的配置信息包括日志级别、日志输出目标等。 如果没有指定配置文件或加载配置文件失败JUL会使用默认的配置。默认的配置包括将日志输出到控制台并使用默认的日志级别。 ​ 总结JUL加载配置文件的源码主要涉及LogManager类的readConfiguration方法该方法通过读取配置文件的内容并根据配置信息更新日志记录器的配置。 2.7.1 读取自定义配置文件 在JULJava Util Logging中加载配置文件的常规步骤如下 1创建一个名为logging.properties的文本文件该文件包含了JUL的配置信息。 2将logging.properties文件放置在类路径下通常是放在src/main/resources目录下。 3在代码中使用以下代码片段来加载配置文件 InputStream inputStream getClass().getClassLoader().getResourceAsStream(logging.properties); if (inputStream ! null) {LogManager.getLogManager().readConfiguration(inputStream); }演示 1在src/main/resources目录下创建 logging.properties 文件内容如下 # 设置根日志记录器的级别为FINE .levelFINEhandlersjava.util.logging.ConsoleHandler,java.util.logging.FileHandler # 配置控制台处理器 java.util.logging.ConsoleHandler.levelFINE java.util.logging.ConsoleHandler.formatterjava.util.logging.SimpleFormatter # 配置文件处理器 java.util.logging.FileHandler.levelFINE # 指定日志文件的路径和名称模式 java.util.logging.FileHandler.pattern%h/java%u.log # 指定日志文件的大小限制 java.util.logging.FileHandler.limit50000 # 指定日志文件的数量限制 java.util.logging.FileHandler.count1 # 指定日志消息的格式化器 java.util.logging.FileHandler.formatterjava.util.logging.XMLFormatter2编写代码读取配置文件 // 读取配置文件 Test public void readConfig() {LogManager manager LogManager.getLogManager();// 获取配置文件InputStream inputStream Thread.currentThread().getContextClassLoader().getResourceAsStream(logging.properties);// InputStream inputStream getClass().getClassLoader().getResourceAsStream(logging.properties);try {manager.readConfiguration(inputStream);} catch (IOException e) {throw new RuntimeException(e);}Logger logger Logger.getLogger(JULTest.class.getName());// 默认的日志打印级别为INFO加载我们自己的配置文件后级别为FINE// 如果能打印fine级别的日志证明加载成功logger.fine(fine); } }2.7.2 配置文件解读 # 设置根日志记录器的级别为INFO .levelINFO # 配置控制台处理器、文件处理器 handlersjava.util.logging.ConsoleHandler,java.util.logging.FileHandler # 为RootLogger根日志记录器配置handlers指定处理器的列表多个处理器之间使用逗号分隔# 配置文件处理器的相关属性 # 设置日志输出级别 java.util.logging.FileHandler.levelINFO # 指定日志文件的路径和名称模式 %h 表示用户家目录 java.util.logging.FileHandler.pattern%h/java%u.log # 指定日志文件的大小限制 java.util.logging.FileHandler.limit50000 # 指定日志文件的数量限制不能小于1 java.util.logging.FileHandler.count1 # 指定日志文件是追加写 java.util.logging.FileHandler.append # 指定日志消息的格式化器 java.util.logging.FileHandler.formatterjava.util.logging.XMLFormatter# 配置控制台处理器的相关属性 # 设置日志输出级别 java.util.logging.ConsoleHandler.levelINFO # 指定日志消息的格式化器 java.util.logging.ConsoleHandler.formatterjava.util.logging.SimpleFormatter # 指定日志消息的格式 java.util.logging.SimpleFormatter.format%4$s: %5$s [%1$tc]%n2.7.3 独立日志的配置 logging.properites 在配置文件中加入如下配置 # 设置 com.clear 日志记录器 com.clear.handlersjava.util.logging.ConsoleHandler com.clear.levelWARNING # 禁用父类的Handler com.clear.useParentHandlersfalse为了让我们自定义的日志记录器生效必须在获取Logger实例之前加载配置文件 我们可以采用静态代码块的方式实现 public class JULTest {static {LogManager manager LogManager.getLogManager();// 获取配置文件InputStream inputStream Thread.currentThread().getContextClassLoader().getResourceAsStream(logging.properties);try {manager.readConfiguration(inputStream);} catch (IOException e) {throw new RuntimeException(e);}}// 读取配置文件Testpublic void readConfig() {// 此时com.clear包下只会打印WARNING级别及以上的日志LOGGER.warning(warning);LOGGER.fine(fine);} } 2.8 过滤器 ​ 在JULJava Util Logging中过滤器用于过滤日志消息只有符合特定条件的日志消息才会被记录或处理。JUL提供了两种类型的过滤器日志记录器过滤器Logger Filter和处理器过滤器Handler Filter。 日志记录器过滤器Logger Filter java.util.logging.Filter接口定义了日志记录器过滤器的方法boolean isLoggable(LogRecord record)该方法接收一个LogRecord对象作为参数并返回一个布尔值表示是否允许记录该日志消息。可以通过实现Filter接口来自定义日志记录器过滤器然后将其设置给特定的日志记录器。 处理器过滤器Handler Filter java.util.logging.Handler接口定义了处理器过滤器的方法boolean isLoggable(LogRecord record)该方法接收一个LogRecord对象作为参数并返回一个布尔值表示是否允许处理该日志消息。可以通过实现Handler接口来自定义处理器过滤器然后将其设置给特定的处理器。 演示 public class FilterTest {public static final Logger LOGGER Logger.getLogger(FilterTest.class.getName());// 日志记录器过滤器测试Testpublic void loggerFilterTest() {// 给日志记录器设置过滤器LOGGER.setFilter(logRecord - // 只打印级别 INFO的日志logRecord.getLevel().intValue() Level.INFO.intValue());LOGGER.info(hello);LOGGER.fine(world);LOGGER.finer(apache);}// 处理器过滤器测试Testpublic void handlerFilterTest() {// 禁用父级处理器LOGGER.setUseParentHandlers(false);ConsoleHandler consoleHandler new ConsoleHandler();consoleHandler.setFormatter(new SimpleFormatter());consoleHandler.setLevel(Level.ALL);// 给处理器设置过滤器consoleHandler.setFilter(logRecord - // 只打印a开头的日志logRecord.getMessage().startsWith(a));// 将处理器Handler加入到日志记录器Logger中LOGGER.addHandler(consoleHandler);LOGGER.info(hello);LOGGER.info(world);LOGGER.info(apache);} }2.9 打印异常堆栈 在JULJava Util Logging中可以通过配置日志记录器的级别和处理器来打印异常堆栈信息。 配置日志记录器的级别 使用Logger.setLevel(Level level)方法来设置日志记录器的级别。通常将日志记录器的级别设置为Level.SEVERE或更低的级别以便记录所有的异常信息。 配置处理器 使用Handler.setFormatter(Formatter formatter)方法来设置处理器的格式化器。使用SimpleFormatter类作为格式化器它会将日志消息格式化为包含时间戳、日志级别和消息内容的字符串。 演示 将异常的堆栈信息打印至控制台和文件中 package com.clear;import org.junit.Test;import java.io.IOException; import java.util.logging.*;public class ExceptionTest {public static final Logger LOGGER Logger.getLogger(ExceptionTest.class.getName());Testpublic void printStackTest() throws IOException {// 设置日志记录器的级别为FINERLOGGER.setLevel(Level.FINER);// 创建处理器Handler consoleHandler new ConsoleHandler();consoleHandler.setLevel(Level.FINER);// 设置处理器的格式化器consoleHandler.setFormatter(new SimpleFormatter());Handler fileHandler new FileHandler();fileHandler.setLevel(Level.FINER);fileHandler.setFormatter(new SimpleFormatter());// 将处理器添加到日志记录器LOGGER.addHandler(consoleHandler);LOGGER.addHandler(fileHandler);try {// 抛出异常int a 10 / 0;} catch (ArithmeticException e) {// 打印异常堆栈信息LOGGER.throwing(ExceptionTest.class.getName(), printStackTest, e);}} }3 LOG4J ​ LOG4J是一个流行的Java日志框架它提供了强大的日志记录和管理功能。LOG4J可以帮助开发人员在应用程序中实现灵活的日志记录并提供了多种配置选项和输出格式。 LOG4J的一些主要特点和用法 配置文件LOG4J使用一个配置文件来定义日志记录器、日志级别、输出目标等配置信息。默认的配置文件名为log4j.properties也可以使用XML格式的配置文件log4j.xml。日志级别LOG4J提供了多个日志级别包括DEBUG、INFO、WARN、ERROR和FATAL。可以根据需要设置不同的日志级别以控制日志记录的详细程度。日志记录器LOG4J使用日志记录器Logger来记录日志消息。每个日志记录器都有一个唯一的名称可以根据需要创建多个日志记录器。输出目标LOG4J支持将日志消息输出到不同的目标如控制台、文件、数据库等。可以根据需要配置不同的输出目标。格式化LOG4J允许自定义日志消息的格式。可以使用预定义的格式化器如PatternLayout也可以自定义格式化器。运行时配置LOG4J支持在运行时动态修改日志配置。可以通过修改配置文件或使用API来改变日志记录器的级别、输出目标等配置。 3.1 LOG4J的使用 1添加POM依赖 ​ 添加LOG4J依赖在项目的构建文件如Maven的pom.xml中添加LOG4J的依赖项 dependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version /dependency2创建LOG4J配置文件 ​ 创建LOG4J配置文件在项目的资源目录下创建一个LOG4J的配置文件命名为log4j.properties或log4j.xml。配置文件中定义了日志记录器、日志级别、输出目标等配置信息 参考如下 # 设置根日志级别为INFO log4j.rootLoggerINFO, console# 定义控制台输出目标 log4j.appender.consoleorg.apache.log4j.ConsoleAppender log4j.appender.console.layoutorg.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n3在代码中使用 在代码中使用LOG4J在需要记录日志的类中通过获取LOG4J的Logger对象来进行日志记录 import org.apache.log4j.Logger; import org.junit.Test;public class Log4jTest {// 获取Logger实例public static final Logger logger Logger.getLogger(Log4jTest.class);Testpublic void test1() {// 日志输出logger.fatal(fatal);logger.error(error);logger.warn(warn);logger.info(info);logger.debug(debug);logger.trace(trace);} }如果我们不添加配置文件会报如下错误 D:\software\jdk1.8.0_131\bin\java.exe ... log4j:WARN No appenders could be found for logger (com.clear.Log4jTest). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.JUL没有添加配置文件不会报错是因为他是Java原生的日志框架拥有默认的配置文件 如果我们没有添加配置文件加上如下方法也是可以的他会初始化一个默认的配置文件 BasicConfigurator.configure();4运行和查看日志 ​ 运行项目时LOG4J会根据配置文件中的设置进行日志记录。日志消息将根据配置的输出目标如控制台、文件进行输出。可以根据配置文件中的日志级别设置过滤和查看不同级别的日志消息。 3.2 默认配置解读 BasicConfigurator.configure();当我们在代码中加上如上一行时可以在使用log4j时不需要添加配置文件 演示 // 获取Logger实例 public static final Logger logger Logger.getLogger(Log4jTest.class);Test public void test1() {BasicConfigurator.configure();// 日志输出logger.fatal(fatal);logger.error(error);logger.warn(warn);logger.info(info);logger.debug(debug);logger.trace(trace); }结果如下 0 [main] FATAL com.clear.Log4jTest - fatal 1 [main] ERROR com.clear.Log4jTest - error 1 [main] WARN com.clear.Log4jTest - warn 1 [main] INFO com.clear.Log4jTest - info 1 [main] DEBUG com.clear.Log4jTest - debug源码解读 BasicConfigurator.configure(); 这一行代码会给RootLogger加上一个控制台的输出源类似于JUL的JHandler 在LOG4J中BasicConfigurator.configure()是一个静态方法用于简单配置日志记录器。它会自动创建一个默认的日志记录器并将其配置为使用控制台输出日志消息。 BasicConfigurator.configure()方法的主要作用是 1创建一个默认的日志记录器该方法会创建一个名为root的日志记录器并将其设置为根日志记录器。 2配置日志记录器默认的配置会将日志级别设置为DEBUG并将一个ConsoleAppender添加到日志记录器中。 3设置日志输出格式默认的配置会使用PatternLayout来定义日志消息的输出格式。 使用BasicConfigurator.configure()方法可以快速启动LOG4J的基本配置方便进行简单的日志记录。但是它的配置选项有限如果需要更复杂的配置可以使用自定义的配置文件或编程方式进行配置。 public static void configure() {Logger root Logger.getRootLogger();root.addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN))); }// 其中 PatternLayout.TTCC_CONVERSION_PATTERN) public final static String TTCC_CONVERSION_PATTERN %r [%t] %p %c %x - %m%n3.3 日志级别 在Log4j中日志级别从低到高分别为与JUL略有不同 TRACE最低级别的日志用于追踪程序的详细执行过程。DEBUG用于调试程序输出一些调试信息。默认INFO用于输出程序的运行信息如启动、关闭等。WARN用于输出警告信息表示可能出现的问题。ERROR用于输出错误信息表示程序出现了错误但不影响程序的继续运行。FATAL最高级别的日志用于输出严重的错误信息表示程序无法继续运行。 和JUL一样也有两个特殊的级别 OFF 用于关闭日志记录ALL 启用所有消息的日志记录 可以根据需要选择适当的日志级别来记录日志通常建议在生产环境中使用INFO级别或更高级别而在开发和调试阶段使用DEBUG级别。 3.4 核心组件 3.4.1 Loggers ​ Logger日志记录器用于记录日志消息的主要组件。每个Logger对象都与一个特定的日志记录器名称相关联可以通过该名称来标识不同的日志记录器。 ​ 实例的命名就是类XX的 full quailied name类的全限定名Logger的名字对大小写敏感其命名有继承机制例如名称为 com.clear.service 的logger 会继承自名称为 com.clear 的logger与JUL一致。 ​ Log4j有一个特殊的Logger叫做root它是所有Logger的根所有的Logger都会直接或间接继承自它。root logger可以用Logger.getRootLogger()方法获取。在JUL中也有一个 名为.的根 3.4.2 Appenders ​ Appender日志输出器与JUL的Handler类似用于将日志消息输出到不同的目标如控制台、文件、数据库等。Log4j提供了多种类型的Appender可以根据需求选择合适的输出目标。 输出端类型作用ConsoleAppender将日志输出到控制台FileAppender将日志输出到文件中DailyRollingFileAppender将日志输出到日志文件中并且每天输出到一个新的文件RollingFileAppender将日志输出到日志文件中并指定文件的尺寸当文件大小到达指定尺寸时会自动把文件改名同时产生一个新的文件JDBCAppender将日志输出到数据集中 例如 // 配置一个控制台输出源 ConsoleAppender consoleAppender new ConsoleAppender(); consoleAppender.setName(clear); consoleAppender.setWriter(new PrintWriter(System.out)); logger.addAppender(consoleAppender);3.4.3 Layouts Layout日志布局器用于定义日志消息的格式。Layout将日志消息转换为特定的字符串格式以便输出到Appender指定的目标。 3.4.4 Lever ​ Level日志级别用于控制日志消息的输出级别。可以根据需要设置不同的日志级别只有达到指定级别及以上的日志消息才会被记录和输出。 3.4.5 Configuration ​ Configuration配置用于配置Log4j的各个组件。可以通过配置文件或编程方式来配置Log4j包括设置日志级别、指定Appender和Layout等。 总结 ​ 这些核心组件共同工作实现了灵活、可配置的日志记录功能。通过合理配置和使用这些组件可以实现对日志消息的记录、输出和管理。 3.5 编程配置 在Log4j中可以通过编程方式进行配置 // 获取Logger实例 public static final Logger logger Logger.getLogger(Log4jTest.class);Test public void test2(){// 获取根Logger实例Logger rootLogger Logger.getRootLogger();// 创建一个ConsoleAppender对象ConsoleAppender consoleAppender new ConsoleAppender();// 设置输出流为标准输出流consoleAppender.setWriter(new PrintWriter(System.out));Layout layout new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN);// 将consoleAppender添加到根Logger实例中以便将日志输出到控制台consoleAppender.setLayout(layout);rootLogger.addAppender(consoleAppender);logger.warn(warn);logger.info(info);logger.debug(debug);}3.6 配置文件 ​ Log4j的配置文件是一个用于配置日志记录器的文本文件它定义了日志记录器的行为和输出方式。Log4j支持多种配置文件格式包括XML、JSON和属性文件 ​ 配置文件的命名通常为log4j.properties或log4j.xml可以放置在类路径下或指定的位置。在应用程序启动时Log4j会自动加载并解析配置文件根据配置文件的定义进行日志记录 例如 log4j.properties # 设置根日志级别为INFO并将日志输出到Console和File其实这里的名字可以随意起影响不大 log4j.rootLoggerINFO, Console, File# 定义控制台输出 log4j.appender.Consoleorg.apache.log4j.ConsoleAppender # 指定控制台输出的Layout为 PatternLayout log4j.appender.Console.layoutorg.apache.log4j.PatternLayout # 设置控制台输出的日志消息格式 log4j.appender.Console.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n# 定义文件输出 log4j.appender.Fileorg.apache.log4j.RollingFileAppender # 指定日志文件的路径和文件名这里定义的是相对路径可根据实际需要进行修改 log4j.appender.File.Filelogs/app.log # 设置日志文件的最大大小为10MB log4j.appender.File.MaxFileSize10MB # 设置保留的日志文件备份数量为10个 log4j.appender.File.MaxBackupIndex10 # 指定文件输出的 Layout为 PatternLayout log4j.appender.File.layoutorg.apache.log4j.PatternLayout # 设置文件输出的日志消息格式 log4j.appender.File.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n说明 ​ 控制台输出使用PatternLayout进行格式化文件输出使用RollingFileAppender进行日志文件的滚动。日志文件将按照文件大小进行切割每个文件最大为10MB最多保留10个备份文件。 如果需要分别控制输出到控制台和文件中的日志级别则如下 # 输出到控制台的日志级别 log4j.rootLoggerINFO, Console# 输出到文件的日志级别自定义Logger log4j.logger.myappWARN, File # 禁止将myapp Logger的日志事件传递给父Logger在自定义Logger时需要配置否则会重复打印日志 log4j.additivity.myappfalse# 控制台输出的配置 log4j.appender.Consoleorg.apache.log4j.ConsoleAppender log4j.appender.Console.layoutorg.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n# 文件输出的配置 log4j.appender.Fileorg.apache.log4j.RollingFileAppender log4j.appender.File.File/path/to/log/file.log log4j.appender.File.MaxFileSize10MB log4j.appender.File.MaxBackupIndex10 log4j.appender.File.layoutorg.apache.log4j.PatternLayout log4j.appender.File.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%nlog4j2.xml ?xml version1.0 encodingUTF-8? Configuration statusWARNAppenders!-- 定义控制台输出 --Console nameConsole targetSYSTEM_OUTPatternLayout pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n //Console!-- 定义文件输出(文件路径可根据实际进行修改) --RollingFile nameFile fileNamelogs/app.logfilePatternlogs/app-%d{yyyy-MM-dd}.logPatternLayout pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n /PoliciesSizeBasedTriggeringPolicy size10MB //PoliciesDefaultRolloverStrategy max10 //RollingFile/AppendersLoggers!-- 设置根日志级别为INFO --Root levelINFOAppenderRef refConsole /AppenderRef refFile //Root/Loggers /Configuration?xml version1.0 encodingUTF-8?指定XML文件的版本和编码。Configuration statusWARN设置Log4j的全局配置其中status属性设置为WARN表示只输出警告级别以上的日志信息。Appenders定义日志输出的Appenders。Console nameConsole targetSYSTEM_OUT定义控制台输出的Appender其中name属性为Appender的名称target属性指定输出目标为系统标准输出。PatternLayout pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n /设置控制台输出的日志消息格式。RollingFile nameFile fileNamelogs/app.log filePatternlogs/app-%d{yyyy-MM-dd}.log定义文件输出的Appender其中name属性为Appender的名称fileName属性指定日志文件的路径和文件名filePattern属性指定日志文件的滚动模式。Policies定义日志文件滚动的策略。SizeBasedTriggeringPolicy size10MB /设置日志文件的滚动触发策略为基于文件大小当日志文件达到10MB时触发滚动。DefaultRolloverStrategy max10 /设置日志文件的滚动策略为默认策略最多保留10个备份文件。Loggers定义日志记录器。Root levelINFO设置根日志记录器的级别为INFO。AppenderRef refConsole /和AppenderRef refFile /将控制台输出和文件输出的Appender引用添加到根日志记录器中。 输出格式 log4j 采用类似 C 语言的 printf 函数的打印格式格式化日志信息具体的占位符及其含义如下 转换符说明%m输出代码中指定的日志信息%p输出优先级如 DEBUG、INFO 等%n换行符Windows平台的换行符为 “\n”Unix 平台为 “\n”%r输出自应用启动到输出该 log 信息耗费的毫秒数%c输出打印语句所属的类的全限定名%t输出产生该日志的线程全名%d输出服务器当前时间默认格式为 ISO8601也可以在后面指定格式。如%d{yyyy-MM-dd HH:mm:ss}%l输出日志时间发生的位置包括类名、发生的线程以及在代码中的行数如Test.main(Test.java:10)%F输出日志消息产生时所在的文件名称%L输出代码中的行号%x输出和当前线程相关的 NDC嵌套诊断环境%%输出一个 “%” 字符 可以在 % 与字符之间加上修饰符来控制最小宽度、最大宽度和文本的对其方式。如 %5c 输出category名称最小宽度是5category5默认的情况下右对齐%-5c 输出category名称最小宽度是5category5-号指定左对齐,会有空格%.5c 输出category名称最大宽度是5category5就会将左边多出的字符截掉5不会有空格%20.30c category名称20补空格并且右对齐30字符就从左边交远销出的字符截掉 3.7 PatternLayout源码 PatternLayout这个实现类可以根据特定的占位符进行转换类似于JUL但是又不一样如下是他的构造器 public PatternLayout(String pattern) {this.pattern pattern;head createPatternParser((pattern null) ? DEFAULT_CONVERSION_PATTERN :pattern).parse(); }传入一个pattern字符他会根据pattern字符串创建一个链表 接着查看解析器 protected PatternParser createPatternParser(String pattern) {return new PatternParser(pattern); }查看parse()方法 // 如下是这个方法的简略版 publicPatternConverter parse() {char c;i 0;while(i patternLength) {c pattern.charAt(i);switch(state) {.....finalizeConverter(c); // 这个方法最重要的就是这个......return head; }下面是finalizeConverter()方法 protectedvoid finalizeConverter(char c) {PatternConverter pc null;switch(c) {case c:pc new CategoryPatternConverter(formattingInfo,extractPrecisionOption());//LogLog.debug(CATEGORY converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;// 处理类名的转换器case C:pc new ClassNamePatternConverter(formattingInfo,extractPrecisionOption());//LogLog.debug(CLASS_NAME converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;// 处理时间的转换器 case d:String dateFormatStr AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT;DateFormat df;String dOpt extractOption();if(dOpt ! null)dateFormatStr dOpt;if(dateFormatStr.equalsIgnoreCase(AbsoluteTimeDateFormat.ISO8601_DATE_FORMAT))df new ISO8601DateFormat();else if(dateFormatStr.equalsIgnoreCase(AbsoluteTimeDateFormat.ABS_TIME_DATE_FORMAT))df new AbsoluteTimeDateFormat();else if(dateFormatStr.equalsIgnoreCase(AbsoluteTimeDateFormat.DATE_AND_TIME_DATE_FORMAT))df new DateTimeDateFormat();else {try {df new SimpleDateFormat(dateFormatStr);}catch (IllegalArgumentException e) {LogLog.error(Could not instantiate SimpleDateFormat with dateFormatStr, e);df (DateFormat) OptionConverter.instantiateByClassName(org.apache.log4j.helpers.ISO8601DateFormat,DateFormat.class, null);}}pc new DatePatternConverter(formattingInfo, df);//LogLog.debug(DATE converter {dateFormatStr}.);//formattingInfo.dump();currentLiteral.setLength(0);break;// 输出日志时间发生的位置包括类名、线程、及代码所在行数 case F:pc new LocationPatternConverter(formattingInfo,FILE_LOCATION_CONVERTER);//LogLog.debug(File name converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case l:pc new LocationPatternConverter(formattingInfo,FULL_LOCATION_CONVERTER);//LogLog.debug(Location converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case L:pc new LocationPatternConverter(formattingInfo,LINE_LOCATION_CONVERTER);//LogLog.debug(LINE NUMBER converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case m:pc new BasicPatternConverter(formattingInfo, MESSAGE_CONVERTER);//LogLog.debug(MESSAGE converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case M:pc new LocationPatternConverter(formattingInfo,METHOD_LOCATION_CONVERTER);//LogLog.debug(METHOD converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case p:pc new BasicPatternConverter(formattingInfo, LEVEL_CONVERTER);//LogLog.debug(LEVEL converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case r:pc new BasicPatternConverter(formattingInfo,RELATIVE_TIME_CONVERTER);//LogLog.debug(RELATIVE time converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;case t:pc new BasicPatternConverter(formattingInfo, THREAD_CONVERTER);//LogLog.debug(THREAD converter.);//formattingInfo.dump();currentLiteral.setLength(0);break;/*case u:if(i patternLength) {char cNext pattern.charAt(i);if(cNext 0 cNext 9) {pc new UserFieldPatternConverter(formattingInfo, cNext - 0);LogLog.debug(USER converter [cNext].);formattingInfo.dump();currentLiteral.setLength(0);i;}elseLogLog.error(Unexpected char cNext at position i);}break;*/case x:pc new BasicPatternConverter(formattingInfo, NDC_CONVERTER);//LogLog.debug(NDC converter.);currentLiteral.setLength(0);break;case X:String xOpt extractOption();pc new MDCPatternConverter(formattingInfo, xOpt);currentLiteral.setLength(0);break;default:LogLog.error(Unexpected char [ c] at position i in conversion patterrn.);pc new LiteralPatternConverter(currentLiteral.toString());currentLiteral.setLength(0);}addConverter(pc);}下面就是一个典型的链表结构的创建: protected void addConverter(PatternConverter pc) {currentLiteral.setLength(0);// Add the pattern converter to the list.addToList(pc);// Next pattern is assumed to be a literal.state LITERAL_STATE;// Reset formatting infoformattingInfo.reset(); }private void addToList(PatternConverter pc) {if(head null) {head tail pc;} else {tail.next pc;tail pc;} }构建完转换器链表之后就是循环这个链表依次处理对应的占位符他的核心格式化的方法也是format方法在format方法中通过一个转换器链来完成转化 public static format(LoggingEvent event){// 在format方法中是通过转换器链来完成的PatternConverter c head;while(c ! null){// 这一句是核心第一个参数是StringBuilder第二个参数是LoggingEventc.format(sbuf, event);c c.next;}return sbuf.toString; } 这里就是通过一个pattern字符串这个字符串可能张这个样子%-d{yyyy-MM-dd HH:mm:ss​} [%t:%r] -[%p] %m%n,使用createPatternParser().parse()构建第一个处理器的链表这个每个处理器处理一个占位符例如%d 进入 c.format()方法我们会进入一个抽象类 PatternConverter 中的format方法该方法的核心代码如下 public void format(StringBuilder sbuf, LoggingEvent e){// 核心语句如下String s convert(e); }3.10 日志分割 在Log4j中可以通过配置来实现日志的分割即将日志按照一定的规则拆分成多个文件以便于管理和查看。 Log4j提供了多种方式来实现日志的分割其中常用的方式包括 按时间分割可以按照日期、小时、分钟等时间单位来拆分日志文件。例如每天生成一个新的日志文件或者每小时生成一个新的日志文件。按文件大小分割可以按照文件大小来拆分日志文件。例如当日志文件达到一定大小时自动创建一个新的日志文件。按日志级别分割可以按照日志级别来拆分日志文件。例如将不同级别的日志分别记录到不同的文件中 源码中FileAppender类有几个子类用于实现日志文件的滚动、分割 DailyRollingFileAppender按照日期滚动的Appender。它可以按照一定的时间间隔如每天、每周、每月生成新的日志文件RollingFileAppender按照文件大小滚动的Appender。它可以在日志文件达到一定大小时生成新的日志文件 ExternallyRolledFileAppende外部滚动的Appender。它允许外部程序控制日志文件的滚动。可以通过外部程序的信号或命令来触发日志文件的滚动。 如下是使用DailyRollingFileAppender和RollingFileAppender来实现日志文件的分割和滚动 # 设置根日志级别为INFO log4j.rootLoggerINFO, dailyRollingFile, rollingFile# 配置DailyRollingFileAppender log4j.appender.dailyRollingFileorg.apache.log4j.DailyRollingFileAppender log4j.appender.dailyRollingFile.Filelogs/application.log # 指定按照日期滚动的规则 log4j.appender.dailyRollingFile.DatePattern.yyyy-MM-dd log4j.appender.dailyRollingFile.layoutorg.apache.log4j.PatternLayout log4j.appender.dailyRollingFile.layout.ConversionPattern%d{HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n# 配置RollingFileAppender log4j.appender.rollingFileorg.apache.log4j.RollingFileAppender log4j.appender.rollingFile.Filelogs/application.log # 日志文件到达10MB时生成新文件 log4j.appender.rollingFile.MaxFileSize10MB # 保留最多5个备份文件 log4j.appender.rollingFile.MaxBackupIndex5 log4j.appender.rollingFile.layoutorg.apache.log4j.PatternLayout log4j.appender.rollingFile.layout.ConversionPattern%d{HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n# 设置日志输出格式 log4j.appender.console.layoutorg.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern%d{HH:mm:ss.SSS} [%t] %-5p %c{1} - %m%n# 配置日志级别 log4j.logger.com.exampleDEBUG# 关闭Log4j内部日志输出 log4j.logger.org.apache.log4jOFF​ 在Java源代码中Log4j的日志分割功能由RollingFileAppender类实现。它通过检查日志文件的大小或时间来决定是否需要生成新的日志文件。 例如 import org.apache.log4j.RollingFileAppender; import org.apache.log4j.PatternLayout;RollingFileAppender appender new RollingFileAppender(); appender.setFile(logs/application.log); appender.setLayout(new PatternLayout(%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n)); appender.setMaxFileSize(10MB); appender.setMaxBackupIndex(5); appender.activateOptions();Logger logger Logger.getLogger(com.clear.MyClass); logger.addAppender(appender);3.6 自定义Logger log4j.properties # 设置根Logger的日志级别和输出目标 log4j.rootLoggerINFO, console# 设置自定义Logger的日志级别和输出目标 log4j.logger.com.clearDEBUG, myappFile # 禁止将myapp Logger的日志事件传递给父Logger在自定义Logger时需要配置否则会重复打印日志 log4j.additivity.com.clearfalse# 设置输出目标为控制台 log4j.appender.consoleorg.apache.log4j.ConsoleAppender log4j.appender.console.layoutorg.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern%d [%t] %-5p %c - %m%n# 设置输出目标为文件 log4j.appender.myappFileorg.apache.log4j.FileAppender log4j.appender.myappFile.FileD:/test/myapp.log log4j.appender.myappFile.layoutorg.apache.log4j.PatternLayout log4j.appender.myappFile.layout.ConversionPattern%d [%t] %-5p %c - %m%n测试 public static final Logger LOGGER Logger.getLogger(DIY.class); Test public void test(){// 测试自定义Logger// 我们配置文件中设置了DEBUG级别以及上的才输出到日志文件LOGGER.trace(trace);LOGGER.debug(debug);LOGGER.info(info);LOGGER.warn(warn);LOGGER.error(error);LOGGER.fatal(fatal); }结果 D:\test\myapp.log 内容如下确实只打印了DEBUG及以上的日志 2023-07-21 21:33:00,514 [main] DEBUG com.clear.DIY - debug 2023-07-21 21:33:00,515 [main] INFO com.clear.DIY - info 2023-07-21 21:33:00,515 [main] WARN com.clear.DIY - warn 2023-07-21 21:33:00,515 [main] ERROR com.clear.DIY - error 2023-07-21 21:33:00,515 [main] FATAL com.clear.DIY - fatal4 日志门面 日志门面Logging Facade是一种设计模式用于在应用程序中实现日志记录的抽象层。它的作用是提供一个统一的接口使应用程序可以使用不同的日志库进行日志记录而不需要直接依赖于特定的日志库。 日志门面的作用有以下几个方面 解耦应用程序和具体的日志库通过使用日志门面应用程序可以将日志记录的实现细节与具体的日志库解耦。这意味着应用程序可以在不修改代码的情况下切换或替换不同的日志库以满足不同的需求或适应不同的环境。统一日志记录接口日志门面提供了一个统一的接口使应用程序可以使用相同的日志记录方法和语法无论使用哪个具体的日志库。这简化了日志记录的代码编写和维护并提高了代码的可读性和可维护性。支持多个日志级别和日志输出目标日志门面通常支持多个日志级别如调试、信息、警告、错误等和多个日志输出目标如控制台、文件、数据库等。这使得应用程序可以根据需要选择适当的日志级别和输出目标以满足不同的调试、监控和故障排查需求。提供日志记录的扩展和定制能力通过日志门面应用程序可以使用日志库提供的扩展和定制功能如日志过滤、格式化、异步记录等。这使得应用程序可以根据具体需求对日志记录进行定制和优化以满足特定的业务需求和性能要求。 总之日志门面的作用是提供一个抽象层使应用程序可以灵活地使用不同的日志库并提供统一的日志记录接口和功能以提高代码的可维护性、可读性和灵活性 4.1 阿里日志规约 【强制】应用中不可直接使用日志系统(Log4、Logback中的API 而应依赖使用日志框架(SLF4)、JCL–Jakarta Commons Logging中的API使用门面模式的日志框架 有利于维护和各个类的日志处理方式统一。 说明日志框架 (SLF4)JCL–Jakarta Commons Logging的使用方式推荐使用 SLF4J) // 使用 SLF4J import org.slf4j Logger; import org slf4j. LoggerFactory; private static final Logger logger LoggerFactory getLogger(Test.class);// 使用 JCL import org.apache.commons.logging.Log; import org.apache.commons.logging. LogFactory; private static final Log log LogFactory getLog(Test.class);【强制】所有日志文件至少保存 15 天因为有些异常具备以“周” 为频次发生的特点。对于当天日志以“应用名.log〞 来保存保存在/home/admin/应用名/logs/目录下过往日志格式为{logname.log}.{保存日期}日期格式yyyy-MM-dd 正例以aap 应用为例日志保存在/home/admin/aapserver/logs/aap.log历史日志名称为aap.log.2016-08-01 【强制】根据国家法律网络运行状态、网络安全事件、个人敏感信息操作等相关记录留存的日志不少于六个月并且进行网络多机备份。 【强制】应用中的扩展日志如打点、临时监控、访问日志等 命名方式 appName log Type Iog Name.log。 logType:日志类型 如stats/monitor/access 等; logName:日志描述。这种命名的好处通过文件名就可知道日志文件属于什么应用什么类型什么目的也有利于归类查找。 说明推荐对日志进行分类如将错误日志和业务日志分开存放便于开发人员查看也便于通过日志对系统进行及时监控。 正例mppserver 应用中单独监控时区转换异常如mppserver_monitor_timeZoneConvert.log 【强制】在日志输出时 字符串变量之间的拼接使用占位符的方式。 说明因为String 字符串的拼接会使用 StringBuilder 的append0方式有一定的性能损耗。使用占位符仅是替换动作可以有效提升性能。 正例 java logger.debug(Processing trade with id: ( and symbol: (, id, symbol);【强制】对于 trace/debue/info 级别的日志输出必须进行日志级别的开关判断。 说明虽然在 debug(参数的方法体内第一行代码 isDisabled(Level.DEBUGLINT)为真时 S1f4j的常见实现Log4j 和Logback就直接return 但是参数可能会进行字符串拼接运算。此外如果 debug(getNameo这种参数内有getName0方法调用无谓浪费方法调用的开销。 正例 // 如果判断为真那么可以输出 trace 和 debug 级别的日志 if (logger.isDebugEnabled0) {logger.debug(“Current ID is: and name is: , id, getNamel); }【强制】避免重复打印日志浪费磁密空间 务必在日志配置文件中设置 additivity false。 正例 logger name”com.taobao.dubbo.config” additivityfalse”【强制】生产环境禁止直接使用 System.out 或System.err 输出日志或使用e.printStackTrace(打印昇常堆桟。 说明标准日志输出与标准错误输出文件每次 Jboss 重启时才滚动如果大量输出送往这两个文件容易造成文件大小超过操作系统大小限制。 【强制】异常信息应该包括两类信息 案发现场信息和异常堆栈信息。如果不处理那么通过关键字 throws 往上抛出。 正例 logger.error(inputParams:{} and errorMessage:{}”各类参数或者对系 toString(), e.getMessage(), e);【强制】日志打印时禁止直接用 JSON 工具将对象转换成 String。 说明如果对象里某些 get 方法被覆写存在抛出异常的情况则可能会因为打印日志而影响正常业务流程的执行。正例打印日志时仅打印出业务相关属性值或者调用其对象的 toString() 方法。 【推荐】递慎地记录日志。生产环境禁止输出 debug 日志有选择地输出 info 日志如果使用 warn 来记录刚上线时的业务行为信息一定要注意日志输出量的问题避免把服务器磁盘撑爆并记得及时删除这些观察日志。 说明大量地输出无效日志 不利于系统性能提升 也不利于快速定位错误点。记录日志时请思考这些日志真的有人看吗看到这条日志你能做什么能不能给问题排查带来好处 【推荐】可以使用 warn 日志级别来记录用户输入参数错误的情况避免用户投诉时无所适从。如非必要请不要在此场景打出 error级别避免频繁报警。 说明注意日志输出的级别error 级别只记录系统逻辑出错、异常或者重要的错误信息。 【推荐】尽量用英文来描述日志错误信息如果日志中的错误信息用英文描述不清楚的话使用中文描述即可否则容易产生歧义。 说明国际化团队或海外部署的服务器由于字符集问题使用全英文来注释和描述日志错误信息。 为什么要使用日志规约 面向接口开发不再依赖具体的实现类减少代码的耦合项目通过导入不同的日志实现类可以灵活的切换日志框架统一API、方便开发者学习、使用统一配置便于项目日志的管理 4.2 SLF4J ​ 简单日志门面Simple Logging Facade For JavaSLF4J主要是为了给Java日志访问提供一套标准、规范的API框架其意义主要是提供接口具体的实现交由日志框架例如log4j、logback等。当然slf4j 自己也提供了功能较为简单的日志实现但是我们一般不使用。 对于一般的Java项目而言我们会选择 slf4j-api 作为门面再配上具体的日志实现log4j、logback等中间使用桥接器完成桥接。 SLF4J主要提供了两大功能 日志框架的绑定日志框架的桥接 4.2.1 使用SLF4J入门slf4j与simple整合 ​ SLF4JSimple Logging Facade for Java是一个日志门面框架它提供了一组简单的接口用于在Java应用程序中进行日志记录。SLF4J本身提供了一个简单的日志实现称为SimpleLogger。SimpleLogger是SLF4J的默认日志实现它不需要额外的依赖可以直接在项目中使用 要使用SimpleLogger只需按照以下步骤进行配置 1添加SLF4J依赖在项目的构建文件如pom.xml中添加SLF4J的依赖。 pom.xml dependencies!-- SLF4J API --!-- SLF4J是一个抽象层它提供了统一的日志接口可以与不同的日志实现框架如Logback、Log4j等进行交互 --dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.32/version/dependency!-- SLF4J 自带的简单日志实现 --dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-simple/artifactIdversion1.7.32/version/dependency /dependencies2配置日志级别在项目的根目录下创建一个名为simplelogger.properties的文件并添加以下内容 这一步可以不配置 org.slf4j.simpleLogger.defaultLogLeveldebug上述配置将日志级别设置为DEBUG你可以根据需要将其调整为其他级别如INFO、WARN、ERROR等。 3在代码中使用SLF4J接口进行日志记录在需要记录日志的地方使用SLF4J提供的接口进行日志记录。 例如 import org.slf4j.Logger; import org.slf4j.LoggerFactory;public class SLF4JTest {// 获取Logger实例public static final Logger logger LoggerFactory.getLogger(SLF4JTest.class);public static void main(String[] args) {logger.debug(Debug message);logger.info(Info message);logger.warn(Warning message);logger.error(Error message);} }​ 通过以上步骤就可以在Java应用程序中使用SLF4J的SimpleLogger进行日志记录。SimpleLogger的实现非常简单适用于简单的应用程序或测试环境。如果需要更高级的日志功能可以考虑使用其他日志实现框架如Logback或Log4j2 4.2.2 绑定其他日志的实现Binding SLF4J支持各种日志框架。SLF4J发行版附带了几个称为“SLF4J绑定”的jar文件每个绑定对应一个受支持的框架。 使用SLF4J的日志绑定流程 添加 slf4j-api 的依赖使用slf4j的API在项目中进行统一的日志记录绑定具体的日志实现框架 绑定已经实现了slf4j的日志框架直接添加对应的依赖绑定没有实现了slf4j的日志框架先添加日志的适配器再添加实现类的依赖 slf4j有且仅有一个日志实现框架的绑定如果出现多个默认使用第一个依赖日志实现 绑定jul的实现jul是JCL门面的实现及与jdk14整合 dependencies!-- SLF4J API --!-- SLF4J是一个抽象层它提供了统一的日志接口可以与不同的日志实现框架如Logback、Log4j等进行交互 --dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.32/version/dependencydependencygroupIdorg.slf4j/groupId!--jdk14指的是JDK1.4开始支持slf4j绑定JUL--artifactIdslf4j-jdk14/artifactIdversion1.7.32/version/dependency /dependencies绑定log4j的实现slf4j与log4j整合 dependencies!-- SLF4J API --!-- SLF4J是一个抽象层它提供了统一的日志接口可以与不同的日志实现框架如Logback、Log4j等进行交互 --dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.32/version/dependencydependencygroupIdorg.slf4j/groupIdartifactIdslf4j-log4j12/artifactIdversion1.7.32/version/dependencydependencygroupIdlog4j/groupIdartifactIdlog4j/artifactIdversion1.2.17/version/dependency /dependencies说明 ​ 要切换日志框架只需要替换类路径上的slf4j绑定。例如要从java.util.loggingjul切换到log4j只需要将 slf4j-jdk14-1.7.32.jar 替换为 slf4j-log4j12-1.7.32.jar 即可。 ​ SLF4J不依赖于任何特殊的类加载。实际上每个SLF4J绑定在编译时都是硬连线的以使用一个且一个特定的日志记录框架。例如 slf4j-log4j12-1.7.32.jar绑定在编译时绑定以使用log4j 4.2.3 桥接旧的日志框架Birdging ​ SLF4J提供了日志桥接Logging Bridges的功能用于将其他日志框架的日志记录转发到SLF4J接口。这样可以在项目中使用SLF4J进行日志记录同时仍然能够使用其他日志框架的功能 ​ 通常您依赖的某些组件依赖于SLF4J以外的日志记录APl。您也可以假设这些組件在不久的将来不会切换到SLF4J。为了解决这种情况SLF4J附带了几个桥接模块这些模共将对log4jJCL和 java.util.logging API 的调用重定向就好像它们是对SLF4J API一样。 ​ 就是你还用log4j的api写代码但是具体的实现给你抽离了我们依赖了一个中间层这个层其实是用旧的的api操作slf4j而不是操作具体的实现。 桥接解決的是项目中日志的遗留问题当系统中存在之前的日志API可以通过桥接转换到slf4j的实现 1先去除之前老的日志框架的依赖必须去掉。2添加SLF4J提供的桥接组件这个组件就是模仿之前老的日志与了一套相同的api只不过这个api是在调用slf4j的api。3为项目添加SLF4J的具体实现。 SLF4J提供的桥接组件 !-- 桥接的组件--!-- log4j转slf4j -- dependencygroupIdorg.slf4j/groupIdartifactIdlog4j-over-slf4j/artifactIdversion1.7.32/version /dependency!-- jul转slf4j -- dependencygroupIdorg.slf4j/groupIdartifactIdjul-to-slf4j/artifactIdversion1.7.32/version /dependency!-- jcl转slf4j -- dependencygroupIdorg.slf4j/groupIdartifactIdjcl-over-slf4j/artifactIdversion1.7.32/version /dependency注意 jcl-over-slf4j.jar 和 slf4j-jcl.jar 不能同时部署。前一个jar文件将导致JCL将日志系统的选择委托给 SLF4J后一个jar文件将导致SLF4J将日志系统的选择委托给 JCL从而导致无限循环。log4j-over-slf4j.jar 和 slf4j-log4j12.jar 不能同时出现jul-to-slf4j.jar 和 slf4j-jdk14.jar 不能同时出现所有的桥接都只对Logger日志记录器有效如果程序中调用了内部的配置类或者是 Appender、Filter等对象将无法产生效果 4.2.3 SLF4J原理剖析 4.3 JCL 全称为Jakarta Conmons Logging是Apache提供的一个通用日志API。该日志门面的使用并不是很广泛。 它是为“所有的Java日志实现提供一个统一的接口它自身也提供一个日志的实现但是功能非常的弱 (Simplelog。所以一般不会单独使用它。他允许开发人员使用不同的具体日志实现工具Log4j、Jdk自带的日志 JUL) JCL有两个基本的抽象类Log(基本记录器) 和 LogFactory负责创建Log实例) 简单使用 1添加依赖 pom.xml dependenciesdependencygroupIdcommons-logging/groupIdartifactIdcommons-logging/artifactIdversion1.2/version/dependency /dependencies2编写代码 public class JCLTest {// 创建Logger实例public static final Log log LogFactory.getLog(JCLTest.class);public static void main(String[] args) {log.fatal(fatal);log.error(error);log.warn(warn);log.info(info);log.debug(debug);}4.4 日志发展历史 Java日志系统历史从入门到崩溃 - 个人文章 - SegmentFault 思否 5 Logback ​ Logback是一个功能强大的Java日志框架是Log4j框架的继任者Logback是由Log4j创始人编写的。它提供了灵活的配置选项和高性能的日志记录功能被广泛用于Java应用程序的日志管理。 以下是一些Logback的特点和功能 灵活的配置Logback使用XML或Groovy配置文件来定义日志记录器、日志级别、输出格式等。它支持继承和覆盖配置可以根据不同的环境和需求进行灵活的配置。多种日志级别Logback支持多种日志级别包括TRACE、DEBUG、INFO、WARN、ERROR等。开发人员可以根据需要选择适当的日志级别来记录不同类型的信息。多种输出方式Logback支持多种输出方式包括控制台输出、文件输出、远程日志服务器等。开发人员可以根据需求配置多个输出目标以便在不同环境下进行日志记录和分析。异步日志记录Logback支持异步日志记录可以提高日志记录的性能。它使用多线程机制将日志事件异步写入目标输出避免了阻塞应用程序的性能问题。运行时配置更新Logback支持在运行时动态更新配置无需重启应用程序。这使得开发人员可以在不停止应用程序的情况下修改日志配置方便调试和故障排查。插件支持Logback提供了丰富的插件支持可以扩展其功能。例如可以使用Logstash插件将日志数据发送到Elasticsearch进行分析和可视化。 5.1 三大模块 Logback框架包含三个主要的模块logback-core、logback-classic 和 logback-access。 logback-corelogback-core是Logback框架的核心模块提供了日志记录和输出的基本功能。 它定义了Logger、Appender、Layout等核心组件的接口和实现并提供了日志事件的处理和传递机制。logback-core模块是其他两个模块的基础它不依赖于任何特定的日志实现。 logback-classiclogback-classic是Logback框架的经典模块是logback-core模块的扩展。 它是Log4j的改良版实现了完整的SLF4JSimple Logging Facade for Java的API并提供了与SLF4J的适配器使得应用程序可以无缝地迁移和使用Logback作为日志实现。logback-classic模块还提供了一些额外的功能如MDCMapped Diagnostic Context和LoggerContext等。 logback-accesslogback-access是Logback框架的访问模块用于记录和访问HTTP请求的日志。 它提供了与Servlet容器集成的功能可以记录HTTP请求的详细信息如请求URL、请求参数、响应状态等。logback-access模块可以与logback-classic模块一起使用实现全面的日志记录和访问功能。 这三个模块共同构成了Logback框架的核心功能开发人员可以根据需要选择和配置相应的模块以满足应用程序的日志管理需求。 5.2 Logbook的使用 1要想使用Logbook框架至少需要在pom中导入如下三个依赖 slf4j-api日志门面logbook-corelogback-classic pom.xml dependencies!-- SLF4J API --!-- SLF4J是一个抽象层它提供了统一的日志接口可以与不同的日志实现框架如Logback、Log4j等进行交互 --dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.32/version/dependency!-- Logback Core --dependencygroupIdch.qos.logback/groupIdartifactIdlogback-core/artifactIdversion1.2.3/version/dependency!-- Logback Classic --dependencygroupIdch.qos.logback/groupIdartifactIdlogback-classic/artifactIdversion1.2.3/version/dependency /dependencies2在模块的src目录下创建核心配置文件 logback.xml ?xml version1.0 encodingUTF-8? configuration!--CONSOLE 表示当前的日志信息是可以输出到控制台的。--appender nameCONSOLE classch.qos.logback.core.ConsoleAppender!--输出流对象 默认 System.out 改为 System.err--targetSystem.out/targetencoder!--格式化输出%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符--pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c [%thread] : %msg%n/pattern/encoder/appender!-- File是输出的方向通向文件的 --appender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/patterncharsetutf-8/charset/encoder!--日志输出路径--fileC:/code/data.log/file!--该目录需要提前存在-!-指定日志文件拆分和压缩规则--rollingPolicyclassch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy!--通过指定压缩文件名称来确定分割文件方式--fileNamePatternC:/code/data-%d{yyyy-MMdd}.log%i.gz/fileNamePattern!--文件拆分大小--maxFileSize1MB/maxFileSize/rollingPolicy/appender!--level:用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF 默认debugroot可以包含零个或多个appender-ref元素标识这个输出位置将会被本日志级别控制。--root levelALLappender-ref refCONSOLE/appender-ref refFILE //root /configuration3创建Logback框架提供的Logger对象然后用Logger对象调用其提供的方法就可以记录系统的日志信息。 public static final Logger LOGGER LoggerFactory.getLogger(类名);简单演示 import org.slf4j.Logger; import org.slf4j.LoggerFactory;public class LogBackTest {// 创建Logger日志对象public static final Logger LOGGER LoggerFactory.getLogger(LogBackTest);public static void main(String[] args) {try {LOGGER.info(div方法开始执行~~~);div(10, 0);LOGGER.info(div方法执行成功~~~);} catch (ArithmeticException e) {LOGGER.error(div方法执行失败);}}public static void div(int a, int b) {LOGGER.debug(参数a: a);LOGGER.debug(参数b: b);System.out.println(a / b a / b);LOGGER.info(a / b a / b);} }结果 16:08:44.962 [main] INFO LogBackTest - div方法开始执行~~~ 16:08:44.964 [main] DEBUG LogBackTest - 参数a: 10 16:08:44.964 [main] DEBUG LogBackTest - 参数b: 0 16:08:44.964 [main] ERROR LogBackTest - div方法执行失败5.3 核心配置文件logback.xml 对LogBack日志框架进行控制 日志的输出位置、输出格式的设置 通常可以设置2个输出日志的位置一个是控制台、一个是系统文件中 appender nameCONSOLE classch.qos.logback.core.ConsoleAppenderappender nameFILE classch.qos.logback.core.rolling.RollingFileAppender开启ALL、关闭日志OFF root levelALLappender-ref refCONSOLE/ !-- 如果不想将日志输出到控制台注释该行即可--appender-ref refFILE / /root如下是一个logback.xml的模板 configuration!-- 定义日志输出的格式 --property nameLOG_PATTERN value%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/!-- 定义日志输出的目录 --property nameLOG_DIR value/path/to/log/directory/!-- 定义根日志级别 --root levelINFOappender-ref refCONSOLE/appender-ref refFILE//root!-- 定义控制台输出的日志 --appender nameCONSOLE classch.qos.logback.core.ConsoleAppenderencoderpattern${LOG_PATTERN}/pattern/encoder/appender!-- 定义文件输出的日志 --appender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderfile${LOG_DIR}/application.log/filerollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicyfileNamePattern${LOG_DIR}/application.%d{yyyy-MM-dd}.%i.log/fileNamePatternmaxHistory30/maxHistory/rollingPolicyencoderpattern${LOG_PATTERN}/pattern/encoder/appender/configuration定义日志输出的格式通过property元素定义一个名为LOG_PATTERN的属性可以在后面的配置中引用该属性。定义日志输出的目录通过property元素定义一个名为LOG_DIR的属性可以在后面的配置中引用该属性。定义根日志级别通过root元素定义根日志的级别以及要使用的日志输出器appender。定义控制台输出的日志通过appender元素定义一个名为CONSOLE的控制台输出器使用ConsoleAppender类并配置日志格式。定义文件输出的日志通过appender元素定义一个名为FILE的文件输出器使用RollingFileAppender类并配置日志文件路径、滚动策略、日志格式等。 打印日志到控制台 appender nameCONSOLE classch.qos.logback.core.ConsoleAppender!--输出流对象 默认 System.out 改为 System.err--targetSystem.out/targetencoder!--格式化输出%d表示日期%thread表示线程名%-5level级别从左显示5个字符宽度%msg日志消息%n是换行符--pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c [%thread] : %msg%n/pattern/encoder /appenderConsoleAppender类表示日志信息输出到控制台 pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c [%thread] : %msg%n中 表示输出格式%d{yyyy-MM-dd HH:mm:ss.SSS} 表示日期年月日时分秒%-5level 表示日志输出的级别%c 表示当前所在类打印日志的类%thread 表示当前线程%msg 表示日志信息%n 表示换行 打印日志到文件 appender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/patterncharsetutf-8/charset/encoder!--日志输出路径--fileC:/code/data.log/file!--指定日志文件拆分和压缩规则--rollingPolicyclassch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy!--通过指定压缩文件名称来确定分割文件方式--fileNamePatternC:/code/data-%d{yyyy-MMdd}.log%i.gz/fileNamePattern!--文件拆分大小--maxFileSize1MB/maxFileSize/rollingPolicy /appenderRollingFileAppender类表示日志信息输出到文件 charsetutf-8/charset 记录写入到文件中的字符集编码为UTF-8 fileC:/code/data.log/file 控制文件输出的路径 5.4 Logback日志级别的设置 以下是Logback中定义的日志级别从小到大 TRACE最低的日志级别用于输出最详细的日志信息通常用于调试目的。(追踪指明程序运行轨迹)DEBUG用于输出调试信息比TRACE级别更高通常用于开发和调试阶段。INFO用于输出一般的信息性消息表示程序正常运行的状态。WARN用于输出警告信息表示潜在的问题或不符合预期的情况但不会影响程序的正常运行。ERROR用于输出错误信息表示严重的问题或错误可能会导致程序的异常终止或不可恢复的错误。 除了以上五个标准的日志级别Logback还支持自定义的日志级别。可以根据具体的需求定义自己的日志级别并在配置文件中进行配置。 ​ 在Logback中可以通过配置文件通常是logback.xml或logback.groovy来设置日志级别。可以为不同的日志记录器Logger设置不同的日志级别以控制不同部分的日志输出。 例如可以使用以下配置将日志级别设置为DEBUG 只有日志级别是大于或等于核心配置文件配置的日志级别才会别记录否则不会被记录 root levelDEBUGappender-ref refCONSOLE/appender-ref refFILE / /root5.5 日志拆分 在 Logback 中可以通过配置来实现日志的拆分。拆分日志可以按照时间、文件大小或者其他条件进行 时间拆分使用 TimeBasedRollingPolicy 可以按照时间来拆分日志文件。可以通过 fileNamePattern 指定拆分后的日志文件名格式例如 logfile-%d{yyyy-MM-dd}.%i.log其中 %d{yyyy-MM-dd} 表示按照日期进行拆分%i 表示拆分后的文件索引。可以通过 maxHistory 指定保留的历史日志文件的数量。大小拆分使用 SizeBasedTriggeringPolicy 可以按照文件大小来拆分日志文件。可以通过 maxFileSize 指定每个日志文件的最大大小例如 10MB。当日志文件达到指定大小时会自动拆分为新的日志文件。条件拆分使用 OnMarkerEvaluator 可以根据自定义的条件来拆分日志文件。可以通过 evaluator 配置一个自定义的 OnMarkerEvaluator并在代码中使用 Marker 来触发日志拆分。 演示 将日志按照时间和文件大小进行拆分 configurationappender nameFILE classch.qos.logback.core.rolling.RollingFileAppenderfile/path/to/logfile.log/file!-- 按照时间来拆分日志文件 --rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy!-- 指定拆分后的日志文件名格式 --fileNamePattern/path/to/logfile-%d{yyyy-MM-dd}.%i.log/fileNamePattern!-- 指定保留的历史日志文件的数量 --maxHistory30/maxHistory/rollingPolicy!-- 按照文件大小来拆分日志文件 --triggeringPolicy classch.qos.logback.core.rolling.SizeBasedTriggeringPolicy!-- 指定每个日志文件的最大大小 --maxFileSize10MB/maxFileSize/triggeringPolicyencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern/encoder/appenderroot levelINFOappender-ref refFILE //root /configuration上面配置中日志文件将按照日期进行拆分每天生成一个新的日志文件。同时当日志文件达到 10MB 时也会触发拆分为新的日志文件 5.6 Logback过滤器 在 Logback 中可以使用过滤器来控制日志的输出。过滤器可以根据不同的条件来决定是否输出某条日志。 Logback 提供了多种类型的过滤器常用的过滤器包括 LevelFilter根据日志级别进行过滤。可以通过设置 level 属性来指定过滤的日志级别只有达到指定级别的日志才会被输出。ThresholdFilter根据日志级别的阈值进行过滤。可以通过设置 level 属性来指定阈值只有达到或超过指定级别的日志才会被输出。EvaluatorFilter根据自定义的评估器进行过滤。可以通过设置 evaluator 属性来指定一个自定义的评估器根据评估器的结果来决定是否输出日志。MarkerFilter根据 Marker 进行过滤。可以通过设置 marker 属性来指定一个 Marker只有包含指定 Marker 的日志才会被输出。TurboFilter自定义的高性能过滤器。可以通过继承 ch.qos.logback.core.spi.TurboFilter 类来实现自定义的过滤器。 演示 使用 LevelFilter 过滤器只输出 INFO 级别的日志 configurationappender nameCONSOLE classch.qos.logback.core.ConsoleAppenderencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern/encoder/appenderroot levelDEBUGappender-ref refCONSOLE //rootlogger namecom.clear levelDEBUG /filter classch.qos.logback.classic.filter.LevelFilter!-- 只输出 INFO 级别的日志 --levelINFO/levelonMatchACCEPT/onMatchonMismatchDENY/onMismatch/filter /configuration在上述配置中所有的日志都会输出到控制台。但是通过 LevelFilter 过滤器只有 INFO 级别的日志才会被接受输出其他级别的日志会被拒绝不输出 5.7 Logback异步日志 打印日志到文件中需要涉及到大量的文件IO性能比较低Logback之所以高效就是因为它支持异步日志 在 Logback 中可以使用异步日志来提高日志的性能和吞吐量。异步日志将日志的写入操作放在一个独立的线程中进行不会阻塞主线程的执行。 使用方式 ​ 要启用异步日志可以使用 Logback 提供的 AsyncAppender。AsyncAppender 是一个包装器可以将其他的 Appender 转换为异步的。 演示 configurationappender nameASYNC_FILE classch.qos.logback.classic.AsyncAppender!-- 使用 AsyncAppender 包装了这个 FileAppender将其转换为异步的 --appender-ref refFILE /!-- 指定了异步队列的大小 --queueSize512/queueSize!-- 指定了当队列满时是否丢弃日志 --!-- 0,表示不丢弃任何日志事件。新的日志事件将被阻塞直到队列中有空闲位置--!-- 大于0,表示当队列已满时丢弃最早的discardingThreshold个日志事件然后将新的日志事件添加到队列中 --!-- 如果对日志的实时性要求较高可以将 discardingThreshold 的值设置为一个较小的数值以避免队列过大导致的性能问题--discardingThreshold0/discardingThreshold/appender!-- FileAppender将日志输出到文件 logs/myapp.log --appender nameFILE classch.qos.logback.core.FileAppenderfilelogs/myapp.log/fileencoderpattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n/pattern/encoder/appenderroot levelDEBUG!-- 用于将一个或多个 appender 引用到根日志中。在这里根日志引用了名为 ASYNC_FILE 的 appender表示根日志的输出目标是 ASYNC_FILE appender--appender-ref refASYNC_FILE //root /configuration6 LOG4J2 ​ Log4j 2 是一个用于 Java 应用程序的日志框架它提供了灵活的配置和强大的日志功能。与 Logback 类似Log4j 2 也支持异步日志可以提高日志的性能和吞吐量其实就是参考了Logback而设计出来的 6.1 与Log4J的关系 LOG4J和LOG4J2都是Java的日志框架它们都提供了强大的日志记录和管理功能。然而它们在设计和实现上有一些区别。 设计理念LOG4J是LOG4J2的前身它的设计目标是提供一个简单、灵活的日志框架。LOG4J2则是LOG4J的升级版它在LOG4J的基础上进行了重构和改进旨在提供更高的性能和更丰富的功能。性能LOG4J2相对于LOG4J在性能上有所提升。LOG4J2使用了异步日志记录机制可以在不阻塞应用程序的情况下进行日志记录从而提高了应用程序的性能。配置方式LOG4J使用基于属性的配置文件如log4j.properties或基于XML的配置文件如log4j.xml来配置日志记录器和输出目标。LOG4J2则引入了新的配置方式支持使用XML、JSON、YAML等格式的配置文件同时也支持使用编程API进行配置。插件支持LOG4J2引入了插件机制可以通过插件扩展日志框架的功能。LOG4J2提供了一些内置的插件如异步日志记录器、日志事件过滤器等同时也支持自定义插件。日志框架迁移由于LOG4J2在设计和实现上与LOG4J有所不同因此在迁移项目中使用LOG4J2时可能需要进行一些代码和配置的调整。 总的来说LOG4J2是LOG4J的升级版它在性能、配置方式和功能扩展方面有所改进。如果你正在开始一个新的项目或者希望提升现有项目的日志性能和功能那么LOG4J2可能是一个更好的选择。但如果你已经在使用LOG4J并且没有特别的需求那么继续使用LOG4J也是可以的。 6.2 默认配置 DefaultConfiguration类提供的默认配置 private volatile Configuration configuration new DefaultConfiguration();6.3 Log4j2的使用 6.3.1 使用log4j-api做门面 要使用 Log4j 2需要在项目中添加 Log4j 2 的依赖并配置 Log4j 2 的配置文件 1pom.xml dependencies!-- Log4j2门面API--dependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-api/artifactIdversion2.14.1/version/dependency!-- Log4j2日志实现--dependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-core/artifactIdversion2.14.1/version/dependency /dependencies2配置 Log4j 2 的配置文件位于类路径的根目录下。 log4j2.xml ?xml version1.0 encodingUTF-8? Configuration statusINFOAppenders!-- 定义一个名为Console的Appender将日志输出到控制台 --Console nameConsole targetSYSTEM_OUTPatternLayout pattern%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n //Console/AppendersLoggers!-- 根日志的级别被设置为 DEBUG--Root levelDEBUGAppenderRef refConsole //Root/Loggers /Configuration3代码中使用 import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.Test;public class Log4j2Test {private static final Logger LOGGER LogManager.getLogger(Log4j2Test.class);Testpublic void test(){LOGGER.fatal(fatal);LOGGER.error(error);LOGGER.warn(warn);LOGGER.info(info);LOGGER.debug(debug);LOGGER.trace(trace);} }结果 21:24:15.027 [main] FATAL com.clear.Log4j2Test - fatal 21:24:15.027 [main] ERROR com.clear.Log4j2Test - error 21:24:15.027 [main] WARN com.clear.Log4j2Test - warn 21:24:15.027 [main] INFO com.clear.Log4j2Test - info 21:24:15.027 [main] DEBUG com.clear.Log4j2Test - debug6.3.2 使用slf4j做门面 使用slf4j作为日志的门面使用log4j2作为日志的实现 1pom.xml dependencies!-- Log4j2门面API--dependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-api/artifactIdversion2.14.1/version/dependency!-- Log4j2日志实现--dependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-core/artifactIdversion2.14.1/version/dependency!-- 使用slf4j作为日志的门面使用log4j2来记录日志--dependencygroupIdorg.slf4j/groupIdartifactIdslf4j-api/artifactIdversion1.7.32/version/dependency!-- 为slf4j绑定日志实现 log4j2的适配器--dependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-slf4j-impl/artifactIdversion2.12.1/version/dependency /dependencies6.4 log4j2异步日志 要使用 Log4j 2 的异步日志功能你需要进行以下配置 1添加 Log4j 2 的异步日志依赖 pom.xml dependencygroupIdorg.apache.logging.log4j/groupIdartifactIdlog4j-async/artifactIdversion2.14.1/version /dependency2创建 Log4j 2 的配置文件 log4j2.xml并将其放置在类路径下 log4j2.xml ?xml version1.0 encodingUTF-8? Configuration statusWARNAppenders!-- 将日志输出到控制台并使用异步日志记录。 --Console nameConsole targetSYSTEM_OUTPatternLayout pattern%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n//Console/AppendersLoggersRoot levelinfoAppenderRef refConsole//Root/Loggers /Configuration3在代码中使用log4j的API记录日志 import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.Test;public class Log4j2Test {private static final Logger LOGGER LogManager.getLogger(Log4j2Test.class);Testpublic void test(){LOGGER.fatal(fatal);LOGGER.error(error);LOGGER.warn(warn);LOGGER.info(info);LOGGER.debug(debug);LOGGER.trace(trace);} }注意 ​ 异步日志可以提高性能但也可能会导致日志消息的顺序不一致。如果你需要确保日志消息的顺序请使用同步日志。 7 日志的打印 基本格式 必须使用参数化信息的方式 logger.debug(Processing ing trade with id:[{}] and symbol:[{}],id,symbol);不要进行字符串拼接那样会产生多个String对象占用空间影响性能。 错误示例 logger.debug(Processing ing trade with id:“ id ” symbol: symbol);ERROR影响到程序正常运行、当前请求正常运行的异常情况 打开配置文件失败 所有第三方对接的异常包括第三方返回异常码 所有影响功能使用的异常包括 SQLException 和除了业务异常之外的所有异常RuntimeException和Exception 不应该出现的情况比如使用阿里云传图片但是未响应 如果有Throwable信息需要记录完整的堆栈信息 log.error(获取用户[{}]的用户信息时出错, userName, e);说明 ​ 如果进行了抛出异常操作请不要记录error日志由最终处理方进行处理 反例错误示例 try{... }catch(Exception e){String errorMessage String.format(Error while reading information of user [%s],userName);logger.error(errorMessage, e);throw new UserServiceException(errorMessage, e); }WARN不应该出现但是不影响程序、当前请求正常运行的异常情况 有容错机制的时候出现的错误情况 找不到配置文件但是系统能自动创建配置文件比如我们第一次格式化Hadoop时就会出现WARN并帮我们创建日志 即将接近临界点的时候比如缓存池占用达到警戒线业务异常的记录比如用户锁定异常 INFO系统运行信息 Service方法中对于系统/业务状态的变更主要逻辑的分步骤1.初始化什么 2.加载什么外部接口的部分客户端请求参数REST/WS调用第三方时的调用参数和调用结果对于复杂的业务逻辑需要进入日志打点以及埋点记录调用其它第三方服务时所有的出参和入参是必须要记录的因为我们很难追溯第三方的错误 说明 ​ 并不是所有的service都进行出入口大点记录单一、简单service是没有意义的job除外job需要记录开始、结束 反例 public List listByBaseType(Integer baseTypeId){log.info(开始查询基地);BaseExample e new BaseExample();BaseExample.Criteria ctr e.createCriteria();ctr.andIsDeleteEqualTo(IsDelete.USE.getValue());Options.doIfPresent(baseTypeId, ctr::andIsDeleteEqualTo);log.info(查询基地结束);return baseRepository.selectByExample(e); }DEBUG可以填写所有的想知道的信息但是也需要填写有意义的信息 生成环境需要关闭DEBUG信息 如果在生产环境情况下需要开启DEBUG需要使用开关进行管理不能一直开启 说明 ​ 如果代码中出现以下代码可以进行优化 ​ 1.获取用户基本薪资 ​ 2.获取用户休假情况 ​ 3.计算用户所得薪资 logger.debug(开始获取员工[{}] [{}]年基本薪资, employee, year); logger.debug(获取员工[{}] [{}]年基本薪资为[{}], employee, year, basicSalary); logger.debug(开始获取员工[{}] [{}]年[{}]月休假情况, employee, year, month); logger.debug(员工[{}] [{}]年[{}]月年假/病假/事假为[{}]/[{}]/[{}], employee, year, month, annualLeaveDays, sickLeaveDays, noPayLeaveDays); logger.debug(开始计算员工[{}] [{}]年[{}]月应得薪资, employee, year, month); logger.debug(员工[{}] [{}]年[{}]月应得薪资为[{}], employee, year, month, actualSaraly);TRACE特别详细的系统运行完全信息业务代码中不要使用除非有特殊用意否则使用DEBUG代替
http://www.hkea.cn/news/14541473/

相关文章:

  • 网站建设存在的问题及建议班级优化大师的优点
  • 谷歌网站入口河源市做网站
  • 东莞电商建站vps 用ip可以访问网站么
  • 招远水利建设工程公司网站wordpress 如何调试
  • 网站上放百度地图免费高清无专码区直接看
  • 网站富文本的内容怎么做百度青岛代理公司
  • 免费企业模板网站iis建立网站
  • 佛山seo网站排名石家庄商城网站搭建多少钱
  • 苏州做网站公网站如何收录
  • php与mysql网站开发...获取网站后台地址
  • 网站开发php程序员做响应网站
  • 启航做网站好吗太原网站建设鸣蝉公司
  • 如何设置网站标题谷歌做新媒体运营的网站
  • html5 网站模板 米半年工作总结
  • 昊杰南宫网站建设青岛网站开发中心
  • 手机网站建设和个人免费网站建设教程
  • 网站建设费计入管理费用小程序开发一般多少钱
  • 品牌网站设计企业服务h5怎么制作小程序
  • 网站定制一般价格多少怎样给自己的店子做网站
  • 怎样搭建个人网站电子商务网站建设实训报告文章
  • wordpress 建站很简单单页淘宝客网站
  • 金寨县建设局网站网站开发需要用到哪些技术
  • 左右左布局网站建设网站建设的计划
  • 比较出名的wordpress网站怎么查看网站的点击率
  • 宁夏交通建设有限公司网站百度识图搜索
  • 电子商务网站建设视频工程网站怎么做
  • 佛山市南海区建设局网站图片设计与制作软件下载
  • 做网站预付款 怎么做账网站模板怎样发布
  • 注册网站域名有什么用长尾关键词有哪些
  • 合肥做装修哪个网站好高凡玉中国互联网协会