背景
在一个典型的分布式服务集群里,我们把应用日志统一扔进 ELK(Elasticsearch + Logstash + Kibana)做检索与可视化。本篇记录一次「日志写到了文件却进不了 ELK」的现场排查。
现象描述
- 线上 Dashboard 空空如也,Kibana 查看索引模板,没有任何新数据进来
- 登录到容器,
tail -f /var/log/my_service/app.log
能实时刷日志 - 集群中其他服务(名称不含 “-neo” 后缀)一切正常
排查思路
- 「文件有 – ES 无」= 中间 Filebeat / Logstash 链路有问题
- 先看 Filebeat 是否 “看见” 文件
- 再看 Logstash 是否 “接到” 事件
- 最后看 Elasticsearch 是否 “收录” 索引
排查过程
inputs
1. 验证 Filebeat 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
有助观察丢包 - 变更前加预案:灰度验证 + 手动链路压测是最快的保险
脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实, 仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。 示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
• 文中所示任何标识符并不对应实际生产环境中的名称或编号。
• 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
• 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
• 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
• 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。
Copyright © 1989–Present Ge Yuxu. All Rights Reserved.