本文目录导读:

在PHP中实现慢执行日志分离,主要有以下几种方案,我帮你逐一分析:
修改 php.ini 配置(最基础)
; 开启慢日志 slowlog = "/var/log/php/slow.log" request_slowlog_timeout = 2 ; 或者针对PHP-FPM [www] slowlog = /var/log/php-fpm/slow.log request_slowlog_timeout = 2s
优点:实现简单
缺点:只能记录超时脚本,无法自定义记录内容
自定义慢日志类(推荐)
<?php
class SlowLogHandler {
private $threshold;
private $logFile;
private static $instance = null;
private function __construct($threshold = 1) {
$this->threshold = $threshold; // 秒数
$this->logFile = __DIR__ . '/slow_logs_' . date('Y-m-d') . '.log';
}
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 记录慢执行日志
*/
public function log($startTime) {
$elapsed = microtime(true) - $startTime;
if ($elapsed >= $this->threshold) {
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$backtrace = $this->formatBacktrace($trace);
$logData = [
'time' => date('Y-m-d H:i:s'),
'elapsed' => round($elapsed, 3),
'uri' => $_SERVER['REQUEST_URI'] ?? '',
'method' => $_SERVER['REQUEST_METHOD'] ?? '',
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
'memory' => memory_get_usage(true),
'backtrace' => $backtrace,
'server' => gethostname()
];
file_put_contents(
$this->logFile,
json_encode($logData, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT) . "\n",
FILE_APPEND | LOCK_EX
);
}
}
private function formatBacktrace($trace) {
$result = [];
foreach (array_slice($trace, 0, 10) as $item) {
$result[] = sprintf(
"%s:%d %s->%s",
$item['file'] ?? 'unknown',
$item['line'] ?? 0,
$item['class'] ?? '',
$item['function'] ?? ''
);
}
return implode("\n", array_slice($result, 1)); // 跳过log()本身
}
}
使用示例:
<?php
// 在项目入口文件或基类中添加
$startTime = microtime(true);
// 注册关闭函数,在脚本结束时检查
register_shutdown_function(function() {
SlowLogHandler::getInstance()->log($GLOBALS['_start_time']);
});
$GLOBALS['_start_time'] = $startTime;
// 或者使用中间件/拦截器方式
class SlowLogMiddleware {
public function handle($request, $next) {
$start = microtime(true);
$response = $next($request);
$elapsed = microtime(true) - $start;
if ($elapsed > 2) {
error_log("Slow request: {$elapsed}s, " . $request->getUri());
}
return $response;
}
}
数据库查询慢日志
<?php
class QueryLogger {
private $slowQueries = [];
private $threshold = 0.5; // 500ms
public function logQuery($sql, $params, $startTime) {
$elapsed = microtime(true) - $startTime;
if ($elapsed > $this->threshold) {
$this->slowQueries[] = [
'sql' => $this->formatSql($sql, $params),
'elapsed' => $elapsed,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)
];
}
}
public function saveLog() {
if (empty($this->slowQueries)) {
return;
}
$log = [
'datetime' => date('Y-m-d H:i:s'),
'queries' => $this->slowQueries
];
file_put_contents(
'/path/to/sql-slow-log.log',
json_encode($log, JSON_UNESCAPED_UNICODE) . "\n",
FILE_APPEND
);
}
}
// PDO 扩展示例
class SlowQueryPDO extends PDO {
private $slowLogger;
public function query() {
$start = microtime(true);
$result = parent::query(...func_get_args());
$this->checkSlowQuery($start);
return $result;
}
private function checkSlowQuery($startTime) {
$elapsed = microtime(true) - $startTime;
if ($elapsed > 0.5) {
// 记录日志
}
}
}
完善版 - 支持多种记录方式
<?php
interface LogWriterInterface {
public function write(array $logData);
}
class FileLogWriter implements LogWriterInterface {
private $path;
public function __construct($path) {
$this->path = $path;
}
public function write(array $logData) {
file_put_contents(
$this->path,
json_encode($logData, JSON_UNESCAPED_UNICODE) . "\n",
FILE_APPEND | LOCK_EX
);
}
}
class RedisLogWriter implements LogWriterInterface {
private $redis;
private $key;
public function __construct($redis, $key) {
$this->redis = $redis;
$this->key = $key;
}
public function write(array $logData) {
$this->redis->rPush($this->key, json_encode($logData));
$this->redis->expire($this->key, 86400); // 保留1天
}
}
class SlowMonitor {
private $writer;
private $threshold;
private $startTime;
public function __construct(LogWriterInterface $writer, $threshold = 2) {
$this->writer = $writer;
$this->threshold = $threshold;
$this->startTime = microtime(true);
}
public function checkAndLog() {
$elapsed = microtime(true) - $this->startTime;
if ($elapsed < $this->threshold) {
return;
}
$logData = [
'datetime' => date('Y-m-d H:i:s'),
'elapsed' => round($elapsed, 3),
'uri' => $_SERVER['REQUEST_URI'] ?? '',
'method' => $_SERVER['REQUEST_METHOD'] ?? '',
'client' => $_SERVER['REMOTE_ADDR'] ?? '',
'user_agent'=> $_SERVER['HTTP_USER_AGENT'] ?? '',
'memory' => memory_get_usage(true),
'peak_memory' => memory_get_peak_usage(true),
'hostname' => gethostname(),
'php_version' => PHP_VERSION,
'trace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)
];
$this->writer->write($logData);
}
public function __destruct() {
$this->checkAndLog();
}
}
// 使用示例
$writer = new FileLogWriter('/var/log/php/slow-requests.log');
// $writer = new RedisLogWriter($redis, 'slow_requests');
$monitor = new SlowMonitor($writer, 2);
// 在请求结束时调用
register_shutdown_function([$monitor, 'checkAndLog']);
结合框架中间件(Laravel)
// app/Http/Middleware/RequestSlowLogger.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Log;
class RequestSlowLogger
{
public function handle($request, Closure $next)
{
$startTime = microtime(true);
$response = $next($request);
if (config('app.slow_threshold')) {
$elapsed = microtime(true) - $startTime;
if ($elapsed >= config('app.slow_threshold')) {
Log::channel('slow')->info('Slow request', [
'url' => $request->fullUrl(),
'method' => $request->method(),
'elapsed' => round($elapsed, 2),
'memory' => memory_get_peak_usage(true),
'session_id' => $request->session()->getId(),
'user_id' => auth()->id()
]);
}
}
return $response;
}
}
关键建议
- 分级处理:根据耗时不同级别记录(警告、严重)
- 上下文信息:记录请求ID、用户ID、页面URL等
- 日志轮转:使用 logrotate 进行日志分割
- 性能影响:确保日志记录本身不会影响性能
- 监控报警:可以将慢日志接入监控系统(如ELK)
推荐使用方案二或方案四,它们灵活且易于集成到现有项目中,如果需要更专业的性能分析,可以考虑使用 APM 工具(如 Sentry、XHProf)。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播