isConfigured()) { $this->error('SLS 服务未配置,请检查 .env 中的 SLS_* 配置项'); return Command::FAILURE; } if (!$aiService->isConfigured()) { $this->error('AI 服务未配置,请在页面上配置 AI 提供商或设置 .env 中的 AI_* 配置项'); return Command::FAILURE; } // 解析时间参数 $from = $this->parseTime($this->option('from') ?? '-1h'); $to = $this->parseTime($this->option('to') ?? 'now'); if ($from >= $to) { $this->error('开始时间必须早于结束时间'); return Command::FAILURE; } // 解析分析模式 $modeOption = $this->option('mode'); $mode = $modeOption === 'logs+code' ? AnalysisMode::LogsWithCode : AnalysisMode::Logs; $query = $this->option('query'); $this->info("开始分析日志..."); $this->line(" 时间范围: {$from->format('Y-m-d H:i:s')} ~ {$to->format('Y-m-d H:i:s')}"); $this->line(" 查询语句: " . ($query ?: '*')); $this->line(" 分析模式: {$mode->label()}"); $this->newLine(); try { $result = $analysisService->analyze( $from, $to, $query, $mode, !$this->option('no-save') ); // 输出到文件 if ($outputPath = $this->option('output')) { $json = json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); file_put_contents($outputPath, $json); $this->info("报告已保存到: {$outputPath}"); } // 推送到钉钉 if ($this->option('push')) { $this->line("正在推送到钉钉..."); $pushed = $analysisService->pushToNotification($result); if ($pushed) { $this->info("已推送到钉钉"); } else { $this->warn("钉钉推送失败"); } } // 显示摘要 $this->displaySummary($result); return Command::SUCCESS; } catch (\Exception $e) { $this->error("分析失败: {$e->getMessage()}"); return Command::FAILURE; } } /** * 解析时间参数 */ private function parseTime(string $input): Carbon { // 相对时间格式: -1h, -30m, -1d, -2w if (preg_match('/^-(\d+)([hmsdw])$/', $input, $matches)) { $value = (int) $matches[1]; $unit = $matches[2]; return match ($unit) { 'h' => Carbon::now()->subHours($value), 'm' => Carbon::now()->subMinutes($value), 's' => Carbon::now()->subSeconds($value), 'd' => Carbon::now()->subDays($value), 'w' => Carbon::now()->subWeeks($value), default => Carbon::now(), }; } // 特殊值 if ($input === 'now') { return Carbon::now(); } // 尝试解析为日期时间 return Carbon::parse($input); } /** * 显示分析摘要 */ private function displaySummary(array $result): void { $this->newLine(); $this->info('=== 分析摘要 ==='); $this->line("总日志数: {$result['metadata']['total_logs']}"); $this->line("分析应用数: {$result['metadata']['apps_analyzed']}"); $this->line("执行时间: {$result['metadata']['execution_time_ms']}ms"); $this->newLine(); if (empty($result['results'])) { $this->warn('未找到匹配的日志'); return; } foreach ($result['results'] as $appName => $appResult) { $this->line("【{$appName}】"); if (isset($appResult['error'])) { $this->error(" 分析失败: {$appResult['error']}"); continue; } $impact = $appResult['impact'] ?? 'unknown'; $impactColor = match ($impact) { 'high' => 'red', 'medium' => 'yellow', 'low' => 'green', default => 'white', }; $this->line(" 日志数: {$appResult['log_count']}"); $this->line(" 代码上下文: " . ($appResult['has_code_context'] ? '是' : '否')); $this->line(" 影响级别: {$impact}"); $this->line(" 摘要: " . ($appResult['summary'] ?? 'N/A')); $anomalies = $appResult['core_anomalies'] ?? []; if (!empty($anomalies)) { $this->line(" 异常数: " . count($anomalies)); $table = []; foreach (array_slice($anomalies, 0, 5) as $anomaly) { $table[] = [ $anomaly['type'] ?? 'N/A', $anomaly['classification'] ?? 'N/A', $anomaly['count'] ?? 1, mb_substr($anomaly['possible_cause'] ?? 'N/A', 0, 40), ]; } $this->table(['类型', '分类', '数量', '可能原因'], $table); } $this->newLine(); } } }