PHP项目远程日志如何对接收集

wen PHP项目 20

本文目录导读:

PHP项目远程日志如何对接收集

  1. ELK/EFK 方案(最常用)
  2. Rsyslog 方案(轻量级)
  3. Fluentd 方案(高性能)
  4. Redis 缓冲方案(高并发场景)
  5. HTTP API 推送方案
  6. 最佳实践建议
  7. 推荐组合方案

对于PHP项目的远程日志对接收集,可以考虑以下几种主流方案:

ELK/EFK 方案(最常用)

使用 Filebeat + Logstash + Elasticsearch + Kibana

PHP端配置:

// 使用 Monolog 日志库
use Monolog\Logger;
use Monolog\Handler\SocketHandler;
$log = new Logger('app');
$handler = new SocketHandler('tcp://logstash-server:5000');
$handler->setFormatter(new \Monolog\Formatter\JsonFormatter());
$log->pushHandler($handler);

Filebeat 配置:

# filebeat.yml
filebeat.inputs:
- type: log
  paths:
    - /var/log/php/*.log
output.logstash:
  hosts: ["logstash:5044"]

Rsyslog 方案(轻量级)

PHP端配置:

// PHP syslog 发送
openlog('myapp', LOG_PID | LOG_PERROR, LOG_LOCAL0);
syslog(LOG_WARNING, "User login failed: {$username}");
closelog();

Rsyslog 服务端配置:

# /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
$template RemoteLogs,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
*.* ?RemoteLogs

Fluentd 方案(高性能)

PHP端使用 Fluentd Logger:

use Fluent\Logger\FluentLogger;
$logger = new FluentLogger("localhost", "24224");
$logger->post("app.access", [
    "method" => $_SERVER['REQUEST_METHOD'],
    "uri"    => $_SERVER['REQUEST_URI'],
    "time"   => time()
]);

Fluentd 配置:

<source>
  @type forward
  port 24224
</source>
<match app.**>
  @type elasticsearch
  host localhost
  port 9200
  index_name app_logs
</match>

Redis 缓冲方案(高并发场景)

// PHP 端
$redis = new Redis();
$redis->connect('redis-server', 6379);
$redis->rPush('log_queue', json_encode([
    'timestamp' => date('Y-m-d H:i:s'),
    'level'     => 'ERROR',
    'message'   => 'Database connection failed',
    'trace'     => debug_backtrace()
]));
// 消费端脚本(使用 Supervisor 守护)
$redis = new Redis();
$redis->connect('redis-server', 6379);
while ($log = $redis->lPop('log_queue')) {
    // 发送到日志系统
    sendToLogSystem($log);
}

HTTP API 推送方案

// PHP 端
class RemoteLogger {
    private $apiUrl = 'https://log-collector.yourdomain.com/api/logs';
    public function send($level, $message, $context = []) {
        $data = [
            'app_id'     => 'your-app-id',
            'token'      => 'your-auth-token',
            'level'      => $level,
            'message'    => $message,
            'context'    => $context,
            'timestamp'  => date('c'),
            'host'       => gethostname(),
            'php_version'=> PHP_VERSION
        ];
        $ch = curl_init($this->apiUrl);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        curl_setopt($ch, CURLOPT_TIMEOUT, 2); // 非阻塞
        curl_exec($ch);
        curl_close($ch);
    }
}

收集端 API:

// 接收并存储
public function store(Request $request) {
    $log = $request->all();
    // 验证 token
    // 存储到 Elasticsearch/数据库
    // 发送到消息队列
    return response()->json(['status' => 'ok']);
}

最佳实践建议

异步处理(避免影响主流程)

// 使用进程通信
function asyncLog($message) {
    $pipe = '/tmp/php_log_pipe';
    if (!file_exists($pipe)) {
        posix_mkfifo($pipe, 0666);
    }
    $pid = pcntl_fork();
    if ($pid == -1) {
        // fork 失败,直接写入
    } else if ($pid) {
        // 父进程继续
    } else {
        // 子进程处理日志
        $fp = fopen($pipe, 'w');
        fwrite($fp, json_encode($message));
        fclose($fp);
        exit(0);
    }
}

日志格式规范化

// 统一日志格式
function formatLog($level, $message, $context = []) {
    return [
        'id'        => uniqid(),
        'timestamp' => (new DateTime())->format('c'),
        'level'     => $level,
        'message'   => $message,
        'context'   => $context,
        'host'      => gethostname(),
        'pid'       => getmypid(),
        'memory'    => memory_get_usage(true),
        'request_id'=> $_SERVER['HTTP_X_REQUEST_ID'] ?? uniqid()
    ];
}

推荐组合方案

对于大多数场景,推荐:

  • 中小项目:Rsyslog + Logstash + Elasticsearch
  • 大型项目:Filebeat + Kafka + Logstash + Elasticsearch
  • 云原生:Fluentd + 阿里云日志服务/SLS

最终选择取决于:

  1. 日志量大小(每天多少GB)
  2. 实时性要求
  3. 系统复杂度
  4. 运维能力

建议先从小方案开始,随着业务增长逐步升级。

抱歉,评论功能暂时关闭!