背景

在一个典型的分布式服务集群里,我们把应用日志统一扔进 ELK(Elasticsearch + Logstash + Kibana)做检索与可视化。本篇记录一次「日志写到了文件却进不了 ELK」的现场排查。

现象描述

  • 线上 Dashboard 空空如也,Kibana 查看索引模板,没有任何新数据进来
  • 登录到容器,tail -f /var/log/my_service/app.log 能实时刷日志
  • 集群中其他服务(名称不含 “-neo” 后缀)一切正常

排查思路

  • 「文件有 – ES 无」= 中间 Filebeat / Logstash 链路有问题
  • 先看 Filebeat 是否 “看见” 文件
  • 再看 Logstash 是否 “接到” 事件
  • 最后看 Elasticsearch 是否 “收录” 索引

排查过程

1. 验证 Filebeat inputs

filebeat.inputs:
  - type: log
    paths:
      - /var/log/my_service/*.log
    fields:
      project: my_service
  • 实际服务器日志目录是 /var/log/my_service-neo/
  • 采集规则却写死为 my_service路径失配

2. 临时软链压测

ln -s /var/log/my_service-neo /var/log/my_service
  • 软链一创建,Kibana 中立刻出现日志 → 路径就是元凶
  • 证明 Filebeat、Logstash、ES 本身都没毛病

3. 溯源“后缀 -neo”

  • Python 服务的工程名在 settings.py 里手动改过
    SERVICE_NAME = "my_service-neo"
  • 部署流水线和 Filebeat 规则却还是历史名 my_service

工程名改动 如果没同步到所有配置,就一定埋雷。

根因分析

  • 单节点可写日志 → Python logging 配置 OK
  • Filebeat 不认路径 → 采集规则老化
  • 上游自动化脚本、K8s ConfigMap 同样硬编码了旧路径

解决方案

  • 方案 A:回滚工程名
    • 简单粗暴,但需要全量回退 Tag、镜像仓库名,不推荐
  • 方案 B:升级采集规则 ✅
    • 把 Filebeat、Logstash、自定义监控统统改为新工程名
    • 全链路保持单一真名

下文以方案 B 为例。

Python 端结构化日志

import logging
import logging.config
import json_log_formatter

formatter = json_log_formatter.JSONFormatter()

LOG_CONFIG = {
    "version": 1,
    "formatters": {
        "json": {
            "class": "json_log_formatter.JSONFormatter",
            "format": "%(asctime)s %(levelname)s %(name)s %(message)s"
        }
    },
    "handlers": {
        "file": {
            "class": "logging.handlers.TimedRotatingFileHandler",
            "filename": "/var/log/my_service-neo/app.log",
            "when": "midnight",
            "backupCount": 7,
            "formatter": "json"
        }
    },
    "root": {
        "handlers": ["file"],
        "level": "INFO"
    }
}

logging.config.dictConfig(LOG_CONFIG)
logger = logging.getLogger(__name__)

logger.info({"event": "service_start", "version": "1.2.3"})
  • 使用 json_log_formatter 把日志变成纯 JSON,Filebeat 解析无痛
  • filename 含新工程名 my_service-neo

Filebeat 动态拾取

filebeat.autodiscover:
  providers:
    - type: kubernetes
      hints.enabled: true
      templates:
        - condition:
            equals:
              kubernetes.labels.app: my_service-neo
          config:
            - type: log
              paths:
                - /var/log/my_service-neo/*.log
              json.keys_under_root: true
              json.add_error_key: true
  • 只要 Pod 有 app=my_service-neo 标签,日志就能被采集
  • 彻底去掉硬编码

日志落 ES

  • Logstash 保持 json codec,按日期走 ILM
  • Elasticsearch 索引命名:my_service-neo-%{+yyyy.MM.dd}
  • Kibana Saved Search 更新索引模式即可

经验总结

  • 工程名/路径改动要全链路跟
  • 日志用 JSON,字段少但结构稳
  • Filebeat 用 Autodiscover,避免人肉维护 YAML
  • 监控采集量:Filebeat event.published_time 有助观察丢包
  • 变更前加预案:灰度验证 + 手动链路压测是最快的保险
Ge Yuxu • AI & Engineering

脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实, 仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。 示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
    • 文中所示任何标识符并不对应实际生产环境中的名称或编号。
    • 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
    • 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。

版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
    • 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
    • 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。

Copyright © 1989–Present Ge Yuxu. All Rights Reserved.