UserLogScheduleService.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. <?php
  2. namespace App\Module\Game\Services;
  3. use App\Module\Game\Jobs\CollectUserLogJob;
  4. use App\Module\Game\Logics\UserLogCollectorManager;
  5. use Illuminate\Support\Facades\Log;
  6. /**
  7. * 用户日志调度服务
  8. *
  9. * 负责管理用户日志收集的调度任务
  10. */
  11. class UserLogScheduleService
  12. {
  13. /**
  14. * 执行日志收集(同步方式)
  15. *
  16. * @param string|null $collectorName 收集器名称,null表示执行所有收集器
  17. * @return array 执行结果
  18. */
  19. public static function collectNow(?string $collectorName = null): array
  20. {
  21. try {
  22. $manager = new UserLogCollectorManager();
  23. if ($collectorName) {
  24. return $manager->collectByName($collectorName);
  25. } else {
  26. return $manager->collectAll();
  27. }
  28. } catch (\Exception $e) {
  29. Log::error('同步执行日志收集失败', [
  30. 'collector' => $collectorName,
  31. 'error' => $e->getMessage()
  32. ]);
  33. return [
  34. 'status' => 'error',
  35. 'error' => $e->getMessage(),
  36. 'timestamp' => now()->toDateTimeString()
  37. ];
  38. }
  39. }
  40. /**
  41. * 调度日志收集任务(异步方式)
  42. *
  43. * @param string|null $collectorName 收集器名称,null表示执行所有收集器
  44. * @return void
  45. */
  46. public static function scheduleCollection(?string $collectorName = null): void
  47. {
  48. CollectUserLogJob::dispatchCollection($collectorName);
  49. }
  50. /**
  51. * 获取收集器信息
  52. *
  53. * @return array
  54. */
  55. public static function getCollectorsInfo(): array
  56. {
  57. try {
  58. $manager = new UserLogCollectorManager();
  59. return $manager->getCollectorsInfo();
  60. } catch (\Exception $e) {
  61. Log::error('获取收集器信息失败', [
  62. 'error' => $e->getMessage()
  63. ]);
  64. return [];
  65. }
  66. }
  67. /**
  68. * 重置收集器进度
  69. *
  70. * @param string|null $collectorName 收集器名称,null表示重置所有收集器
  71. * @return bool
  72. */
  73. public static function resetCollector(?string $collectorName = null): bool
  74. {
  75. try {
  76. $manager = new UserLogCollectorManager();
  77. if ($collectorName) {
  78. $manager->resetCollector($collectorName);
  79. } else {
  80. $manager->resetAllCollectors();
  81. }
  82. return true;
  83. } catch (\Exception $e) {
  84. Log::error('重置收集器进度失败', [
  85. 'collector' => $collectorName,
  86. 'error' => $e->getMessage()
  87. ]);
  88. return false;
  89. }
  90. }
  91. /**
  92. * 检查收集器状态
  93. *
  94. * @return array
  95. */
  96. public static function checkCollectorsStatus(): array
  97. {
  98. try {
  99. $manager = new UserLogCollectorManager();
  100. $collectorsInfo = $manager->getCollectorsInfo();
  101. $status = [];
  102. foreach ($collectorsInfo as $name => $info) {
  103. $cacheKey = "user_log_collector:last_processed_id:{$info['source_table']}";
  104. $lastProcessedId = \Illuminate\Support\Facades\Cache::get($cacheKey, 0);
  105. $status[$name] = [
  106. 'name' => $name,
  107. 'source_table' => $info['source_table'],
  108. 'source_type' => $info['source_type'],
  109. 'last_processed_id' => $lastProcessedId,
  110. 'last_check_time' => now()->toDateTimeString(),
  111. ];
  112. }
  113. return $status;
  114. } catch (\Exception $e) {
  115. Log::error('检查收集器状态失败', [
  116. 'error' => $e->getMessage()
  117. ]);
  118. return [];
  119. }
  120. }
  121. /**
  122. * 获取收集统计信息
  123. *
  124. * @param int $days 统计天数
  125. * @return array
  126. */
  127. public static function getCollectionStats(int $days = 7): array
  128. {
  129. try {
  130. $stats = [
  131. 'period' => "{$days}天",
  132. 'start_date' => now()->subDays($days)->toDateString(),
  133. 'end_date' => now()->toDateString(),
  134. 'total_logs' => 0,
  135. 'daily_stats' => [],
  136. 'source_type_stats' => [],
  137. ];
  138. // 获取总日志数
  139. $totalLogs = \App\Module\Game\Models\UserLog::where('created_at', '>=', now()->subDays($days))
  140. ->count();
  141. $stats['total_logs'] = $totalLogs;
  142. // 获取每日统计
  143. $dailyStats = \App\Module\Game\Models\UserLog::where('created_at', '>=', now()->subDays($days))
  144. ->selectRaw('DATE(created_at) as date, COUNT(*) as count')
  145. ->groupBy('date')
  146. ->orderBy('date')
  147. ->get()
  148. ->pluck('count', 'date')
  149. ->toArray();
  150. $stats['daily_stats'] = $dailyStats;
  151. // 获取来源类型统计
  152. $sourceTypeStats = \App\Module\Game\Models\UserLog::where('created_at', '>=', now()->subDays($days))
  153. ->selectRaw('source_type, COUNT(*) as count')
  154. ->whereNotNull('source_type')
  155. ->groupBy('source_type')
  156. ->get()
  157. ->pluck('count', 'source_type')
  158. ->toArray();
  159. $stats['source_type_stats'] = $sourceTypeStats;
  160. return $stats;
  161. } catch (\Exception $e) {
  162. Log::error('获取收集统计信息失败', [
  163. 'error' => $e->getMessage()
  164. ]);
  165. return [];
  166. }
  167. }
  168. /**
  169. * 健康检查
  170. *
  171. * @return array
  172. */
  173. public static function healthCheck(): array
  174. {
  175. try {
  176. $health = [
  177. 'status' => 'healthy',
  178. 'checks' => [],
  179. 'timestamp' => now()->toDateTimeString(),
  180. ];
  181. // 检查收集器是否正常注册
  182. $manager = new UserLogCollectorManager();
  183. $collectorsInfo = $manager->getCollectorsInfo();
  184. $health['checks']['collectors_registered'] = [
  185. 'status' => !empty($collectorsInfo) ? 'pass' : 'fail',
  186. 'count' => count($collectorsInfo),
  187. 'details' => array_keys($collectorsInfo),
  188. ];
  189. // 检查最近是否有日志生成
  190. $recentLogsCount = \App\Module\Game\Models\UserLog::where('created_at', '>=', now()->subMinutes(10))
  191. ->count();
  192. $health['checks']['recent_logs'] = [
  193. 'status' => 'info',
  194. 'count' => $recentLogsCount,
  195. 'message' => "最近10分钟生成了 {$recentLogsCount} 条日志",
  196. ];
  197. // 检查数据库连接
  198. try {
  199. \App\Module\Game\Models\UserLog::count();
  200. $health['checks']['database'] = [
  201. 'status' => 'pass',
  202. 'message' => '数据库连接正常',
  203. ];
  204. } catch (\Exception $e) {
  205. $health['checks']['database'] = [
  206. 'status' => 'fail',
  207. 'message' => '数据库连接失败: ' . $e->getMessage(),
  208. ];
  209. $health['status'] = 'unhealthy';
  210. }
  211. return $health;
  212. } catch (\Exception $e) {
  213. return [
  214. 'status' => 'unhealthy',
  215. 'error' => $e->getMessage(),
  216. 'timestamp' => now()->toDateTimeString(),
  217. ];
  218. }
  219. }
  220. }