|
|
@@ -2,19 +2,18 @@
|
|
|
|
|
|
namespace App\Module\Game\Jobs;
|
|
|
|
|
|
-use App\Module\Game\Services\UserLogService;
|
|
|
+use App\Module\Game\Logics\UserLogCollectorManager;
|
|
|
use Illuminate\Bus\Queueable;
|
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
|
use Illuminate\Queue\SerializesModels;
|
|
|
-use Illuminate\Support\Facades\Cache;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
|
/**
|
|
|
* 用户日志收集任务
|
|
|
*
|
|
|
- * 异步批量处理用户日志收集,提升性能
|
|
|
+ * 通过计划任务定时收集各模块的原始日志,转换为用户友好的日志消息
|
|
|
*/
|
|
|
class CollectUserLogJob implements ShouldQueue
|
|
|
{
|
|
|
@@ -35,20 +34,20 @@ class CollectUserLogJob implements ShouldQueue
|
|
|
public $timeout = 60;
|
|
|
|
|
|
/**
|
|
|
- * 日志数据
|
|
|
+ * 指定收集器名称
|
|
|
*
|
|
|
- * @var array
|
|
|
+ * @var string|null
|
|
|
*/
|
|
|
- protected array $logs;
|
|
|
+ protected ?string $collectorName;
|
|
|
|
|
|
/**
|
|
|
* 创建新的任务实例
|
|
|
*
|
|
|
- * @param array $logs 日志数据数组
|
|
|
+ * @param string|null $collectorName 收集器名称,null表示执行所有收集器
|
|
|
*/
|
|
|
- public function __construct(array $logs = [])
|
|
|
+ public function __construct(?string $collectorName = null)
|
|
|
{
|
|
|
- $this->logs = $logs;
|
|
|
+ $this->collectorName = $collectorName;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -59,39 +58,49 @@ class CollectUserLogJob implements ShouldQueue
|
|
|
public function handle(): void
|
|
|
{
|
|
|
try {
|
|
|
- // 如果没有传入日志数据,从缓存中获取
|
|
|
- if (empty($this->logs)) {
|
|
|
- $this->logs = $this->getLogsFromCache();
|
|
|
- }
|
|
|
-
|
|
|
- if (empty($this->logs)) {
|
|
|
- Log::info('用户日志收集任务:没有待处理的日志');
|
|
|
- return;
|
|
|
- }
|
|
|
+ $manager = new UserLogCollectorManager();
|
|
|
|
|
|
- // 批量记录日志
|
|
|
- $success = UserLogService::batchLog($this->logs);
|
|
|
+ if ($this->collectorName) {
|
|
|
+ // 执行指定收集器
|
|
|
+ $result = $manager->collectByName($this->collectorName);
|
|
|
|
|
|
- if ($success) {
|
|
|
- Log::info('用户日志收集任务执行成功', [
|
|
|
- 'logs_count' => count($this->logs)
|
|
|
+ Log::info('用户日志收集任务执行完成', [
|
|
|
+ 'collector' => $this->collectorName,
|
|
|
+ 'processed_count' => $result['processed_count'],
|
|
|
+ 'execution_time' => $result['execution_time'],
|
|
|
+ 'status' => $result['status']
|
|
|
]);
|
|
|
|
|
|
- // 清理缓存
|
|
|
- $this->clearLogsCache();
|
|
|
+ if ($result['status'] === 'error') {
|
|
|
+ throw new \Exception("收集器 {$this->collectorName} 执行失败: {$result['error']}");
|
|
|
+ }
|
|
|
} else {
|
|
|
- Log::error('用户日志收集任务执行失败', [
|
|
|
- 'logs_count' => count($this->logs)
|
|
|
+ // 执行所有收集器
|
|
|
+ $results = $manager->collectAll();
|
|
|
+
|
|
|
+ Log::info('用户日志收集任务执行完成', [
|
|
|
+ 'total_processed' => $results['total_processed'],
|
|
|
+ 'total_execution_time' => $results['total_execution_time'],
|
|
|
+ 'collectors_count' => count($results['collectors'])
|
|
|
]);
|
|
|
|
|
|
- // 任务失败,重新抛出异常以触发重试
|
|
|
- throw new \Exception('批量记录用户日志失败');
|
|
|
+ // 检查是否有失败的收集器
|
|
|
+ $failedCollectors = [];
|
|
|
+ foreach ($results['collectors'] as $name => $result) {
|
|
|
+ if ($result['status'] === 'error') {
|
|
|
+ $failedCollectors[] = $name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!empty($failedCollectors)) {
|
|
|
+ throw new \Exception('部分收集器执行失败: ' . implode(', ', $failedCollectors));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
Log::error('用户日志收集任务异常', [
|
|
|
+ 'collector' => $this->collectorName,
|
|
|
'error' => $e->getMessage(),
|
|
|
- 'logs_count' => count($this->logs),
|
|
|
'attempt' => $this->attempts()
|
|
|
]);
|
|
|
|
|
|
@@ -109,117 +118,33 @@ class CollectUserLogJob implements ShouldQueue
|
|
|
public function failed(\Throwable $exception): void
|
|
|
{
|
|
|
Log::error('用户日志收集任务最终失败', [
|
|
|
+ 'collector' => $this->collectorName,
|
|
|
'error' => $exception->getMessage(),
|
|
|
- 'logs_count' => count($this->logs),
|
|
|
'attempts' => $this->attempts()
|
|
|
]);
|
|
|
|
|
|
// 可以在这里实现失败后的补偿机制
|
|
|
- // 比如将失败的日志保存到文件或发送告警
|
|
|
+ // 比如发送告警通知或记录到特殊日志文件
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 从缓存中获取待处理的日志
|
|
|
- *
|
|
|
- * @return array
|
|
|
- */
|
|
|
- private function getLogsFromCache(): array
|
|
|
- {
|
|
|
- $cacheKey = 'user_logs_queue';
|
|
|
- $logs = Cache::get($cacheKey, []);
|
|
|
-
|
|
|
- return is_array($logs) ? $logs : [];
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 清理日志缓存
|
|
|
+ * 静态方法:调度日志收集任务
|
|
|
*
|
|
|
+ * @param string|null $collectorName 收集器名称,null表示执行所有收集器
|
|
|
* @return void
|
|
|
*/
|
|
|
- private function clearLogsCache(): void
|
|
|
+ public static function dispatchCollection(?string $collectorName = null): void
|
|
|
{
|
|
|
- $cacheKey = 'user_logs_queue';
|
|
|
- Cache::forget($cacheKey);
|
|
|
- Cache::forget($cacheKey . '_count');
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 静态方法:添加日志到队列
|
|
|
- *
|
|
|
- * @param int $userId 用户ID
|
|
|
- * @param string $message 日志消息
|
|
|
- * @param string|null $sourceType 来源类型
|
|
|
- * @param int|null $sourceId 来源记录ID
|
|
|
- * @param string|null $sourceTable 来源表名
|
|
|
- * @return void
|
|
|
- */
|
|
|
- public static function addLogToQueue(
|
|
|
- int $userId,
|
|
|
- string $message,
|
|
|
- ?string $sourceType = null,
|
|
|
- ?int $sourceId = null,
|
|
|
- ?string $sourceTable = null
|
|
|
- ): void {
|
|
|
try {
|
|
|
- $cacheKey = 'user_logs_queue';
|
|
|
- $countKey = $cacheKey . '_count';
|
|
|
-
|
|
|
- // 构建日志数据
|
|
|
- $logData = [
|
|
|
- 'user_id' => $userId,
|
|
|
- 'message' => $message,
|
|
|
- 'source_type' => $sourceType,
|
|
|
- 'source_id' => $sourceId,
|
|
|
- 'source_table' => $sourceTable,
|
|
|
- 'created_at' => now()->toDateTimeString(),
|
|
|
- ];
|
|
|
-
|
|
|
- // 添加到缓存队列
|
|
|
- $logs = Cache::get($cacheKey, []);
|
|
|
- $logs[] = $logData;
|
|
|
- Cache::put($cacheKey, $logs, 3600); // 缓存1小时
|
|
|
-
|
|
|
- // 更新计数
|
|
|
- $count = Cache::increment($countKey, 1);
|
|
|
- if (!$count) {
|
|
|
- Cache::put($countKey, 1, 3600);
|
|
|
- $count = 1;
|
|
|
- }
|
|
|
+ self::dispatch($collectorName);
|
|
|
|
|
|
- // 当队列达到一定数量时,触发批量处理
|
|
|
- if ($count >= config('game.user_log.batch_size', 100)) {
|
|
|
- self::dispatch($logs);
|
|
|
- }
|
|
|
-
|
|
|
- } catch (\Exception $e) {
|
|
|
- Log::error('添加日志到队列失败', [
|
|
|
- 'user_id' => $userId,
|
|
|
- 'message' => $message,
|
|
|
- 'error' => $e->getMessage()
|
|
|
+ Log::info('调度用户日志收集任务', [
|
|
|
+ 'collector' => $collectorName ?? 'all'
|
|
|
]);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 静态方法:强制处理队列中的所有日志
|
|
|
- *
|
|
|
- * @return void
|
|
|
- */
|
|
|
- public static function flushQueue(): void
|
|
|
- {
|
|
|
- try {
|
|
|
- $cacheKey = 'user_logs_queue';
|
|
|
- $logs = Cache::get($cacheKey, []);
|
|
|
-
|
|
|
- if (!empty($logs)) {
|
|
|
- self::dispatch($logs);
|
|
|
- Log::info('强制处理用户日志队列', [
|
|
|
- 'logs_count' => count($logs)
|
|
|
- ]);
|
|
|
- }
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
- Log::error('强制处理用户日志队列失败', [
|
|
|
+ Log::error('调度用户日志收集任务失败', [
|
|
|
+ 'collector' => $collectorName,
|
|
|
'error' => $e->getMessage()
|
|
|
]);
|
|
|
}
|