本文目录导读:

对于PHP项目的微服务日志集中采集、分析和检索,推荐采用 ELK/EFK(Elasticsearch + Logstash/Fluentd + Kibana) 或 Grafana + Loki 这类开源方案,以下是完整的实施指南:
整体架构方案
[PHP微服务A] --日志--> [Filebeat/Logstash]
[PHP微服务B] --日志--> [Filebeat/Logstash]
[PHP微服务C] --日志--> [Filebeat/Logstash]
↓
[消息队列] (可选: Kafka/Redis)
↓
[Logstash/Fluentd] (解析/过滤)
↓
[Elasticsearch] (存储/索引)
↓
[Kibana/Grafana] (可视化/检索)
PHP端日志规范
统一日志格式(推荐JSON)
// 使用 Monolog 库
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\JsonFormatter;
$logger = new Logger('order-service');
$handler = new StreamHandler('/var/log/app/order.log');
$handler->setFormatter(new JsonFormatter());
$logger->pushHandler($handler);
// 记录结构化日志
$logger->info('订单创建成功', [
'order_id' => 12345,
'user_id' => 67890,
'amount' => 99.99,
'trace_id' => getenv('TRACE_ID'), // 链路追踪ID
'span_id' => uniqid(),
'service' => 'order-service',
'env' => 'production'
]);
必须包含的字段
{
"@timestamp": "2024-01-15T10:30:00+08:00",
"level": "INFO",
"service": "order-service",
"instance": "pod-instance-1",
"trace_id": "abc123...",
"request_id": "req-001",
"message": "订单创建成功",
"context": {
"order_id": 12345,
"user_id": 67890
},
"exception": null, // 异常堆栈
"duration_ms": 235, // 请求耗时
"method": "POST",
"path": "/api/orders"
}
日志采集方案
方案1:轻量级 - Filebeat + Elasticsearch
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
json.keys_under_root: true
json.overwrite_keys: true
fields:
service: order-service
env: production
output.elasticsearch:
hosts: ["http://elasticsearch:9200"]
index: "%{[fields.service]}-%{+yyyy.MM.dd}"
方案2:高吞吐 - Filebeat + Kafka + Logstash
# filebeat.yml
output.kafka:
hosts: ["kafka:9092"]
topic: php-logs
partition.round_robin:
reachable_only: true
# logstash.conf
input {
kafka {
bootstrap_servers => "kafka:9092"
topics => ["php-logs"]
codec => json
}
}
filter {
mutate {
add_field => { "[@metadata][index]" => "%{[service]}-%{+YYYY.MM.dd}" }
}
}
output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "%{[@metadata][index]}"
}
}
方案3:容器化环境 - 使用Sidecar模式
# docker-compose.yml
services:
php-app:
image: php-app
volumes:
- app-logs:/var/log/app
filebeat:
image: docker.elastic.co/beats/filebeat:8.11.0
user: root
volumes:
- app-logs:/var/log/app
- ./filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
depends_on:
- elasticsearch
volumes:
app-logs:
日志检索与优化
Elasticsearch索引模板
PUT _template/php_logs_template
{
"index_patterns": ["*-*.*.*"],
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1,
"refresh_interval": "5s"
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"instance": { "type": "keyword" },
"trace_id": {
"type": "text",
"fields": {
"keyword": { "type": "keyword" }
}
},
"message": { "type": "text" },
"duration_ms": { "type": "long" },
"exception": { "type": "text" }
}
}
}
Kibana常用检索
- 按服务查询:
service: "order-service" - 按耗时排序:
duration_ms > 1000 - 错误日志:
level: "ERROR" OR level: "CRITICAL" - 链路追踪:
trace_id: "abc123..." - 时间段:
@timestamp >= "now-1h"
监控与告警
Elasticsearch Watcher告警
{
"trigger": {
"schedule": { "interval": "5m" }
},
"input": {
"search": {
"request": {
"indices": ["*"],
"body": {
"query": {
"bool": {
"must": [
{ "term": { "level": "ERROR" } },
{ "range": { "@timestamp": { "gte": "now-5m" } } }
]
}
}
}
}
}
},
"actions": {
"email_admin": {
"email": {
"to": ["admin@company.com"],
"subject": "错误日志告警",
"body": "最近5分钟产生 {{ctx.payload.hits.total}} 条错误日志"
}
}
}
}
基于Logstash的异常检测
# logstash filter
filter {
if [level] == "ERROR" {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
query => "level:ERROR AND service:%{[service]}"
fields => { "count" => "[hits][total]" }
}
if [count] > 100 {
metrics { meter => { "error_rate" => "%{[service]}" } }
}
}
}
生产环境注意事项
日志安全与合规
-
敏感信息脱敏: 在Monolog中使用处理器过滤密码、手机号等
$processor = new \Monolog\Processor\MaskingProcessor([ 'password', 'credit_card', 'phone' ]); $logger->pushProcessor($processor);
-
日志访问控制: Elasticsearch配置RBAC权限
性能优化
- 异步写日志: 使用Monolog的BufferHandler批量写入
- 日志轮转: 配置logrotate或Docker日志驱动
- 采样策略: 高并发场景下对debug日志采样
成本控制
- 冷热数据分层: 超过7天的日志迁移到冷节点
- 索引生命周期:
PUT _ilm/policy/php_logs_policy { "policy": { "phases": { "hot": { "min_age": "0d", "actions": { "rollover": { "max_size": "50GB" } } }, "warm": { "min_age": "3d", "actions": { "allocate": { "require": { "data": "warm" } } } }, "delete": { "min_age": "30d", "actions": { "delete": {} } } } } }
推荐替代方案
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| ELK | 复杂检索、大集群 | 功能强大,生态完善 | 资源消耗较高 |
| Loki + Grafana | 轻量级、成本敏感 | 占用资源少,与K8s集成好 | 检索功能较弱 |
| Datadog | 预算充足的企业 | SaaS服务,开箱即用 | 成本高 |
| Graylog | 中小团队 | 比ELK更简单,Web界面友好 | 扩展性不如ELK |
最终建议
- 小规模(<5个服务): 使用 Loki + Promtail + Grafana,最低配置2核4G即可运行
- 中大规模: 采用 ELK 或 EFK,建议加上Kafka做缓冲
- Kubernetes环境: 使用 Loki 的Helm Chart,配置简单
- 必须标准化: PHP端统一使用Monolog输出JSON格式日志
- 优先实现: 链路追踪ID、请求耗时、服务名这三个核心字段
实施时建议先从1-2个服务做试点,验证架构可行性后再推广到全部微服务。