| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- <?php
- namespace App\Module\OpenAPI\Services;
- use App\Module\OpenAPI\Models\OpenApiLog;
- use Illuminate\Http\Request;
- use Illuminate\Support\Str;
- /**
- * OpenAPI日志服务
- *
- * 负责记录和管理API调用日志
- */
- class LogService
- {
- /**
- * 记录API调用日志
- *
- * @param string $appId
- * @param Request $request
- * @param array $response
- * @param int $responseTime 响应时间(毫秒)
- * @param string|null $errorMessage
- * @return OpenApiLog
- */
- public function logApiCall(
- string $appId,
- Request $request,
- array $response,
- int $responseTime,
- ?string $errorMessage = null
- ): OpenApiLog {
- return OpenApiLog::create([
- 'app_id' => $appId,
- 'request_id' => $this->generateRequestId(),
- 'method' => $request->getMethod(),
- 'uri' => $request->getRequestUri(),
- 'headers' => $this->sanitizeHeaders($request->headers->all()),
- 'query_params' => $request->query->all(),
- 'body' => $this->sanitizeBody($request->getContent()),
- 'response_status' => $response['status'] ?? 200,
- 'response_headers' => $response['headers'] ?? [],
- 'response_body' => $this->sanitizeResponseBody($response['body'] ?? ''),
- 'response_time' => $responseTime,
- 'ip_address' => $request->ip(),
- 'user_agent' => $request->userAgent(),
- 'error_message' => $errorMessage,
- ]);
- }
- /**
- * 记录认证失败日志
- *
- * @param Request $request
- * @param string $reason
- * @return OpenApiLog
- */
- public function logAuthFailure(Request $request, string $reason): OpenApiLog
- {
- return OpenApiLog::create([
- 'app_id' => 'UNKNOWN',
- 'request_id' => $this->generateRequestId(),
- 'method' => $request->getMethod(),
- 'uri' => $request->getRequestUri(),
- 'headers' => $this->sanitizeHeaders($request->headers->all()),
- 'query_params' => $request->query->all(),
- 'body' => $this->sanitizeBody($request->getContent()),
- 'response_status' => 401,
- 'response_headers' => [],
- 'response_body' => json_encode(['error' => 'unauthorized', 'message' => $reason]),
- 'response_time' => 0,
- 'ip_address' => $request->ip(),
- 'user_agent' => $request->userAgent(),
- 'error_message' => "认证失败: {$reason}",
- ]);
- }
- /**
- * 记录限流日志
- *
- * @param string $appId
- * @param Request $request
- * @param string $limitType
- * @return OpenApiLog
- */
- public function logRateLimit(string $appId, Request $request, string $limitType): OpenApiLog
- {
- return OpenApiLog::create([
- 'app_id' => $appId,
- 'request_id' => $this->generateRequestId(),
- 'method' => $request->getMethod(),
- 'uri' => $request->getRequestUri(),
- 'headers' => $this->sanitizeHeaders($request->headers->all()),
- 'query_params' => $request->query->all(),
- 'body' => $this->sanitizeBody($request->getContent()),
- 'response_status' => 429,
- 'response_headers' => [],
- 'response_body' => json_encode(['error' => 'rate_limit_exceeded', 'message' => '请求频率超出限制']),
- 'response_time' => 0,
- 'ip_address' => $request->ip(),
- 'user_agent' => $request->userAgent(),
- 'error_message' => "限流触发: {$limitType}",
- ]);
- }
- /**
- * 获取应用的调用统计
- *
- * @param string $appId
- * @param string $period 统计周期:day, week, month
- * @return array
- */
- public function getAppStats(string $appId, string $period = 'day'): array
- {
- $startDate = match($period) {
- 'week' => now()->subWeek(),
- 'month' => now()->subMonth(),
- default => now()->subDay(),
- };
- $logs = OpenApiLog::where('app_id', $appId)
- ->where('created_at', '>=', $startDate)
- ->get();
- return [
- 'total_requests' => $logs->count(),
- 'successful_requests' => $logs->where('response_status', '>=', 200)->where('response_status', '<', 300)->count(),
- 'client_errors' => $logs->where('response_status', '>=', 400)->where('response_status', '<', 500)->count(),
- 'server_errors' => $logs->where('response_status', '>=', 500)->count(),
- 'avg_response_time' => $logs->avg('response_time'),
- 'max_response_time' => $logs->max('response_time'),
- 'min_response_time' => $logs->min('response_time'),
- ];
- }
- /**
- * 生成请求ID
- *
- * @return string
- */
- protected function generateRequestId(): string
- {
- return 'req_' . Str::random(16) . '_' . time();
- }
- /**
- * 清理请求头信息(移除敏感信息)
- *
- * @param array $headers
- * @return array
- */
- protected function sanitizeHeaders(array $headers): array
- {
- $sensitiveHeaders = [
- 'authorization',
- 'x-api-key',
- 'x-api-secret',
- 'cookie',
- 'set-cookie',
- ];
- $sanitized = [];
- foreach ($headers as $key => $value) {
- if (in_array(strtolower($key), $sensitiveHeaders)) {
- $sanitized[$key] = ['***REDACTED***'];
- } else {
- $sanitized[$key] = $value;
- }
- }
- return $sanitized;
- }
- /**
- * 清理请求体(移除敏感信息)
- *
- * @param string $body
- * @return string
- */
- protected function sanitizeBody(string $body): string
- {
- // 限制请求体大小
- if (strlen($body) > 10240) { // 10KB
- return substr($body, 0, 10240) . '...[TRUNCATED]';
- }
- // 如果是JSON,尝试移除敏感字段
- $decoded = json_decode($body, true);
- if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
- $sensitiveFields = ['password', 'secret', 'token', 'key'];
-
- foreach ($sensitiveFields as $field) {
- if (isset($decoded[$field])) {
- $decoded[$field] = '***REDACTED***';
- }
- }
-
- return json_encode($decoded);
- }
- return $body;
- }
- /**
- * 清理响应体
- *
- * @param string $body
- * @return string
- */
- protected function sanitizeResponseBody(string $body): string
- {
- // 限制响应体大小
- if (strlen($body) > 10240) { // 10KB
- return substr($body, 0, 10240) . '...[TRUNCATED]';
- }
- return $body;
- }
- }
|