[Java的日志] P2: Log4j的集成到软件

从博客东黄长发发表的文章, 是作者的同意.

大家好, 在所有前 ([Java的日志] P1: 测井软件开发中的重要性) 我分享了关于 日志记录的重要性 有的 原则 登录时. 在本文中,我将指导您 如何将基本日志模块集成到应用程序中. 您应该养成从最小的角度将日志记录集成到所有个人软件中的习惯, 会发现它的方便,软件变得更专业, 在做大型软件的时候也会觉得比较熟悉和容易.
Mình sẽ hướng dẫn cách tích hợp Log4j vào một chương trình Java的 nhỏ. Trong bài này mình sẽ hướng dẫn cấu hình bằng file XML, các bạn hoàn toàn có thể tìm hiểu và thử cấu hình bằng JSON, YAML, Properties cũng với cấu trúc tương tự. Trong phạm vi bài viết này, để đơn giản nhất có thể nên mình sẽ không sử dụng 专家, thay vào đó sẽ dùng cách add lib vào project thông thường 😀

Trước tiên các bạn cần tải gói jar log4j, ở đây mình sẽ sử dụng phiên bản Log4j的 2.7.
Link download: http://archive.apache.org/dist/logging/log4j/2.7/apache-log4j-2.7-bin.zip
Trong file nén này có rất nhiều gói jar, nhưng để ghi được log thì chỉ cần 2 gói coreAPI là đủ.
后 2 gói jar trên, các bạn add vào project và bắt đầu code. Nếu ai chưa biết các add lib .jar vào project thì tự google nhé, đây là kiến thức cơ bản 🙂

Trước tiên mình tạo 1 文件 Main.java cho ví dụ này và khai báo một đối tượng logger như đoạn code dưới.

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
 
public class Main {
    static Logger logger = LogManager.getLogger(Main.class);
    public static void main(String[] args) {
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
    }
}

Sau đó tạo 1 文件log4j2.xml 并放入文件夹资源 项目的 (确保文件名和目录名正确). 这将是用于日志记录的配置文件.
像图像这样的结构文件

首先,我将配置一个 追加器 写入屏幕的最简单的日志 安慰

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss a} %highlight{%-5level} [%15.15t] %style{%40C{1.}.%-20M}{cyan} : %msg%n"/>
        </Console>
    </Appenders>
 
    <Loggers>
        <Root level="debug">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

附加程序 声明定义记录配置位置的连接器, 日志格式是什么?.
我已经在上面声明 1 样式附加器 Console, 命名的 Console 带输出目的地 SYSTEM_OUT表示命令行屏幕. 在里面,我定义了更多的格式 1 输出时日志行会包含哪些信息?.
您可以在以下位置查看有关这些格式的更多详细信息 文档Log4j的
https://logging.apache.org/log4j/2.x/manual/layouts.html#PatternLayout
伐木工 声明使用条件 追加器. 如上所述,我将保留记录所有内容的条件 级别日志调试 以后会写下来 安慰
运行程序并查看结果

2019-07-12 22:56:33 PM INFO  [           main]                               n.t.l.Main.main                 : info
2019-07-12 22:56:33 PM WARN  [           main]                               n.t.l.Main.main                 : warn
2019-07-12 22:56:33 PM ERROR [           main]                               n.t.l.Main.main                 : error

虽然文件中的代码 Main.java 我只是用像这样的文本调用日志记录功能 “信息”, “警告”, “错误”. 但是显示的日志是完整的 执行时间处理时间,日志级别 (信息, 警告, 错误), 包类, 方法, 很方便查看日志. 是因为里面的配置 PatternLayout
同样,我会配置更多 1 追加器 ghi 日志 ra 文件 通过在下面添加 appender

<RollingFile name="File" fileName="logs/server.log"
             filePattern="logs/$${date:yyyy-MM}/%d{dd}/server.%i.log">
    <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss a} %-5level [%t] %logger{36}.%M : %msg%n"/>
    <Policies />
</RollingFile>

结果, 随着日志写入文件,我通常会完整地显示它 包类 并且不要对齐空格以避免多余的空间增益

2019-07-12 23:08:58 PM INFO [main] net.tunghuynh.logging.Main.main : info
2019-07-12 23:08:58 PM WARN [main] net.tunghuynh.logging.Main.main : warn
2019-07-12 23:08:58 PM ERROR [main] net.tunghuynh.logging.Main.main : error

在上述日志文件的附加程序中, 我另外配置了 filePattern 自动 按日期剪切日志文件
所以只需几步, 你可以 记录 你的程序的标准. 如果你想要更清晰, 你可以配置更多 追加器 分割成文件 日志信息, 日志错误, 日志调试 分开以便于控制并替换上面的通用日志.

<RollingFile name="FileInfo" fileName="logs/info.log"
             filePattern="logs/$${date:yyyy-MM}/%d{dd}/info.%i.log">
    <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss a} %-5level [%t] %logger{36}.%M : %msg%n"/>
    <LevelRangeFilter minLevel="INFO" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
    <Policies />
<RollingFile name="FileWarn" fileName="logs/warn.log"
             filePattern="logs/$${date:yyyy-MM}/%d{dd}/warn.%i.log">
    <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss a} %-5level [%t] %logger{36}.%M : %msg%n"/>
    <LevelRangeFilter minLevel="WARN" maxLevel="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
    <Policies />
<RollingFile name="FileError" fileName="logs/error.log"
             filePattern="logs/$${date:yyyy-MM}/%d{dd}/error.%i.log">
    <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss a} %-5level [%t] %logger{36}.%M : %msg%n"/>
    <LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
    <Policies />
</RollingFile>

去这里, 开始看到 追加器 具有类似的配置,例如保存路径 日志, 图案布局, 如果我现在需要修复它,我将不得不一个一个地修复它 追加器, 所以我们可以声明 财产 中的值定义和重用 追加器

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Properties>
        <Property name="patternLayout">%d{yyyy-MM-dd HH:mm:ss a} %-5level [%t] %logger{36}.%M : %msg%n</Property>
        <Property name="logPath">logs</Property>
    </Properties>
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout
                    pattern="%d{yyyy-MM-dd HH:mm:ss a} %highlight{%-5level} [%15.15t] %style{%40C{1.}.%-20M}{cyan} : %msg%n"/>
        </Console>
        <RollingFile name="FileInfo" fileName="${logPath}/info.log"
                     filePattern="${logPath}/$${date:yyyy-MM}/%d{dd}/info.%i.log">
            <PatternLayout pattern="${patternLayout}"/>
            <LevelRangeFilter minLevel="INFO" maxLevel="INFO" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies />
        </RollingFile>
        <RollingFile name="FileWarn" fileName="${logPath}/warn.log"
                     filePattern="${logPath}/$${date:yyyy-MM}/%d{dd}/warn.%i.log">
            <PatternLayout pattern="${patternLayout}"/>
            <LevelRangeFilter minLevel="WARN" maxLevel="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies />
        </RollingFile>
        <RollingFile name="FileError" fileName="${logPath}/error.log"
                     filePattern="${logPath}/$${date:yyyy-MM}/%d{dd}/error.%i.log">
            <PatternLayout pattern="${patternLayout}"/>
            <LevelRangeFilter minLevel="ERROR" maxLevel="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
            <Policies />
        </RollingFile>
    </Appenders>
    .......
</Configuration>

所以现在演出的时候 大发展 向上, 功能数量 职业增加, 如果所有日志仍然写入同一个文件,那将是非常 难以控制, 那是我们需要的时候 嘉日志 根据 业务 具体来说.
但并非每个企业都需要单独的日志文件, 正如我在上一篇文章中提到的,我们将分离日志 重要业务处理很多 出方便控制. 在这里我创造更多 3 类 新模拟 3 业务 出现, 还会 记录 1 类 以职业为例.

public class BusinessA {
    Logger logger = LogManager.getLogger(getClass());
    public BusinessA(){
        logger.info("Info From BusinessA");
        logger.warn("Warn From BusinessA");
        logger.error("Error From BusinessA");
    }
}
public class BusinessB {
    Logger logger = LogManager.getLogger(getClass());
    public BusinessB(){
        logger.info("Info From BusinessB");
        logger.warn("Warn From BusinessB");
        logger.error("Error From BusinessB");
    }
}
public class BusinessC {
    Logger logger = LogManager.getLogger(getClass());
    public BusinessC(){
        logger.info("Info From BusinessC");
        logger.warn("Warn From BusinessC");
        logger.error("Error From BusinessC");
    }
}

然后加 追加器 单独的课程日志 商业A 并使用新创建的 appender 声明该类

.....
    <RollingFile name="LogBusinessA" fileName="${logPath}/business-a.log"
                 filePattern="${logPath}/$${date:yyyy-MM}/%d{dd}/business-a.%i.log">
        <PatternLayout pattern="${patternLayout}"/>
        <Policies />
    </RollingFile>
.....
<Loggers>
        <Logger name="net.tunghuynh.logging.BusinessA" level="debug" additivity="false">
            <AppenderRef ref="LogBusinessA"/>
            <AppenderRef ref="Console"/>
        </Logger>
        ........
    </Loggers>

居住 商业A 我会写下来 1 文件 私人日志并写入屏幕 安慰 级别日志来自 调试 开始
结果仍然会记录所有的完整日志 3 业务 屏幕上新添加的 安慰, 但日志 商业A 只写入文件 business-a.log 而不是出现在像这样的一般日志文件中 info.log, warn.log, error.log

如果您的业务是在 许多类 然后 包揽业务 并且完全可配置的日志指向包名 记录包中的所有类 那里
事情没有那么简单, 当节目变成 1 很棒的软件或应用程序, 处理次数增加 导致每个业务的日志文件也要多写,使得容量越来越大, 如果删除它,日志将丢失, 如果不删除它,将很难读取文件或跟踪日志, 现在我们需要 切割原木.
要剪切日志文件,是的 2 从 普通切割即根据 容量到......的时候, 我通常 结合 所有 2 这边走. 日志切割示例 容量超过10Mb按日期切割日志, 每天都会砍日志 1 这是一天的结束 保存到私人文件夹, 对于处理量大的事务,可以按小时切日志. 例子一 追加器 按日期和容量配置日志切割,如下所示

<RollingFile name="LogBusinessA" fileName="${logPath}/business-a.log"
             filePattern="${logPath}/$${date:yyyy-MM}/%d{dd}/business-a.%i.log">
    <PatternLayout pattern="${patternLayout}"/>
    <Policies>
        <TimeBasedTriggeringPolicy/>
        <SizeBasedTriggeringPolicy size="10 MB"/>
    </Policies>
    <DefaultRolloverStrategy max="10"/>
</RollingFile>

另外,难免会被系统刷屏, 或受苦 1 不断重试出问题了,虽然日志已经被切割成很多文件了,但是文件数量 仍然出生太多 导致硬盘全挂服务器. 所以上面我添加了配置DefaultRolloverStrategy 只允许保存10 文件 在1 日志字符串, 如果超过文件数量,旧文件将自动逐渐删除.
这些配置值也需要在其他appender中复用,所以也可以给财产 如上.

所以你的程序已经 内置基础标准日志模块 足以使用和查看 chuyên nghiệp hơn rất nhiều. 🙂

Đây là bài hướng dẫn tích hợp nên mình upload luôn source cho các bạn tiện tìm hiểu. Ai dùngIntelliJ IDEthì có thể open project là có luôn cấu hình lib trong project Các bạn có thể download source ở cuối bài nhé.

Nhưng đó mới chỉ đáp ứng được việc ghi log ra file, đôi khi việc đọc log trong file cũng gặp không ít bất tiện. Ví dụ khi cần kiểm soát các thao tác của user đăng nhập 软件, 你使用什么功能?, 在软件上进行哪些数据操作?, 一般来说,需要数据 链环 跟着 登录会话 或者特定的业务流程需要将日志保存到 数据库 或为方便起见的类似架构 数据查询.
这篇文章很长,所以我会指导你 异步记录到数据库 在下一部分

下载代码 Log4JExample.zip