在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
💻 作为一名热爱 Java 与软件开发的程序员,我始终相信:清晰的逻辑 + 持续的积累 = 稳健的成长
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕一个常见的开发话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


📝 日志收集系统(Logback + ELK):构建企业级日志分析平台 🔍

在现代分布式系统中,一个用户请求可能经过数十个微服务,日志分散在成百上千台服务器上。当系统出现异常时,运维人员常常面临这样的困境:

“这个错误到底发生在哪台机器?哪个服务?什么时间?上下文是什么?” ❓

传统的 tail -f logs/app.log 方式早已无法满足需求。

于是,集中式日志系统 成为现代 DevOps 的标配。它将分散的日志集中采集、存储、搜索、分析和可视化,帮助我们快速定位问题、监控系统健康、分析业务趋势。

本文将带你从零搭建一套基于 Logback + ELK(Elasticsearch, Logstash, Kibana) 的企业级日志收集系统,涵盖日志格式设计、Logstash 配置、Elasticsearch 存储优化、Kibana 可视化,并结合 Spring Boot 实战,助你打造强大的日志分析能力。

🔗 ELK 官方文档https://www.elastic.co/guide/index.html


🧩 什么是 ELK?三大核心组件解析

ELK 并不是一个单一软件,而是三个开源项目的首字母缩写:

  • Elasticsearch:分布式搜索引擎,负责日志的存储与检索;
  • Logstash:日志收集与处理管道,支持多种输入、过滤、输出;
  • Kibana:数据可视化平台,提供图表、仪表盘、搜索界面。

💡 后来加入 Beats(轻量级数据采集器),合称 Elastic Stack

✅ ELK 工作流程

应用日志
Logback
File / TCP / Kafka
Logstash
Elasticsearch
Kibana
运维/开发
  1. 应用通过 Logback 写入日志;
  2. Logstash 采集日志文件或接收网络日志;
  3. Logstash 进行过滤、解析、丰富日志内容;
  4. 将结构化日志写入 Elasticsearch
  5. 通过 Kibana 进行搜索、分析、可视化。

🛠️ 环境准备

✅ 安装 Elasticsearch

# 下载并启动(Linux/Mac)
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.11.0-linux-x86_64.tar.gz
tar -xzf elasticsearch-8.11.0-linux-x86_64.tar.gz
cd elasticsearch-8.11.0
./bin/elasticsearch

🔗 Elasticsearch 下载https://www.elastic.co/downloads/elasticsearch

✅ 安装 Logstash

wget https://artifacts.elastic.co/downloads/logstash/logstash-8.11.0-linux-x86_64.tar.gz
tar -xzf logstash-8.11.0-linux-x86_64.tar.gz

✅ 安装 Kibana

wget https://artifacts.elastic.co/downloads/kibana/kibana-8.11.0-linux-x86_64.tar.gz
tar -xzf kibana-8.11.0-linux-x86_64.tar.gz
cd kibana-8.11.0-linux-x86_64
./bin/kibana

🔗 Kibana 下载https://www.elastic.co/downloads/kibana


🧱 Logback:Java 应用的日志引擎

Logbacklog4j 的继任者,由同一作者开发,性能更高、配置更灵活。

✅ Maven 依赖

<dependencies>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.11</version>
    </dependency>
    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
        <version>7.4</version>
    </dependency>
</dependencies>

🔗 logstash-logback-encoder GitHubhttps://github.com/logfellow/logstash-logback-encoder


📦 设计结构化日志格式(JSON)

传统日志难以解析:

2025-09-27 21:00:00 [INFO] User login success: id=1001, ip=192.168.1.1

JSON 格式 便于 Logstash 解析:

{
  "@timestamp": "2025-09-27T21:00:00.123Z",
  "level": "INFO",
  "message": "User login success",
  "userId": 1001,
  "ip": "192.168.1.1",
  "service": "user-service",
  "traceId": "abc-123-def"
}

🎨 配置 Logback 输出 JSON 日志

创建 logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <property name="LOG_PATH" value="./logs"/>

    <!-- 控制台输出 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp/>
                <logLevel/>
                <loggerName/>
                <message/>
                <mdc/> <!-- Mapped Diagnostic Context -->
                <arguments/>
                <stackTrace/>
            </providers>
        </encoder>
    </appender>

    <!-- 文件输出(JSON) -->
    <appender name="FILE_JSON" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_PATH}/app.json</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_PATH}/archive/app-%d{yyyy-MM-dd}.%i.json</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>10GB</totalSizeCap>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp/>
                <logLevel/>
                <loggerName/>
                <message/>
                <mdc/>
                <arguments/>
                <stackTrace/>
                <!-- 自定义字段 -->
                <provider class="net.logstash.logback.composite.ContextJsonProvider"/>
                <pattern>
                    <pattern>
                        {
                          "service": "user-service",
                          "host": "${HOSTNAME}",
                          "env": "prod"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <!-- 异步输出(提升性能) -->
    <appender name="ASYNC_JSON" class="ch.qos.logback.classic.AsyncAppender">
        <appender-ref ref="FILE_JSON"/>
        <queueSize>1024</queueSize>
        <includeCallerData>false</includeCallerData>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ASYNC_JSON"/>
    </root>
</configuration>

🧪 在代码中使用 MDC 传递上下文

@RestController
public class UserController {

    private static final Logger logger = LoggerFactory.getLogger(UserController.class);

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        // 将请求上下文放入 MDC
        MDC.put("userId", String.valueOf(id));
        MDC.put("traceId", UUID.randomUUID().toString());

        try {
            logger.info("开始查询用户信息");
            User user = userService.findById(id);
            logger.info("查询用户成功", user);
            return user;
        } catch (Exception e) {
            logger.error("查询用户失败", e);
            throw e;
        } finally {
            MDC.clear();
        }
    }
}

生成的日志片段:

{
  "@timestamp": "2025-09-27T21:05:30.456Z",
  "level": "INFO",
  "logger_name": "com.example.UserController",
  "message": "开始查询用户信息",
  "MDC": {
    "userId": "1001",
    "traceId": "abc-123-def"
  },
  "service": "user-service",
  "host": "server-01"
}

🚰 Logstash:日志的“搬运工”与“美容师”

Logstash 负责从各种来源采集日志,并进行处理后发送到 Elasticsearch。

✅ 配置 logstash.conf

input {
  # 读取本地 JSON 日志文件
  file {
    path => "/path/to/your/logs/archive/app-*.json"
    start_position => "beginning"
    sincedb_path => "/dev/null"
    codec => "json"
  }

  # 或通过 TCP 接收日志(适用于 Docker/K8s)
  tcp {
    port => 5000
    codec => json
  }
}

filter {
  # 解析时间字段
  date {
    match => [ "@timestamp", "ISO8601" ]
  }

  # 添加字段
  mutate {
    add_field => {
      "cluster" => "prod-cluster"
      "region" => "cn-east-1"
    }
  }

  # 条件过滤:只处理 ERROR 级别日志
  # if [level] == "ERROR" {
  #   drop {}
  # }

  # 解析 message 字段(如果包含结构化内容)
  # grok {
  #   match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:msg}" }
  # }
}

output {
  # 输出到 Elasticsearch
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "logs-%{+YYYY.MM.dd}"
    user => "elastic"
    password => "your_password"
  }

  # 开发环境可同时输出到控制台
  stdout {
    codec => rubydebug
  }
}

✅ 启动 Logstash

cd logstash-8.11.0
bin/logstash -f config/logstash.conf

🔍 Elasticsearch:日志的“大脑”

Elasticsearch 是一个分布式、RESTful 的搜索和分析引擎。

✅ 检查索引是否创建

curl -X GET "localhost:9200/_cat/indices?v"

输出示例:

health status index            uuid                   pri rep docs.count docs.deleted store.size
green  open   logs-2025.09.27  abc123def456ghi789   1   1   12345      0              10.2mb

✅ 查询日志

curl -X GET "localhost:9200/logs-2025.09.27/_search" \
-H "Content-Type: application/json" \
-d '{
  "query": {
    "match": {
      "message": "查询用户失败"
    }
  }
}'

📊 Kibana:日志的“可视化驾驶舱”

Kibana 提供了强大的 Web 界面,用于搜索、分析和可视化 Elasticsearch 中的数据。

✅ 创建 Index Pattern

  1. 打开 Kibana:http://localhost:5601
  2. 进入 Stack Management > Index Patterns
  3. 创建 logs-* 模式,选择 @timestamp 作为时间字段。

✅ 搜索日志

Discover 页面,你可以:

  • 使用 Kibana Query Language (KQL) 搜索:
    level : "ERROR" and message : "failed"
    
  • 按时间范围筛选;
  • 查看日志详情。

✅ 创建可视化图表

  1. 进入 Visualize Library
  2. 创建 Vertical Bar Chart
    • X-axis: @timestamp (Date Histogram)
    • Y-axis: Count
    • Filters: level : "ERROR"
  3. 保存为 “每日错误日志趋势”

✅ 构建仪表盘(Dashboard)

将多个图表组合成一个仪表盘:

  • 错误日志趋势
  • 各服务日志量占比(Pie Chart)
  • 响应时间分布(Histogram)
  • 实时日志流(Latest Data Table)

🔗 Kibana 教程https://www.elastic.co/guide/en/kibana/current/index.html


🛡️ 安全配置(生产环境必做)

✅ 启用 Elasticsearch 安全

# elasticsearch.yml
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

设置密码:

./bin/elasticsearch-setup-passwords auto

✅ 配置 Logstash 输出认证

output {
  elasticsearch {
    hosts => ["https://es-server:9200"]
    index => "logs-%{+YYYY.MM.dd}"
    user => "logstash_writer"
    password => "secure_password"
    ssl => true
    cacert => "/path/to/http_ca.crt"
  }
}

🚀 性能优化建议

✅ Elasticsearch 优化

  • 分片策略:单索引分片数不超过 50GB;
  • 冷热架构:热节点 SSD 存储近期日志,冷节点 HDD 存档;
  • 索引生命周期管理(ILM):自动 rollover、shrink、delete。
PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "1d"
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

✅ Logstash 优化

  • 使用 Persistent Queue 防止数据丢失;
  • 多 worker 线程处理;
  • 避免复杂 Grok 解析。
# logstash.yml
queue.type: persisted
pipeline.workers: 4
pipeline.batch.size: 125

🔄 替代方案:Filebeat + Logstash

在生产环境中,Filebeat 常作为轻量级日志采集器,替代 Logstash 的 input 角色。

✅ 架构演进

应用
Logback File
Filebeat
Logstash Filter
Elasticsearch
Kibana

优势

  • Filebeat 资源占用极低(< 10MB 内存);
  • 支持断点续传、ACK 机制,保证不丢日志;
  • 可部署在每台应用服务器上。

✅ 配置 filebeat.yml

filebeat.inputs:
  - type: filestream
    paths:
      - /var/log/myapp/*.json
    json.keys_under_root: true
    json.add_error_key: true

output.logstash:
  hosts: ["logstash-server:5044"]

🔗 Filebeat 官方指南https://www.elastic.co/guide/en/beats/filebeat/current/index.html


🐳 Docker 部署 ELK

使用 docker-compose.yml 一键部署:

version: '3.7'

services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=true
    ports:
      - "9200:9200"
    volumes:
      - esdata:/usr/share/elasticsearch/data

  logstash:
    image: docker.elastic.co/logstash/logstash:8.11.0
    volumes:
      - ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
    ports:
      - "5000:5000"
    depends_on:
      - elasticsearch

  kibana:
    image: docker.elastic.co/kibana/kibana:8.11.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    depends_on:
      - elasticsearch

volumes:
  esdata:

启动:

docker-compose up -d

🧪 实战:Spring Boot 集成 ELK

✅ 应用配置

确保 logback-spring.xml 已配置 JSON 输出。

✅ 模拟日志输出

@GetMapping("/test-error")
public String testError() {
    MDC.put("requestId", UUID.randomUUID().toString());
    logger.info("收到测试请求");
    
    try {
        int i = 1 / 0;
    } catch (Exception e) {
        logger.error("发生算术异常", e);
    }
    
    MDC.clear();
    return "error logged";
}

✅ Kibana 中搜索

在 Kibana Discover 中输入:

message : "算术异常"

即可看到包含完整堆栈的错误日志。


📈 高级功能:日志分析场景

✅ 1. 错误告警

使用 Elastic Stack Alerting

  • 监控 ERROR 日志数量;
  • 超过阈值时发送邮件/钉钉/企业微信。
// 告警条件
{
  "query": {
    "bool": {
      "must": [
        { "match": { "level": "ERROR" } },
        { "range": { "@timestamp": { "gte": "now-5m" } } }
      ]
    }
  },
  "threshold": 10
}

🔗 Elastic Alertinghttps://www.elastic.co/guide/en/kibana/current/alerting-getting-started.html


✅ 2. 链路追踪集成

结合 SkyWalkingZipkin,将 traceId 写入日志,实现 日志与链路追踪联动

// 在拦截器中注入 traceId
String traceId = TracingContext.getCurrentTraceId();
MDC.put("traceId", traceId);

在 Kibana 中点击日志的 traceId,跳转到 APM 页面查看完整调用链。


✅ 3. 业务指标分析

将业务日志转化为指标:

  • 用户注册量(message:"user registered"
  • 支付成功率(status:"success" vs status:"failed"
  • API 调用量(endpoint:"/api/order"

🧰 最佳实践总结

  1. 日志级别合理使用

    • DEBUG:开发调试
    • INFO:关键业务节点
    • WARN:可容忍的异常
    • ERROR:影响功能的错误
  2. 避免日志敏感信息

    logger.info("用户登录: id={}, phone=***", userId); // 脱敏
    
  3. 控制日志量:避免在循环中打日志。

  4. 统一日志格式:所有服务使用相同 JSON Schema。

  5. 定期清理:通过 ILM 自动删除 30 天前日志。


📊 监控 ELK 自身健康

  • Elasticsearch:监控 JVM、磁盘、线程池;
  • Logstash:监控事件处理速率、队列大小;
  • Kibana:监控响应时间。

使用 Elastic Stack MonitoringPrometheus + Grafana

🔗 Prometheus Exporterhttps://github.com/justwatchcom/elasticsearch_exporter


🏁 结语

一套完善的 Logback + ELK 日志系统,是现代应用的“黑匣子”和“雷达站”。

  • 它让 问题定位从小时级缩短到分钟级
  • 它让 系统状态从“黑盒”变为“透明”
  • 它让 运维从“救火”变为“预防”

通过本文的实践,你已经掌握了:

  • 如何用 Logback 输出结构化 JSON 日志;
  • 如何用 Logstash 采集和处理日志;
  • 如何用 Elasticsearch 存储和检索日志;
  • 如何用 Kibana 可视化和告警。

🔗 推荐阅读

🚀 构建你的 ELK 日志平台,让每一次日志都成为系统的“智慧之眼”!
🔍 让数据说话,让问题无处遁形。


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐