从零搭建 ELK + Kafka 日志收集系统(Spring Boot + Logback 直连 Kafka)

前言

在生产环境中,微服务日志分散在各个服务器上,排查问题需要登录多台机器,效率极低。本文将带你从零开始,搭建一套完整的应用日志 → Kafka → ELK 日志收集管道,实现日志的集中存储、实时搜索与可视化。你将学会:

  • 安装配置 Elasticsearch、Kibana、Logstash、Kafka

  • Spring Boot 应用通过 Logback 直连 Kafka 发送 JSON 格式日志

  • Logstash 消费 Kafka 并按日志级别分流写入 Elasticsearch

  • Kibana 中创建数据视图,快速检索日志

最终效果:所有业务日志实时进入 Elasticsearch,可在 Kibana 中秒级搜索。


一、环境准备

1.1 组件版本

为保证兼容性,统一使用 9.3.2 版本(Elastic Stack 各组件版本需一致,Kafka 使用 2.13-3.5.0 或更高)。

组件 版本 端口
Elasticsearch 9.3.2 9200
Kibana 9.3.2 5601
Logstash 9.3.2 9600 (API)
Kafka 3.5.0 9092
Zookeeper 3.8.0 2181
Spring Boot 3.5.13 8080

1.2 下载地址

Elasticsearch 9.3.2
Kibana 9.3.2
Logstash 9.3.2
Kafka (Scala 2.13) 3.5.0

注:Kafka 依赖 Zookeeper,安装包自带 Zookeeper 启动脚本。

二、安装与启动

2.1 启动 Elasticsearch

解压后进入 bin 目录:

bash 复制代码
# Windows
elasticsearch.bat

# Linux
./elasticsearch -d

验证:访问 http://localhost:9200,应返回 JSON 信息(含版本号)。

2.2 启动 Kibana

解压后修改 config/kibana.yml(关键配置):

bash 复制代码
server.port: 5601
server.host: "localhost"
elasticsearch.hosts: ["http://localhost:9200"]
elasticsearch.username: "elastic"
elasticsearch.password: "root123"   # 如果你设置了密码

启动:

bash 复制代码
# Windows
kibana.bat

# Linux
./kibana &

访问 http://localhost:5601 验证。

2.3 启动 Kafka (含 Zookeeper)

解压 Kafka 后,进入根目录:

bash 复制代码
# 启动 Zookeeper
bin/zookeeper-server-start.sh -daemon config/zookeeper.properties

# 启动 Kafka
bin/kafka-server-start.sh -daemon config/server.properties

验证:netstat -tulnp | grep 9092 应看到监听。

2.4 启动 Logstash

解压后创建配置文件(见下文),启动:

bash 复制代码
bin/logstash -f config/logstash-kafka.conf

三、Spring Boot 应用配置

3.1 添加依赖

pom.xml 中加入:

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Logback Kafka Appender -->
<dependency>
    <groupId>com.github.danielwegener</groupId>
    <artifactId>logback-kafka-appender</artifactId>
    <version>0.2.0</version>
</dependency>
<!-- 0.2.0不可用替代 -->
 <dependency>
     <groupId>com.github.danielwegener</groupId>
     <artifactId>logback-kafka-appender</artifactId>
     <version>0.2.0-RC2</version>
 </dependency>

如果 Maven 下载失败,可手动安装:

  • 下载 jar 和 pom 从 中央仓库

  • 执行 mvn install:install-file -Dfile=xxx.jar -DpomFile=xxx.pom

3.2 配置 application.yml

bash 复制代码
spring:
  elasticsearch:
    uris: http://localhost:9200
    # 如果需要认证,取消注释下面两行
    username: elastic
    password: root123
  kafka:
    bootstrap-servers: 192.168.194.147:9092   # 使用你服务器的实际IP
    producer:
      key-serializer: org.apache.kafka.common.serialization.StringSerializer
      value-serializer: org.apache.kafka.common.serialization.StringSerializer
    consumer:
      group-id: my-group                       # 消费者组ID,随意命名
      auto-offset-reset: earliest              # 从最早的消息开始消费
      key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
      value-deserializer: org.apache.kafka.common.serialization.StringDeserializer

3.3 配置 logback-spring.xml

放在 src/main/resources 下,完整内容:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- 控制台输出(供调试) -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!-- Kafka Appender(异步发送 JSON 日志) -->
    <appender name="KAFKA" class="com.github.danielwegener.logback.kafka.KafkaAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <pattern>{"timestamp":"%d{yyyy-MM-dd'T'HH:mm:ss.SSSZZ}","level":"%level","thread":"%thread","logger":"%logger","message":"%msg","exception":"%ex{short}"}%n</pattern>
        </encoder>
        <topic>app-logs</topic>
        <keyingStrategy class="com.github.danielwegener.logback.kafka.keying.NoKeyKeyingStrategy"/>
        <deliveryStrategy class="com.github.danielwegener.logback.kafka.delivery.AsynchronousDeliveryStrategy"/>
        <producerConfig>bootstrap.servers=192.168.194.147:9092</producerConfig>
        <producerConfig>acks=0</producerConfig>
        <producerConfig>linger.ms=100</producerConfig>
        <producerConfig>max.block.ms=0</producerConfig>
    </appender>

    <!-- 关键:避免 Kafka 客户端日志进入 Kafka Appender 造成循环 -->
    <logger name="org.apache.kafka" level="WARN" additivity="false">
        <appender-ref ref="CONSOLE"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="KAFKA"/>
    </root>
</configuration>

注意 :将 bootstrap.servers 改为你的 Kafka 实际 IP。

3.4 测试代码

创建一个简单的 Test ,测试代码没必要保持一致主要实现的是日志log.info、log.error

触发日志输出:

java 复制代码
@SpringBootTest
public class KafkaTests {
    @Autowired
    private KafkaProducer kafkaProducer;
    @Test
    public void testKafkaProducer() throws InterruptedException {
        for (int i = 0; i < 10; i++) {

            String text="afkaProducer Test Message ";
            if (i == 5) {
                text="fail message";
            }
            kafkaProducer.sendKafkaMessage("test-topic", String.valueOf(i), text + i);
        }
        Thread.sleep(5000);
    }
}
java 复制代码
@Slf4j
@Component
@RequiredArgsConstructor
public class KafkaProducer {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    //生产者
    public void sendKafkaMessage(String topic, String key, String message) {
        kafkaTemplate.send(topic, key, message);
        log.info("发送Kafka消息: topic={}, key={}, message={}", topic, key, message);
    }

    //消费者 业务1
    @KafkaListener(topics = "test-topic", groupId = "test1-key")
    public void listenKafkaTest1Message(String message) {

        if (message.contains("fail")) {
        log.error("收到Kafka消息: test1 -> {}", message);
        } else{
            log.info("收到Kafka消息: test1 -> {}", message);
        }
    }

    //消费者 业务2
    @KafkaListener(topics = "test-topic", groupId = "test2-key")
    public void listenKafkaTest2Message(String message) {
        log.info("收到Kafka消息: test2 -> {}", message);
    }

}

启动 Spring Boot 应用。

四、Logstash 配置

在 Logstash 的 config 目录下创建 logstash-kafka.conf

bash 复制代码
input {
    kafka {
        bootstrap_servers => "192.168.194.147:9092"
        topics => ["app-logs"]
        group_id => "logstash-group"
        consumer_threads => 3
        auto_offset_reset => "earliest"
        codec => "json"
    }
}

filter {
    # 将日志中的 timestamp 字段映射为 @timestamp
    if [timestamp] {
        date {
            match => [ "timestamp", "ISO8601" ]
            target => "@timestamp"
        }
        mutate {
            remove_field => [ "timestamp" ]
        }
    }
}

output {
    if [level] == "ERROR" {
        elasticsearch {
            hosts => ["http://localhost:9200"]
            index => "app-logs-error-%{+YYYY.MM.dd}"
            user => "elastic"
            password => "root123"
        }
    } else {
        elasticsearch {
            hosts => ["http://localhost:9200"]
            index => "app-logs-info-%{+YYYY.MM.dd}"
            user => "elastic"
            password => "root123"
        }
    }
    stdout { codec => rubydebug }
}

修改 bootstrap_servers 和 Elasticsearch 认证信息(若无密码可去掉 user/password)。

启动 Logstash 后,它就会开始消费 Kafka 中的消息。


五、Kibana 中查看日志

  1. 访问 http://localhost:5601

  2. 左侧菜单 → ManagementStack ManagementData Views

  3. 点击 Create data view

    • Name: app-info-logs

    • Index pattern: app-logs-info-*

    • Timestamp field: @timestamp (若没有则选 I don't want to use the time filter)

  4. 同样创建 app-error-logs,Index pattern: app-logs-error-*

  5. 进入 Discover ,选择数据视图,调整时间范围为 Today,即可看到实时日志。


六、验证与测试

  1. 执行测试产生日志:

    java 复制代码
        @Autowired
        private KafkaProducer kafkaProducer;
        @Test
        public void testKafkaProducer() throws InterruptedException {
            for (int i = 0; i < 10; i++) {
    
                String text="afkaProducer Test Message ";
                if (i == 5) {
                    text="fail message";
                }
                kafkaProducer.sendKafkaMessage("test-topic", String.valueOf(i), text + i);
            }
            Thread.sleep(5000);
        }
  2. 观察 Logstash 控制台输出(stdout 会打印每条消息)。

  3. 在 Kibana Discover 中搜索 level:ERROR,应看到错误日志。

  4. 查看 Elasticsearch 索引:

    打开 Kibana 界面(http://localhost:5601

    点击左侧菜单栏的 Dev Tools(扳手图标)

    在 Console 窗口中输入:

    bash 复制代码
    GET _cat/indices?v

    点击右侧的 ▶ 按钮(或按 Ctrl+Enter)执行

    下方会返回索引列表,包括 app-logs-info-*、users 等

  5. 应出现 app-logs-info-2026.04.20app-logs-error-2026.04.20

七、常见问题及解决

7.1 StackOverflowError 循环依赖

原因:Kafka 客户端初始化时打印日志,Logback 将其发送到 Kafka Appender,而 Appender 又要创建 Kafka 客户端,无限递归。

解决 :在 logback-spring.xml 中为 org.apache.kafka 包单独配置输出到控制台,且 additivity="false"

7.2 Logback Kafka Appender 下载失败

阿里云镜像没有该依赖。解决方法:

  • 添加中央仓库到 pom.xml<repositories>

  • 或手动安装 jar 到本地 Maven 仓库

7.3 Logstash 无法连接 Kafka

检查 bootstrap_servers 地址和端口,确保 Kafka 已启动且防火墙允许 9092 端口。

7.4 Kibana 看不到数据

  • 确认 Logstash 已成功消费并写入 ES(查看 Logstash 日志)

  • 检查索引是否存在(GET _cat/indices

  • 在 Kibana Data View 中点击 Refresh 刷新字段列表

  • 扩大时间范围或选择 No time filter


八、总结

通过本文,你已经完成了从零搭建一套企业级日志收集系统。这套架构具备以下优点:

  • 高吞吐:Kafka 缓冲,可应对突发流量

  • 可靠:Kafka 多副本持久化,Logstash 消费失败可重试

  • 解耦:应用只写 Kafka,不依赖后端存储

  • 可扩展:增加 Logstash 消费者即可提高处理能力

  • 可重放:Kafka 中消息保留多天,支持重置偏移量重新处理

你可以将这套方案应用到自己的项目中,轻松实现日志的集中管理和分析。


九、参考资料

如果觉得本文对你有帮助,欢迎点赞、收藏、转发。遇到任何问题,欢迎在评论区留言交流。

相关推荐
香菜TTT9 小时前
Kafka_深度解析_从架构原理到生产实践
分布式·架构·kafka·linq
paopaokaka_luck9 小时前
基于springboot3+vue3的智能文库平台(AI智能搜索、AI智能汇总、实时在线状态展示、多格式文档预览与富文本编辑、Echarts图形化分析)
前端·网络·spring boot·网络协议·echarts
热心市民lcj15 小时前
Spring Boot 整合 Caffeine 本地缓存实战
spring boot·后端·缓存
java1234_小锋15 小时前
【免费】基于Spark实时金融交易风险监控与预测系统(Java版本+可视化大屏+Kafka+SpringBoot+Vue3) 锋哥原创出品,必属精品
大数据·spark·kafka·金融交易风险监控与预测
天丁o16 小时前
Spring Boot + MyBatis Plus 考勤日报统计报表:打卡记录聚合、异常分类和明细下钻 Demo
spring boot·mybatis plus·企业数字化·考勤系统·报表统计
智_永无止境16 小时前
Spring Boot 集成 OnlyOffice
java·spring boot·后端
梦想画家16 小时前
FilePulse:Kafka Connect 的“智能文件网关”,重塑数据接入新范式
kafka·文件连接器·filepulse
Devin~Y17 小时前
从本地生活电商到 AI RAG:互联网大厂 Java 面试场景完整实战
java·spring boot·redis·elasticsearch·spring cloud·kafka·rag
米码收割机17 小时前
SA508-3钢回火焊道焊接温度场数值模拟(模拟图+论文)
spring boot·express·宠物
斯普润布特17 小时前
Kafka KRaft 三节点 ARM64 Docker 部署
分布式·kafka