mirror of
https://devops.lemonos.cn/lawson/FendxPHP.git
synced 2026-06-15 23:12:49 +08:00
198 lines
6.1 KiB
PHP
198 lines
6.1 KiB
PHP
|
|
<?php
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace App\Interceptor;
|
||
|
|
|
||
|
|
use Fendx\Core\Aop\JoinPoint;
|
||
|
|
use Fendx\Core\Aop\Advice\AroundAdvice;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 日志拦截器
|
||
|
|
*/
|
||
|
|
class LogInterceptor implements AroundAdvice
|
||
|
|
{
|
||
|
|
public function invoke(JoinPoint $joinPoint): mixed
|
||
|
|
{
|
||
|
|
$startTime = microtime(true);
|
||
|
|
$traceId = \Fendx\Core\Context\Context::getTraceId();
|
||
|
|
|
||
|
|
// 记录请求开始
|
||
|
|
$this->logRequestStart($joinPoint, $traceId);
|
||
|
|
|
||
|
|
try {
|
||
|
|
// 执行目标方法
|
||
|
|
$result = $joinPoint->proceed();
|
||
|
|
|
||
|
|
// 记录请求成功
|
||
|
|
$this->logRequestSuccess($joinPoint, $result, $startTime, $traceId);
|
||
|
|
|
||
|
|
return $result;
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
// 记录请求异常
|
||
|
|
$this->logRequestException($joinPoint, $e, $startTime, $traceId);
|
||
|
|
|
||
|
|
throw $e;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 记录请求开始
|
||
|
|
*/
|
||
|
|
private function logRequestStart(JoinPoint $joinPoint, string $traceId): void
|
||
|
|
{
|
||
|
|
$request = $this->getRequest();
|
||
|
|
$method = $joinPoint->getMethod();
|
||
|
|
$class = $joinPoint->getTarget()::class;
|
||
|
|
|
||
|
|
$logData = [
|
||
|
|
'trace_id' => $traceId,
|
||
|
|
'event' => 'request_start',
|
||
|
|
'class' => $class,
|
||
|
|
'method' => $method,
|
||
|
|
'request_uri' => $request->uri(),
|
||
|
|
'request_method' => $request->method(),
|
||
|
|
'client_ip' => $request->getClientIp(),
|
||
|
|
'user_agent' => $request->userAgent(),
|
||
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
||
|
|
];
|
||
|
|
|
||
|
|
// 记录请求参数(排除敏感信息)
|
||
|
|
$params = $this->filterSensitiveData($request->all());
|
||
|
|
if (!empty($params)) {
|
||
|
|
$logData['request_params'] = $params;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->writeLog('INFO', 'Request started', $logData);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 记录请求成功
|
||
|
|
*/
|
||
|
|
private function logRequestSuccess(JoinPoint $joinPoint, mixed $result, float $startTime, string $traceId): void
|
||
|
|
{
|
||
|
|
$executionTime = round((microtime(true) - $startTime) * 1000, 2);
|
||
|
|
$method = $joinPoint->getMethod();
|
||
|
|
$class = $joinPoint->getTarget()::class;
|
||
|
|
|
||
|
|
$logData = [
|
||
|
|
'trace_id' => $traceId,
|
||
|
|
'event' => 'request_success',
|
||
|
|
'class' => $class,
|
||
|
|
'method' => $method,
|
||
|
|
'execution_time' => $executionTime,
|
||
|
|
'memory_usage' => memory_get_usage(true),
|
||
|
|
'memory_peak' => memory_get_peak_usage(true),
|
||
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
||
|
|
];
|
||
|
|
|
||
|
|
// 记录响应数据(排除敏感信息)
|
||
|
|
if ($result !== null && !is_resource($result)) {
|
||
|
|
$responseData = $this->filterSensitiveData($result);
|
||
|
|
if (is_array($responseData) && count($responseData) > 100) {
|
||
|
|
$logData['response_size'] = count($responseData);
|
||
|
|
$logData['response_type'] = gettype($result);
|
||
|
|
} else {
|
||
|
|
$logData['response_data'] = $responseData;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 性能警告
|
||
|
|
if ($executionTime > 1000) {
|
||
|
|
$logData['performance_warning'] = 'Slow request detected';
|
||
|
|
$this->writeLog('WARNING', 'Slow request completed', $logData);
|
||
|
|
} else {
|
||
|
|
$this->writeLog('INFO', 'Request completed successfully', $logData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 记录请求异常
|
||
|
|
*/
|
||
|
|
private function logRequestException(JoinPoint $joinPoint, \Exception $e, float $startTime, string $traceId): void
|
||
|
|
{
|
||
|
|
$executionTime = round((microtime(true) - $startTime) * 1000, 2);
|
||
|
|
$method = $joinPoint->getMethod();
|
||
|
|
$class = $joinPoint->getTarget()::class;
|
||
|
|
|
||
|
|
$logData = [
|
||
|
|
'trace_id' => $traceId,
|
||
|
|
'event' => 'request_exception',
|
||
|
|
'class' => $class,
|
||
|
|
'method' => $method,
|
||
|
|
'execution_time' => $executionTime,
|
||
|
|
'exception_type' => get_class($e),
|
||
|
|
'exception_code' => $e->getCode(),
|
||
|
|
'exception_message' => $e->getMessage(),
|
||
|
|
'exception_file' => $e->getFile(),
|
||
|
|
'exception_line' => $e->getLine(),
|
||
|
|
'stack_trace' => $e->getTraceAsString(),
|
||
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
||
|
|
];
|
||
|
|
|
||
|
|
$this->writeLog('ERROR', 'Request failed with exception', $logData);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 获取当前请求对象
|
||
|
|
*/
|
||
|
|
private function getRequest(): \Fendx\Web\Request\Request
|
||
|
|
{
|
||
|
|
return \Fendx\Web\Request\Request::createFromGlobals();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 过滤敏感数据
|
||
|
|
*/
|
||
|
|
private function filterSensitiveData(mixed $data): mixed
|
||
|
|
{
|
||
|
|
if (!is_array($data)) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
$sensitiveFields = [
|
||
|
|
'password', 'passwd', 'secret', 'token', 'key',
|
||
|
|
'credit_card', 'bank_account', 'ssn', 'id_card'
|
||
|
|
];
|
||
|
|
|
||
|
|
$filtered = [];
|
||
|
|
foreach ($data as $key => $value) {
|
||
|
|
if (in_array(strtolower($key), $sensitiveFields)) {
|
||
|
|
$filtered[$key] = '***';
|
||
|
|
} elseif (is_array($value)) {
|
||
|
|
$filtered[$key] = $this->filterSensitiveData($value);
|
||
|
|
} else {
|
||
|
|
$filtered[$key] = $value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $filtered;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 写入日志
|
||
|
|
*/
|
||
|
|
private function writeLog(string $level, string $message, array $data): void
|
||
|
|
{
|
||
|
|
$logEntry = [
|
||
|
|
'level' => $level,
|
||
|
|
'message' => $message,
|
||
|
|
'data' => $data,
|
||
|
|
];
|
||
|
|
|
||
|
|
// 这里应该调用实际的日志系统
|
||
|
|
// Log::write($level, $message, $data);
|
||
|
|
|
||
|
|
// 临时实现:写入文件
|
||
|
|
$logFile = runtime_path('logs/app_' . date('Y-m-d') . '.log');
|
||
|
|
$logLine = date('Y-m-d H:i:s') . " [{$level}] {$message} " . json_encode($logEntry, JSON_UNESCAPED_UNICODE) . PHP_EOL;
|
||
|
|
|
||
|
|
$logDir = dirname($logFile);
|
||
|
|
if (!is_dir($logDir)) {
|
||
|
|
mkdir($logDir, 0755, true);
|
||
|
|
}
|
||
|
|
|
||
|
|
file_put_contents($logFile, $logLine, FILE_APPEND | LOCK_EX);
|
||
|
|
}
|
||
|
|
}
|