CollectUserLogsContinuousCommand.php 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. namespace App\Module\Game\Commands;
  3. use App\Module\Game\Logics\UserLogCollectorManager;
  4. use UCore\Command\Command;
  5. /**
  6. * 用户日志持续收集命令
  7. *
  8. * 持续运行的日志收集命令,循环100次后退出,间隔1秒
  9. * 复用CollectUserLogsCommand的核心逻辑
  10. * php artisan game:collect-user-logs-continuous
  11. */
  12. class CollectUserLogsContinuousCommand extends Command
  13. {
  14. /**
  15. * 命令名称和参数
  16. *
  17. * @var string
  18. */
  19. protected $signature = 'game:collect-user-logs-continuous {--detail : 显示详细的处理过程} {--limit=100 : 单次处理最大记录数} {--cycles=100 : 循环次数} {--interval=1 : 间隔秒数}';
  20. /**
  21. * 命令描述
  22. *
  23. * @var string
  24. */
  25. protected $description = '持续收集用户日志,循环指定次数后退出
  26. 选项说明:
  27. --detail 显示详细的处理过程
  28. --limit 单次处理最大记录数(默认100)
  29. --cycles 循环次数(默认100)
  30. --interval 间隔秒数(默认1秒)
  31. 进度追踪机制:
  32. - 基于原始日志ID进行进度追踪,确保不遗漏任何记录
  33. - 每个收集器独立追踪进度,无需手动重置
  34. - 适用于需要持续监控日志收集的场景';
  35. /**
  36. * 执行命令
  37. */
  38. public function handleRun()
  39. {
  40. $detail = $this->option('detail');
  41. $limit = (int)$this->option('limit');
  42. $cycles = (int)$this->option('cycles');
  43. $interval = (int)$this->option('interval');
  44. // 参数验证
  45. if ($cycles <= 0) {
  46. $this->error("❌ 循环次数必须大于0");
  47. return 1;
  48. }
  49. if ($interval <= 0) {
  50. $this->error("❌ 间隔时间不能 <= 0");
  51. return 1;
  52. }
  53. $this->info("🚀 开始持续收集用户日志...");
  54. $this->line("📊 配置信息:");
  55. $this->line(" 🔄 循环次数: <info>{$cycles}</info>");
  56. $this->line(" ⏱️ 间隔时间: <info>{$interval}秒</info>");
  57. $this->line(" 📝 单次限制: <info>{$limit}条</info>");
  58. $this->line("");
  59. $manager = new UserLogCollectorManager();
  60. $totalProcessed = 0;
  61. $totalExecutionTime = 0;
  62. $successfulCycles = 0;
  63. $failedCycles = 0;
  64. $startTime = microtime(true);
  65. for ($i = 1; $i <= $cycles; $i++) {
  66. $this->line("循环 {$i} ");
  67. $cycleStartTime = microtime(true);
  68. try {
  69. if ($detail) {
  70. $this->line("🔄 第 {$i}/{$cycles} 次循环开始...");
  71. }
  72. // 复用原有的收集逻辑
  73. $result = $this->executeTimelineCollection($manager, $limit, $detail);
  74. $cycleEndTime = microtime(true);
  75. $cycleExecutionTime = round(($cycleEndTime - $cycleStartTime) * 1000, 2);
  76. $totalProcessed += $result['processed_count'];
  77. $totalExecutionTime += $cycleExecutionTime;
  78. $successfulCycles++;
  79. if ($detail) {
  80. $this->line("✅ 第 {$i} 次循环完成: 处理 {$result['processed_count']} 条记录,耗时 {$cycleExecutionTime}ms");
  81. } else {
  82. // 简化输出,只显示有处理记录的循环
  83. if ($result['processed_count'] > 0) {
  84. $this->line("✅ 第 {$i} 次: 处理 {$result['processed_count']} 条记录");
  85. }
  86. }
  87. } catch (\Exception $e) {
  88. $failedCycles++;
  89. $this->error("❌ 第 {$i} 次循环失败: {$e->getMessage()}");
  90. if ($detail) {
  91. $this->line("🚨 错误详情: " . $e->getTraceAsString());
  92. }
  93. }
  94. // 如果不是最后一次循环,则等待间隔时间
  95. if ($i < $cycles && $interval > 0) {
  96. if ($detail) {
  97. $this->line("⏳ 等待 {$interval} 秒...");
  98. }
  99. sleep($interval);
  100. }
  101. }
  102. $endTime = microtime(true);
  103. $totalRealTime = round(($endTime - $startTime) * 1000, 2);
  104. // 显示最终统计
  105. $this->displayFinalStatistics($cycles, $successfulCycles, $failedCycles, $totalProcessed, $totalExecutionTime, $totalRealTime);
  106. return $failedCycles > 0 ? 1 : 0;
  107. }
  108. /**
  109. * 执行时间线收集(复用原有逻辑)
  110. *
  111. * @param UserLogCollectorManager $manager
  112. * @param int $limit
  113. * @param bool $detail
  114. * @return array
  115. */
  116. private function executeTimelineCollection(UserLogCollectorManager $manager, int $limit, bool $detail): array
  117. {
  118. $startTime = microtime(true);
  119. // 直接执行所有收集器,传递限制参数
  120. $results = $manager->collectAll($limit);
  121. if ($results['total_processed'] == 0) {
  122. return [
  123. 'processed_count' => 0,
  124. 'execution_time' => round((microtime(true) - $startTime) * 1000, 2),
  125. 'status' => 'success',
  126. 'message' => '没有新记录需要处理',
  127. 'timestamp' => now()->toDateTimeString()
  128. ];
  129. }
  130. if ($detail) {
  131. foreach ($results['collectors'] as $collectorName => $result) {
  132. if ($result['processed_count'] > 0) {
  133. $this->line(" {$collectorName}: 处理了 {$result['processed_count']} 条记录");
  134. }
  135. }
  136. }
  137. $endTime = microtime(true);
  138. return [
  139. 'processed_count' => $results['total_processed'],
  140. 'execution_time' => round(($endTime - $startTime) * 1000, 2),
  141. 'status' => 'success',
  142. 'timestamp' => now()->toDateTimeString(),
  143. 'details' => $results['collectors']
  144. ];
  145. }
  146. /**
  147. * 显示最终统计信息
  148. *
  149. * @param int $totalCycles
  150. * @param int $successfulCycles
  151. * @param int $failedCycles
  152. * @param int $totalProcessed
  153. * @param float $totalExecutionTime
  154. * @param float $totalRealTime
  155. * @return void
  156. */
  157. private function displayFinalStatistics(int $totalCycles, int $successfulCycles, int $failedCycles, int $totalProcessed, float $totalExecutionTime, float $totalRealTime): void
  158. {
  159. $this->line("");
  160. $this->info("🎉 持续收集完成!");
  161. $this->line("");
  162. $this->line("📊 <comment>执行统计</comment>:");
  163. $this->line(" 🔄 总循环次数: <info>{$totalCycles}</info>");
  164. $this->line(" ✅ 成功次数: <info>{$successfulCycles}</info>");
  165. if ($failedCycles > 0) {
  166. $this->line(" ❌ 失败次数: <error>{$failedCycles}</error>");
  167. }
  168. $this->line(" 📝 总处理记录: <info>{$totalProcessed}</info>");
  169. $this->line(" ⏱️ 总执行时间: <info>{$totalExecutionTime}ms</info>");
  170. $this->line(" 🕐 总运行时间: <info>{$totalRealTime}ms</info>");
  171. if ($totalProcessed > 0) {
  172. $avgTimePerRecord = round($totalExecutionTime / $totalProcessed, 2);
  173. $this->line(" 📈 平均处理时间: <info>{$avgTimePerRecord}ms/条</info>");
  174. }
  175. if ($successfulCycles > 0) {
  176. $avgRecordsPerCycle = round($totalProcessed / $successfulCycles, 2);
  177. $this->line(" 📊 平均每次处理: <info>{$avgRecordsPerCycle}条</info>");
  178. }
  179. $successRate = round(($successfulCycles / $totalCycles) * 100, 2);
  180. $this->line(" 🎯 成功率: <info>{$successRate}%</info>");
  181. $this->line("");
  182. }
  183. }