LogService.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. <?php
  2. namespace App\Module\ThirdParty\Services;
  3. use App\Module\ThirdParty\Models\ThirdPartyLog;
  4. use App\Module\ThirdParty\Enums\LOG_LEVEL;
  5. use Illuminate\Support\Collection;
  6. /**
  7. * 第三方服务日志服务类
  8. */
  9. class LogService
  10. {
  11. /**
  12. * 创建日志记录
  13. *
  14. * @param array $data
  15. * @return ThirdPartyLog
  16. */
  17. public static function create(array $data): ThirdPartyLog
  18. {
  19. return ThirdPartyLog::createLog($data);
  20. }
  21. /**
  22. * 获取日志列表
  23. *
  24. * @param array $filters
  25. * @param array $options
  26. * @return Collection
  27. */
  28. public static function getList(array $filters = [], array $options = []): Collection
  29. {
  30. $query = ThirdPartyLog::with('service', 'credential');
  31. // 应用过滤条件
  32. if (isset($filters['service_id'])) {
  33. $query->where('service_id', $filters['service_id']);
  34. }
  35. if (isset($filters['credential_id'])) {
  36. $query->where('credential_id', $filters['credential_id']);
  37. }
  38. if (isset($filters['level'])) {
  39. $query->where('level', $filters['level']);
  40. }
  41. if (isset($filters['method'])) {
  42. $query->where('method', $filters['method']);
  43. }
  44. if (isset($filters['status_code'])) {
  45. $query->where('response_status', $filters['status_code']);
  46. }
  47. if (isset($filters['start_date'])) {
  48. $query->where('created_at', '>=', $filters['start_date']);
  49. }
  50. if (isset($filters['end_date'])) {
  51. $query->where('created_at', '<=', $filters['end_date']);
  52. }
  53. if (isset($filters['search'])) {
  54. $search = $filters['search'];
  55. $query->where(function ($q) use ($search) {
  56. $q->where('url', 'like', "%{$search}%")
  57. ->orWhere('request_id', 'like', "%{$search}%")
  58. ->orWhere('error_message', 'like', "%{$search}%");
  59. });
  60. }
  61. // 只查询错误日志
  62. if (isset($filters['errors_only']) && $filters['errors_only']) {
  63. $query->errors();
  64. }
  65. // 应用排序
  66. $sortBy = $options['sort_by'] ?? 'created_at';
  67. $sortOrder = $options['sort_order'] ?? 'desc';
  68. $query->orderBy($sortBy, $sortOrder);
  69. // 应用限制
  70. if (isset($options['limit'])) {
  71. $query->limit($options['limit']);
  72. }
  73. return $query->get();
  74. }
  75. /**
  76. * 获取日志详情
  77. *
  78. * @param int $logId
  79. * @return ThirdPartyLog
  80. */
  81. public static function getById(int $logId): ThirdPartyLog
  82. {
  83. return ThirdPartyLog::with('service', 'credential')->findOrFail($logId);
  84. }
  85. /**
  86. * 获取日志统计信息
  87. *
  88. * @param array $filters
  89. * @return array
  90. */
  91. public static function getStats(array $filters = []): array
  92. {
  93. $query = ThirdPartyLog::query();
  94. // 应用过滤条件
  95. if (isset($filters['service_id'])) {
  96. $query->where('service_id', $filters['service_id']);
  97. }
  98. if (isset($filters['start_date'])) {
  99. $query->where('created_at', '>=', $filters['start_date']);
  100. }
  101. if (isset($filters['end_date'])) {
  102. $query->where('created_at', '<=', $filters['end_date']);
  103. }
  104. $total = $query->count();
  105. $successful = $query->whereBetween('response_status', [200, 299])->count();
  106. $errors = $query->where('response_status', '>=', 400)->count();
  107. // 按级别统计
  108. $levelStats = $query->selectRaw('level, COUNT(*) as count')
  109. ->groupBy('level')
  110. ->pluck('count', 'level')
  111. ->toArray();
  112. // 按状态码统计
  113. $statusStats = $query->selectRaw('response_status, COUNT(*) as count')
  114. ->whereNotNull('response_status')
  115. ->groupBy('response_status')
  116. ->pluck('count', 'response_status')
  117. ->toArray();
  118. // 平均响应时间
  119. $avgResponseTime = $query->whereNotNull('response_time')
  120. ->avg('response_time');
  121. return [
  122. 'total' => $total,
  123. 'successful' => $successful,
  124. 'errors' => $errors,
  125. 'success_rate' => $total > 0 ? round(($successful / $total) * 100, 2) : 0,
  126. 'avg_response_time' => $avgResponseTime ? round($avgResponseTime, 2) : null,
  127. 'by_level' => $levelStats,
  128. 'by_status' => $statusStats,
  129. ];
  130. }
  131. /**
  132. * 获取错误日志
  133. *
  134. * @param array $filters
  135. * @param int $limit
  136. * @return Collection
  137. */
  138. public static function getErrorLogs(array $filters = [], int $limit = 100): Collection
  139. {
  140. $filters['errors_only'] = true;
  141. $options = ['limit' => $limit];
  142. return static::getList($filters, $options);
  143. }
  144. /**
  145. * 获取慢请求日志
  146. *
  147. * @param int $threshold 响应时间阈值(毫秒)
  148. * @param array $filters
  149. * @param int $limit
  150. * @return Collection
  151. */
  152. public static function getSlowLogs(int $threshold = 5000, array $filters = [], int $limit = 100): Collection
  153. {
  154. $query = ThirdPartyLog::with('service', 'credential')
  155. ->where('response_time', '>', $threshold);
  156. // 应用其他过滤条件
  157. if (isset($filters['service_id'])) {
  158. $query->where('service_id', $filters['service_id']);
  159. }
  160. if (isset($filters['start_date'])) {
  161. $query->where('created_at', '>=', $filters['start_date']);
  162. }
  163. if (isset($filters['end_date'])) {
  164. $query->where('created_at', '<=', $filters['end_date']);
  165. }
  166. return $query->orderBy('response_time', 'desc')
  167. ->limit($limit)
  168. ->get();
  169. }
  170. /**
  171. * 清理旧日志
  172. *
  173. * @param int $days 保留天数
  174. * @return int 删除数量
  175. */
  176. public static function cleanup(int $days = 30): int
  177. {
  178. return ThirdPartyLog::where('created_at', '<', now()->subDays($days))->delete();
  179. }
  180. /**
  181. * 导出日志
  182. *
  183. * @param array $filters
  184. * @param string $format
  185. * @return array
  186. */
  187. public static function export(array $filters = [], string $format = 'array'): array
  188. {
  189. $logs = static::getList($filters);
  190. $exported = [];
  191. foreach ($logs as $log) {
  192. $exported[] = [
  193. 'id' => $log->id,
  194. 'service_name' => $log->service->name,
  195. 'service_code' => $log->service->code,
  196. 'request_id' => $log->request_id,
  197. 'method' => $log->method,
  198. 'url' => $log->url,
  199. 'response_status' => $log->response_status,
  200. 'response_time' => $log->response_time,
  201. 'level' => $log->level,
  202. 'error_message' => $log->error_message,
  203. 'user_id' => $log->user_id,
  204. 'ip_address' => $log->ip_address,
  205. 'created_at' => $log->created_at->toDateTimeString(),
  206. ];
  207. }
  208. return $exported;
  209. }
  210. /**
  211. * 获取请求追踪信息
  212. *
  213. * @param string $requestId
  214. * @return ThirdPartyLog|null
  215. */
  216. public static function getByRequestId(string $requestId): ?ThirdPartyLog
  217. {
  218. return ThirdPartyLog::with('service', 'credential')
  219. ->where('request_id', $requestId)
  220. ->first();
  221. }
  222. /**
  223. * 获取用户的调用日志
  224. *
  225. * @param int $userId
  226. * @param array $options
  227. * @return Collection
  228. */
  229. public static function getUserLogs(int $userId, array $options = []): Collection
  230. {
  231. $query = ThirdPartyLog::with('service', 'credential')
  232. ->where('user_id', $userId);
  233. $limit = $options['limit'] ?? 50;
  234. $query->limit($limit);
  235. return $query->orderBy('created_at', 'desc')->get();
  236. }
  237. /**
  238. * 记录API调用
  239. *
  240. * @param array $data
  241. * @return ThirdPartyLog
  242. */
  243. public static function logApiCall(array $data): ThirdPartyLog
  244. {
  245. // 过滤敏感信息
  246. if (isset($data['headers'])) {
  247. $data['headers'] = static::filterSensitiveData($data['headers']);
  248. }
  249. if (isset($data['params'])) {
  250. $data['params'] = static::filterSensitiveData($data['params']);
  251. }
  252. return static::create($data);
  253. }
  254. /**
  255. * 过滤敏感数据
  256. *
  257. * @param array $data
  258. * @return array
  259. */
  260. protected static function filterSensitiveData(array $data): array
  261. {
  262. $sensitiveFields = config('thirdparty.logging.sensitive_fields', []);
  263. foreach ($sensitiveFields as $field) {
  264. if (isset($data[$field])) {
  265. $data[$field] = '***';
  266. }
  267. }
  268. return $data;
  269. }
  270. }