logback框架和日志分离管理

一、日志框架

1. 什么是日志框架?

日志框架 是一种软件组件,负责记录应用程序在运行时生成的日志信息。日志信息通常包括错误、警告、调试信息和其他重要的运行状态,帮助开发者和运维人员监控和调试应用。

2. 日志框架的作用

  • 记录运行信息:捕获程序执行中的重要事件和状态信息,便于追踪问题和性能瓶颈。
  • 故障排查:当应用发生错误时,日志记录提供了上下文信息,有助于快速定位和解决问题。
  • 性能监控:记录性能指标,帮助分析系统的运行效率。
  • 审计和合规:某些应用需要记录操作历史以满足安全审计和合规要求。
  • 可追溯性:通过日志,用户可以追溯到具体的操作和系统状态。

3. 常见的日志框架

3.1. Log4j

最早的 Java 日志框架之一,提供了强大的日志记录功能。
支持多种输出目标(控制台、文件、数据库等),灵活的配置方式,但在性能上相对较低。
目前有 Log4j 1 和 Log4j 2,后者在性能和功能上进行了显著改进。

3.2. Logback

由 Log4j 的创始人开发,是 SLF4J 的原生实现,性能优越(比log4j强)。
支持异步日志记录、自动重载配置文件、灵活的输出格式等。

3.3. java.util.logging (JUL)

Java 官方自带的日志框架,简单易用,但功能和灵活性相对较弱。
默认与 JDK 一起提供,不需要额外依赖,但通常被其他日志框架替代。
java.util.logging 适合小型项目和快速集成,但在复杂应用中可能无法满足需求。

3.4. SLF4J(日志门面)(Simple Logging Facade for Java)

SLF4J 是一个日志门面,提供了统一的日志 API,允许开发者在不同的日志框架之间切换。可以与多种日志框架(如 Logback、Log4j)兼容使用,提供简洁的 API,易于使用。将依赖从具体日志框架转移到统一接口,简化了依赖管理。不处理日志,只是一层抽象,实际的日志处理依赖于其他框架。

4.常见的日志级别

  • TRACE:最细粒度的信息,通常用于追踪问题。
  • DEBUG:调试信息,通常在开发和测试时使用。
  • INFO:正常运行的信息。
  • WARN:警告信息,表示可能出现的问题。
  • ERROR:错误信息,表示发生了错误。
  • FATAL:严重错误,表示应用程序无法继续运行。

5.讲讲logback

Logback 主要由三个核心模块构成:
logback-core:核心模块,提供基本的日志记录功能。
logback-classic:经典模块,提供 SLF4J(Simple Logging Facade for Java)实现,支持多种日志级别和输出格式。
logback-access:用于 Servlet 环境中的访问日志记录。

5.1. logback-core

logback-core 是 Logback 的基础模块,提供了日志记录的核心功能和通用的 API。它包含了 Logback 的一些基本组件,比如 Appender、Layout 和 Filter。它定义了基本的日志记录行为。提供了其他模块(如 logback-classic 和 logback-access)所需的共享功能。
一般情况下,不需要直接与 logback-core 进行交互,因为它是 Logback 其他模块的基础。

5.2. logback-classic

logback-classic 是 Logback 的经典模块,它实现了 SLF4J的接口。这个模块是最常用的,通常用于大多数 Java 应用程序。
提供对 SLF4J API 的实现,支持多种日志级别(如 TRACE、DEBUG、INFO、WARN、ERROR、FATAL)。
允许配置日志输出到不同的目标(控制台、文件等)。
支持日志格式化和过滤器。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 

public class MyApp {
    private static final Logger logger = LoggerFactory.getLogger(MyApp.class);

    public static void main(String[] args) {
        logger.info("应用程序启动");
        try {
            int result = 10 / 0;
        } catch (Exception e) {
            logger.error("发生错误:{}", e.getMessage());
        }
        logger.info("应用程序结束");
    }

5.3. logback-access

logback-access 是 Logback 的一个扩展模块,专门用于 Servlet 环境中的访问日志记录。它允许你记录 HTTP 请求和响应的相关信息。
提供一个 Servlet 过滤器,可以捕获和记录请求信息。
允许配置请求和响应日志的输出格式。

public class LoginServlet extends HttpServlet {
    private static final Logger logger = LoggerFactory.getLogger(LoginServlet.class);

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        // 假设的用户验证逻辑
        boolean isAuthenticated = authenticateUser(username, password);

        if (isAuthenticated) {
            logger.info("用户 {} 登录成功", username);
            response.getWriter().write("登录成功");
        } else {
            logger.warn("用户 {} 登录失败,密码错误", username);
            response.getWriter().write("登录失败");
        }
    }

    private boolean authenticateUser(String username, String password) {
        return "admin".equals(username) && "password".equals(password);
    }

5.4.学到此处的疑惑?

上述在http交互中,好像直接使用logback classic也可以,为什么还多此一举多个logback access?或者说logback access优越在哪里?
举个例子作比较:
1.假设我们在处理用户登录时,使用 Logback Classic 记录日志:

public class LoginServlet extends HttpServlet {
    private static final Logger logger = LoggerFactory.getLogger(LoginServlet.class);

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        boolean isAuthenticated = authenticateUser(username, password);

        if (!isAuthenticated) {
            // 手动记录登录失败的信息
            logger.warn("登录失败,用户名: {}, 请求方法: {}, 请求路径: {}", 
                username, request.getMethod(), request.getRequestURI());            ---注意这里
            response.getWriter().write("登录失败");
        } else {
            response.getWriter().write("登录成功");
        }
    }

    private boolean authenticateUser(String username, String password) {
        return "admin".equals(username) && "password".equals(password);
    }
}

输出结果:

2024-10-21 10:00:00 WARN  [http-nio-8080-exec-1] LoginServlet [LoginServlet.java:25] 
登录失败,用户名: user, 请求方法: POST, 请求路径: /login

2.在同样的登录失败场景中,使用 Logback Access:

public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        boolean isAuthenticated = authenticateUser(username, password);

        if (!isAuthenticated) {
            // 使用 Logback Access 自动记录 HTTP 请求信息
            LogbackAccessFilter filter = new LogbackAccessFilter();
            filter.logAccess(request, response, "登录失败,用户名: " + username);     ---和上面比一下
            response.getWriter().write("登录失败");
        } else {
            response.getWriter().write("登录成功");
        }
    }

    private boolean authenticateUser(String username, String password) {
        return "admin".equals(username) && "password".equals(password);
    }
}

输出结果

2024-10-21 10:00:00 WARN  [http-nio-8080-exec-1] AccessLogger [LogbackAccess.java:123] 
请求方法: POST, 请求路径: /login, 用户名: user, 状态码: 401, 响应时间: 150ms

3.比较分析

输出内容:
Logback Classic:记录了用户名、请求方法和请求路径。这些信息帮助理解发生了什么,但缺乏对请求状态的详细描述。
Logback Access:自动记录请求方法、请求路径、状态码和响应时间等多种信息,使得分析请求情况更加全面。

代码简洁性:
Logback Classic:需要手动提取和记录请求相关的信息,代码较冗长且容易出错。
Logback Access:自动处理 HTTP 请求的记录,代码更简洁,专注于业务逻辑。

上下文信息:
Logback Classic:需要自己管理所有的请求上下文信息,容易遗漏关键信息。
Logback Access:全面捕获 HTTP 请求的上下文信息。

性能优化:
Logback Classic:未针对 HTTP 请求进行优化,记录过程相对较慢。
Logback Access:经过优化,专门为 HTTP 请求设计,可以更高效地记录访问信息。

6.举个完整示例

6.1. 项目结构 (登录为例)

my-login-app
│
├── src
│   ├── main
│   │   ├── java
│   │   │   ├── LoginServlet.java
│   │   │   └── MyApp.java
│   │   └── resources
│   │       └── logback.xml
│   └── webapp
│       └── index.html
└── pom.xml

6.2. Maven 依赖

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

6.3. Logback 配置文件

在 src/main/resources 目录下创建 logback.xml 文件,内容如下:

<configuration>

    <!-- 配置 ConsoleAppender,用于输出日志到控制台 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} [%file:%line] - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- 配置 AccessAppender,用于处理 HTTP 访问日志 -->
    <appender name="ACCESS" class="ch.qos.logback.access.Appender">
        <encoder>
            <pattern>%h %l %u %t "%r" %s %b %D</pattern> <!-- 自定义输出格式 -->
        </encoder>
    </appender>

    <!-- 配置日志级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT" />  <!-- 将控制台输出连接到根日志 -->
    </root>

    <logger name="ch.qos.logback.access" level="DEBUG">
        <appender-ref ref="ACCESS" />  <!-- 将访问日志连接到特定日志级别 -->
    </logger>

</configuration>

6.4.Logback 的 JDBCAppender

将日志输出到数据库中
1.先数据库建表:

CREATE TABLE logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    timestamp TIMESTAMP NOT NULL,
    level VARCHAR(10) NOT NULL,
    thread VARCHAR(50),
    logger VARCHAR(100),
    message TEXT
);

2.配置xml:

<configuration>

    <!-- JDBC Appender -->
    <appender name="JDBC" class="ch.qos.logback.classic.db.JDBCAppender">
        <connectionSource>
            <driverClass>com.mysql.cj.jdbc.Driver</driverClass>  
            <url>jdbc:mysql://localhost:3306/database</url>  
            <user>username</user>  
            <password>password</password>  
        </connectionSource>
        
        <encoder>
            <pattern>%date %level [%thread] %logger{10} %msg%n</pattern> 
        </encoder>
    </appender>

    <root level="debug">
        <appender-ref ref="JDBC" />  <!-- 引用 JDBC Appender -->
    </root>
</configuration>

3.数据存储结果:

id	timestamp	        level	thread	logger	                    message
1	2024-10-22 10:00:00	INFO	main	com.example.LoginServlet	用户 admin 登录成功
2	2024-10-22 10:01:00	WARN	main	com.example.LoginServlet	登录失败,用户名: user
3	2024-10-22 10:02:00	ERROR	main	com.example.LoginServlet	数据库连接失败

已经集成了与数据库操作,很方便

二、日志分离管理

1. 日志分类

将日志根据其性质和使用场景进行分类,常见的分类方式:

  • 操作日志:
    记录用户的登录和登出时间、IP 地址、操作行为(如数据查询、修改、删除等)。
    例如,记录如下信息:
  2024-10-22 10:00:00 INFO 用户 admin 登录成功, IP 地址: 192.168.1.1
  2024-10-22 10:05:00 INFO 用户 admin 修改了文件 config.xml
  • 安全日志:
    记录安全相关事件,如访问控制失败、入侵检测、恶意软件检测等
  2024-10-22 10:15:00 WARN 用户 user 尝试登录失败, 原因: 密码错误
  2024-10-22 10:20:00 WARN 检测到异常登录活动: 用户 admin 从异常 IP 地址 203.0.113.45 登录
  • 审计日志:
    记录对敏感数据的访问、修改、删除操作
  2024-10-22 10:30:00 INFO 用户 admin 访问敏感文件 sensitive_data.txt
  2024-10-22 10:35:00 INFO 用户 admin 删除了用户账户 user123
  • 系统日志:
    记录系统启动、关闭、升级、故障和配置变更等事件。
  2024-10-22 10:00:00 INFO 系统启动
  2024-10-22 11:00:00 INFO 配置文件 config.yml 被修改

2.角色分离与权限管理

2.1. 角色理解

废除超级管理员,将权限分配。 三员对应三角色
1.系统管理员(配置):
主要负责系统的资源和运行进行配置、控制和管理,包括用户身份、系统资源配置、系统加载和启动、系统运行的异常处理、数据和设备的备份与恢复等。

2.安全管理员(授权):
主要对系统中的安全策略进行配置,包括安全参数的设置,主体、客体进行统一安全标记,对主体进行授权,配置可信验证策略等。

3.审计管理员(审计):
主要负责对审计记录进行分析,并根据分析结果进行处理,包括根据安全审计策略对审计记录进行存储、管理和查询等。

2.2.具体管理

1.系统管理员:
主要负责系统的日常运行维护工作。包括网络设备、安全保密产品、服务器和用户终端、操作系统数据库、涉密业务系统的安装、配置、升级、维护、运行管理;网络和系统的用户增加或删除;网络和系统的数据备份、运行日志审查和运行情况监控;应急条件下的安全恢复。

2.安全管理员:
主要负责系统的日常安全保密管理工作。包括网络和系统用户权限的授予与撤销,用户操作行为的安全设计,安全保密设备管理,系统安全事件的审计、分析和处理,应急条件下的安全恢复。

3.审计管理员:
主要负责对系统管理员和安全保密员的操作行为进行审计、分析和监督检查,及时发现违规行为并定期向系统安全保密管理机构汇报情况。

系统管理员、安全保密管理员和安全审计员不能以其他用户身份登陆系统,不能查看和修改任何业务数据库中的信息,不能删改日志内容。
同一设备或系统的系统管理员和安全审计员不能由同一人兼任,安全保密管理员和安全审计员不得由同一人兼任。

2.3. 日志中的三员管理

  • 系统管理员:
    负责日志管理系统的配置和维护,确保日志的准确性和完整性。管理员可以进行系统配置、日志存储路径设置和用户权限管理。
    权限:
    访问所有日志数据,包括操作日志、审计日志和安全事件日志。
    配置日志记录参数和存储策略。

  • 操作员:
    负责日常操作和监控,检查系统日志以确保系统正常运行,及时发现异常并上报。
    权限:
    访问特定的操作日志和系统事件日志,但不能访问敏感数据或审计日志。
    可以生成报告和查看操作历史。

  • 审计员:
    进行定期审计和检查,分析日志数据以识别潜在的安全问题。
    权限:
    访问所有日志数据,进行审计和分析。
    不能进行日志修改或系统配置。

3.日志审计与监控

3.1.简单解释:

日志监控:主要关注实时跟踪系统的状态,及时捕获异常、错误或特定事件,以便快速响应。
日志分析:旨在深入挖掘日志数据,识别趋势、模式和潜在的安全问题,通常在后续阶段进行

3.2.ELK

ELK 是ElasticSearch开源生态中提供的一套完整日志收集、分析以及展示的解决方案,是三个产品的首字母缩写,分别是ElasticSearch、Logstash 和 Kibana。

  • 1.ElasticSearch ,它是一个近实时(NRT)的分布式搜索和分析引擎,它可以用于全文搜索,结构化搜索以及分析。它是一个建立在全文搜索引擎 Apache Lucene 基础上的搜索引擎,使用 Java 语言编写。
  • 2.Logstash ,它是一个具有近实时(NRT)传输能力的数据收集、过滤、分析引擎,用来进行数据收集、解析、过滤,并最终将数据发送给ES。
  • 3.Kibana ,它是一个为 ElasticSearch 提供分析和展示的可视化 Web 平台。它可以在 ElasticSearch 的索引中查找,交互数据,并生成各种维度表格、图形以及仪表盘。

    比较复杂且长,可以算另一个领域来看,这里先不说

4.Linux的日志分离

4.1.Linux日志类型

1.【内核及系统日志】
2.【用户日志】
3.【程序日志】

分类 说明
daemon 后台进程相关的信息
kern 内核产生的信息
lpr 打印系统产生的信息
authpriv 安全认证信息
cron 定时计划任务相关的信息
mail 邮件相关的信息
syslog 日志服务本身的信息
news 新闻系统
local0~local7 8个系统保留的类,供其他程序使用或用户自定义

4.2.常见日志

Linux系统本身和大部分服务器程序的日志文件默认情况下都放置在目录“/var/log”中。一部分程序公用一个日志文件,一部分程序使用单个日志文件,而有些大型服务器程序由于日志文件不止一个,所以会在“/var/log”目录中建立相应的子目录来存放日志文件,这样既保证了日志文件目录的结构清晰,又可以快速地定位日志文件。有相当一部分日志文件只有root用户才有权限读取,这保证了相关日志信息的安全性。

日志路径 作用
/var/log/cron 记录了系统定时任务相关的日志
/var/log/cups/ 记录打印信息的日志
/var/log/dmesg 记录了系统在开机时内核自检的信息。也可以使用dmesg命令直接查看内核自建信息
/var/log/btmp 记录错误登录的日志。这个文件是二进制文件,不能直接vi查看,而要使用lastb命令查看。
/var/log/lastlog 记录系统中所有用户最后一次的登录时间的日志。这个文件也是二进制文件,不能直接vi,而要使用lastlog命令查看
/var/log/mailog 记录邮件信息
/var/log/message 记录系统重要信息的日志。这个日志文件中会记录Linux系统的绝大多数重要信息,如果系统出现问题时,首先要检查的就应该是这个日志文件。
/var/log/secure 记录验证和授权方面的信息,只要涉及账户和密码的程序都会记录。比如说系统的登录,ssh的登陆,su切换用户,sudo授权,甚至添加用户和修改用户密码都会记录在这个日志文件中。
/var/log/wtmp 永久记录所有用户的登录、注销信息,同时记录系统的启动、重启、关机事件。同样这个文件也是一个二进制文件,不能直接vi,而需要使用last命令来查看。
/var/run/utmp 记录当前已经登录的用户的信息。这个文件会随着用户的登录和注销而不断变化,只记录当前登录用户的信息。同样这个文件不能直接vi,而要使用w,who,users等命令来查询。

4.3.日志级别

比普通的日志多几个级别:

编码 优先级 严重性
7 debug 信息对开发人员调试应用程序有用,在操作过程中没用
6 info 正常的操作信息,可以收集报告,测量吞吐量等
5 notice 注意,正常但重要的事件
4 warning 警告,如果不采取措施,将会发生错误,例如文件系统已使用90%
3 err 错误,阻止某个模块或程序的功能不能正常使用
2 crit 关键错误,已经影响到整个系统或软件不能正常工作
1 alert 警报,需要立即修改
0 emerg 紧急,内核崩溃等严重信息

4.4.日志轮换

把旧的日志删除,轮换新的日志内容

参数 参数说明
daily 日志的轮替周期是每天
weekly 日志的轮替周期是每周
monthly 日志的轮替周期是每月
rotate 数字
compress 日志轮替时,旧的日志进行压缩
create mode owner group 建立新日志,同时指定新日志的权限与所有者和所属组。如create 0600 root utmp
mail address
missingok 如果日志不存在,则忽略该日志的警告信息
notifempty 如果日志为空文件,则不进行日志轮替
minsize 大小 日志轮替的最小值。也就是日志一定要达到这个最小值才会轮替,否则就算时间达到也不轮替
size 大小
dateext 使用日期作为日志轮替文件的后缀。如secure-20241025

PS:logback也可以实现分离,但要单独对类在xml里面进行设置;目前我还在找解决办法

posted @ 2024-10-22 15:17  20222320  阅读(20)  评论(0编辑  收藏  举报