1. 日志采集
日志采集是指在软件系统、网络设备、服务器或其他IT基础设施中自动收集日志文件和事件信息的过程。这些日志通常包含了时间戳、事件类型、源和目标信息、错误代码、用户操作记录等关键数据。日志采集的目的是为了监控系统运行状态、分析系统性能、审计用户行为、故障排查和安全监控等。
日志采集通常涉及以下几个关键步骤:
-
日志生成:系统或应用程序在运行过程中产生日志。
-
日志存储:日志被保存在本地文件系统、数据库或其他存储介质中。
-
日志收集:使用特定的工具或服务将分散在不同位置的日志集中到一个或多个中心位置。
-
日志传输:将收集的日志数据通过网络传输到日志分析系统或存储系统。
-
日志处理:对日志数据进行格式化、过滤、聚合等处理,以便于分析和存储。
-
日志分析:使用日志分析工具对收集的日志数据进行分析,以识别模式、趋势、异常行为或安全威胁。
-
日志监控和告警:实时监控日志数据,并在检测到特定事件或异常时触发告警。
-
日志保留:根据合规性和审计要求,日志数据需要被保留一定时间。
2. 日志框架
一些典型的日志框架如下:
-
JUL:
java.util.logging
(简称JUL)是Java平台的一部分,它是一个轻量级的日志框架,提供了日志记录的基础设施。JUL是Java SE标准库的一部分,因此不需要额外的库就可以在任何Java应用程序中使用它。 -
Logback:Logback是一个流行的Java日志框架,由Log4j的创始人Ceki Gülcü和另一位Log4j贡献者Sébastien Pennec设计。
-
Log4j:Log4j是一个由Apache软件基金会维护的开源日志记录工具,它是Java语言中广泛使用的日志框架之一。
-
Log4j2:作为Log4j的继任者,在性能和功能上都有显著的提升。
-
logstash:Logstash是一个开源的服务器端数据处理管道,它能够从多个来源采集数据,转换数据,然后将数据发送到“数据库”。
-
Slf4j:SLF4J(Simple Logging Facade for Java)是一个为Java提供简单日志抽象的API。它并不是一个具体的日志框架,而是一个日志门面,允许开发者在代码中使用统一的API来记录日志,而不必直接依赖于具体的日志实现(如Log4j、Logback或Java Util Logging等)
3. 实例
3.1 JUL
JDK1.4具有的原生日志框架(不建议使用)。
package com.xiaokai;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
/**
* Author:yang
* Date:2024-11-19 10:25
*/
public class JULExample {
private static final Logger logger = Logger.getLogger(JULExample.class.getName());
public static void main(String[] args) {
// 创建一个控制台处理器,并设置格式器
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setFormatter(new SimpleFormatter());
logger.addHandler(consoleHandler);
logger.setLevel(Level.INFO);// 设置日志级别为ALL,其他级别为FINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE
// 记录日志
logger.log(Level.INFO, "This is an info message");
logger.log(Level.SEVERE, "This is a severe message");
}
}
测试结果:
十一月 19, 2024 10:30:44 上午 com.xiaokai.JULExample main
信息: This is an info message
十一月 19, 2024 10:30:44 上午 com.xiaokai.JULExample main
信息: This is an info message
十一月 19, 2024 10:30:44 上午 com.xiaokai.JULExample main
严重: This is a severe message
十一月 19, 2024 10:30:44 上午 com.xiaokai.JULExample main
严重: This is a severe message
3.2 Logback
它具有快速和通用的特性,可以在不同的环境下工作。Logback由三个模块组成:
-
logback-core:构成logback-classic和logback-access的基础。要执行日志记录,需要logback-classic或logback-access。
-
logback-classic:依靠logback-core提供日志记录服务,并且是log4j的改进版。它提供了更强大的日志功能,并且向下兼容log4j。它还支持SLF4J,可以在不修改代码的情况下将应用程序从一个日志框架切换到另一个日志框架。
-
logback-access:为servlet容器(如Tomcat和Jetty)提供HTTP访问日志功能。
Logback原生实现了Java的简单日志外观(SLF4J)API,这意味着开发人员可以针对SLF4J API编写日志代码,在部署时灵活地插入所需的日志框架。由于Logback原生实现了SLF4J,因此额外的SLF4J API层不会产生任何性能开销,这是Logback相对于其他框架的一点优势。
Logback支持TRACE、DEBUG、INFO、WARN和ERROR五种日志级别。在本地开发时,通常将日志级别设置为DEBUG,这将提供详细的日志消息以供开发者使用。部署到生产环境时,通常将日志级别设置为ERROR,这是为了避免日志中充斥过多的调试信息。
3.2.1 添加依赖
<!-- Logback Classic Module -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
3.2.2 配置logback
创建一个名为logback.xml
的配置文件,并将其放置在项目的src/main/resources
目录下
<configuration>
<!-- Console Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- File Appender -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Loggers -->
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
这个配置定义了两个Appender:一个输出到控制台,一个输出到文件application.log
。
3.2.3 示例
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class MyService {
private static final Logger logger = LoggerFactory.getLogger(MyService.class);
public void doSomething() {
logger.info("Doing something important");
}
}
注:
-
SpringBoot项目,会自动加载logback-sprinng.xml命令的配置文件。
-
一般情况下先加载logback-test.xml文件,没有会读取logback.xml文件。
-
在application.yml文件中配置加载文件。
# application.yml logging: config: classpath:logback.xml
3.3 Slf4j
SLF4J(Simple Logging Facade for Java)是一个为Java提供简单日志抽象的API。它并不是一个具体的日志框架,而是一个日志门面,允许开发者在代码中使用统一的API来记录日志,而不必直接依赖于具体的日志实现(如Log4j、Logback或Java Util Logging等)。
上述3.2
为slf4j+logback实现的日志输出示例。
3.4 Log4j
Log4j是一个由Apache软件基金会维护的开源日志记录工具,它是Java语言中广泛使用的日志框架之一。以下是Log4j的一些关键特点和介绍:
-
灵活性和可配置性:
-
Log4j允许开发者通过配置文件(如
log4j.properties
或log4j.xml
)灵活地设置日志级别、输出格式和目的地。这些配置文件定义了Loggers(日志记录器)、Appenders(日志输出目的地)和Layouts(日志格式)。
-
-
多种日志级别:
-
Log4j支持多种日志级别,包括DEBUG、INFO、WARN、ERROR和FATAL,允许开发者根据需要控制日志的详细程度。
-
-
多种Appender支持:
-
Log4j提供了多种Appender,可以将日志输出到不同的地方,如控制台(ConsoleAppender)、文件(FileAppender)、滚动文件(RollingFileAppender)和数据库(JDBCAppender)等。
-
-
Layout定制:
-
通过Layout,Log4j允许开发者定制日志的输出格式,包括时间戳、日志级别、消息等。
-
-
性能:
-
虽然Log4j1.x在性能上不如Log4j2,但它仍然是许多Java应用的常用日志框架,特别是在不需要极端性能要求的场景下。
-
-
安全性:
-
Log4j2相比于Log4j1.x在安全性方面有显著改进,例如,Log4j2中的JNDI支持更加安全,而Log4j1.x中的某些版本存在已知的安全漏洞,如Log4Shell(CVE-2021-44228)。
-
-
易用性:
-
Log4j通过简单的API使得在代码中插入日志语句变得容易,无需编写复杂的日志记录代码。
-
-
社区支持:
-
作为一个成熟的开源项目,Log4j拥有活跃的社区支持,提供文档、教程和问题解答。
-
-
审计和调试:
-
Log4j不仅在开发周期中发挥作用,其丰富的日志记录功能也可以作为审计工具使用。
-
3.4.1 Maven依赖配置
在项目的pom.xml文件中添加Log4j的依赖:
<!-- Log4j2依赖 -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
3.4.2 Log4j配置文件
在src/main/resources目录下创建log4j.properties文件:
# 设置根Logger的级别和输出目的地
log4j.rootLogger=DEBUG, stdout, file
# 配置控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
# 配置文件输出
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=logs/application.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
这个配置定义了两个Appender:一个输出到控制台,一个输出到文件application.log。
3.4.3 Java代码示例
创建一个Java类来使用Log4j记录日志:
import org.apache.log4j.Logger;
public class Log4jExample {
private static final Logger logger = Logger.getLogger(Log4jExample.class);
public static void main(String[] args) {
logger.debug("这是一个调试信息");
logger.info("这是一个普通信息");
logger.warn("这是一个警告信息");
logger.error("这是一个错误信息");
logger.fatal("这是一个致命错误信息");
}
}
3.5 Logstash
Logstash是一个开源的服务器端数据处理管道,它能够从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。以下是Logstash的一些主要功能和特点:
-
集中、转换和存储数据:
-
Logstash能够动态地采集、转换和传输数据,不受格式或复杂度的影响。利用Grok从非结构化数据中派生出结构,从IP地址解码出地理坐标,匿名化或排除敏感字段,并简化整体处理过程。
-
-
输入、筛选和输出:
-
Logstash支持各种输入选择,可以同时从众多常用来源捕捉事件,如日志、指标、Web应用等。它还提供实时解析和转换数据的能力,以及众多输出选择,可以将数据发送到指定的地方。
-
-
可扩展插件生态系统:
-
Logstash提供超过200个插件,以及创建和贡献自己的灵活性。它采用可插拔框架,允许将不同的输入选择、筛选器和输出选择混合搭配、精心安排,让它们在管道中和谐地运行。
-
-
可靠性与安全性:
-
如果Logstash节点发生故障,Logstash会通过持久化队列来保证至少将运行中的事件送达一次。那些未被正常处理的消息会被送往死信队列 (dead letter queue) 以便做进一步处理。此外,Logstash还能让您充分确保自己采集管道的安全性。
-
-
性能:
-
Logstash在性能上已经有很大提升,但与它的替代者们相比还是要慢很多的。它在大数据量的情况下可能会是个问题,特别是在资源消耗(默认的堆大小是1GB)方面。生产中写入Elasticsearch的速度可以达到5万/秒左右,但因为牵扯到过滤等操作,性能会有所降低。
-
-
社区支持:
-
Logstash是一个广泛采用的开源项目,拥有活跃的社区支持和大量的文档资源。
-
-
与Log4j的比较:
-
Logstash可以与Log4j配合使用,Log4j负责日志的生成和初步处理,而Logstash则负责日志的收集、解析和传输。Log4j配置文件中可以设置将日志输出到Logstash,Logstash再将这些日志数据传输到Elasticsearch中进行存储和分析。
-
3.5.1 基本示例
1. Logstash配置文件
首先,我们需要创建一个Logstash配置文件,这里我们称之为logstash.conf
。这个配置文件包含了输入(input)、过滤(filter)和输出(output)三个部分。
input {
stdin { }
}
filter {
grok {
match => { "message" => "%{COMBINEDAPACHELOG}"}
}
}
output {
stdout { codec => rubydebug }
elasticsearch {
hosts => ["http://localhost:9200"] # Elasticsearch服务器地址
index => "logstash-apache-logs-%{+YYYY.MM.dd}" # 索引名称,包含日期
}
}
2. 运行Logstash
接下来,我们使用以下命令运行Logstash,并指定我们的配置文件:
bin/logstash -f logstash.conf
这个命令告诉Logstash使用我们提供的logstash.conf
文件作为配置。
3. 输入日志数据
在运行Logstash的同时,我们可以向标准输入(stdin)输入日志数据。例如:
127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
4. 查看处理结果
Logstash会将输入的日志数据通过grok插件解析,然后输出到标准输出(stdout)和Elasticsearch。在标准输出中,你会看到类似以下格式的JSON数据:
{
"@version": "1",
"host": "your-hostname",
"@timestamp": "2023-11-20T12:39:38.514Z",
"message": "127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] \"GET /apache_pb.gif HTTP/1.0\" 200 2326",
"apache": {
"clientip": "127.0.0.1",
"ident": "-",
"auth": "frank",
"verb": "GET",
"request": "/apache_pb.gif",
"httpversion": "HTTP/1.0",
"bytes": "2326",
"referrer": "-",
"agent": "-",
"response": "200",
"cookies": [],
"xforwardedfor": [],
"unresolvedaddress": null,
"unresolvedhostname": null
}
}
同时,这些数据也会被索引到Elasticsearch中,可以通过Kibana或其他Elasticsearch客户端工具来查询和分析这些日志数据。
3.5.2 采集Java程序日志作为输入
1. 添加依赖:在你的Java项目中添加Logback和Logstash encoder的依赖。如果你的项目是Maven项目,可以在pom.xml
中添加以下依赖:
<!-- Logback Classic Module -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- Logstash Logback Encoder -->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>5.3</version>
</dependency>
2. 配置Logback:在src/main/resources
目录下创建logback-spring.xml
文件,并配置一个appender将日志发送到Logstash:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<!-- 配置Logstash服务地址 -->
<destination>127.0.0.1:4560</destination>
<!-- 日志输出编码 -->
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>UTC</timeZone>
</timestamp>
<pattern>
<pattern>
{
"logLevel": "%level",
"serviceName": "
${springAppName:-}",
"pid": "$
{PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"rest": "%message"
}</pattern>
</pattern>
</providers>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="LOGSTASH" />
</root>
</configuration>
3. 启动Logstash:配置Logstash监听TCP端口并接收日志:
input {
tcp {
mode => "server"
host => "127.0.0.1"
port => 4560
codec => json_lines
}
}
output {
elasticsearch {
hosts => "127.0.0.1:9200"
index => "springboot-logstash-%{+YYYY.MM.dd}"
}
}
4. 启动应用并查看日志:启动ava应用程序,日志将被发送到Logstash,并且Logstash会将这些日志存储到Elasticsearch中,在Kibana中查看和分析这些日志。
不积跬步,无以至千里 --- xiaokai