ApiLog.php 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. <?php
  2. namespace App\Http\Middleware;
  3. use Closure;
  4. use Illuminate\Http\Request;
  5. use Symfony\Component\HttpFoundation\Response;
  6. use Illuminate\Support\Facades\Cache;
  7. use Illuminate\Support\Facades\Log;
  8. class ApiLog
  9. {
  10. /**
  11. * Handle an incoming request.
  12. *
  13. * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
  14. */
  15. public function handle(Request $request, Closure $next): Response
  16. {
  17. $response = $next($request);
  18. if (! defined('LARAVEL_START')) {
  19. return $response;
  20. }
  21. $delay = (int) round((microtime(true) - LARAVEL_START) * 1000);
  22. /**
  23. * =========================
  24. * 1. 文件日志(daily)
  25. * =========================
  26. */
  27. Log::channel('daily')->info('api.request', [
  28. 'time' => now()->toTimeString(),
  29. 'delay' => $delay,
  30. 'method' => $request->method(),
  31. 'path' => $request->path(),
  32. 'ip' => $request->ip(),
  33. ]);
  34. /**
  35. * =========================
  36. * 2. 实时监控(Cache / Redis)
  37. * =========================
  38. */
  39. $apiPath = explode('/', trim($request->path(), '/'));
  40. if (count($apiPath) >= 3 && $apiPath[2] !== 'api') {
  41. $apiName = $apiPath[2];
  42. $timeMinute = intdiv(time(), 60);
  43. $timeSecond = time();
  44. // 分钟级统计
  45. $this->updateCache("pref-m/all/{$timeMinute}", $delay);
  46. $this->updateCache("pref-m/{$apiName}/{$timeMinute}", $delay);
  47. // 秒级统计(短期)
  48. $this->updateCache("pref-s/all/{$timeSecond}", $delay, 30);
  49. $this->updateCache("pref-s/{$apiName}/{$timeSecond}", $delay, 30);
  50. }
  51. return $response;
  52. }
  53. private function updateCache(string $key, int $delay, int $ttl = 3600): void
  54. {
  55. $countKey = "{$key}/count";
  56. $delayKey = "{$key}/delay";
  57. // 原子操作(Redis 驱动下安全)
  58. Cache::increment($countKey);
  59. Cache::increment($delayKey, $delay);
  60. // increment 不会刷新 TTL,需手动补
  61. Cache::put($countKey, Cache::get($countKey, 0), $ttl);
  62. Cache::put($delayKey, Cache::get($delayKey, 0), $ttl);
  63. }
  64. }