#feature: add AI log analysis & some bugfix

This commit is contained in:
2026-01-14 13:58:50 +08:00
parent e479ed02ea
commit ae6c169f5f
33 changed files with 3898 additions and 164 deletions

View File

@@ -0,0 +1,315 @@
<?php
namespace App\Http\Controllers;
use App\Enums\AnalysisMode;
use App\Services\AiService;
use App\Services\ConfigService;
use App\Services\LogAnalysisService;
use App\Services\SlsService;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class LogAnalysisController extends Controller
{
public function __construct(
private readonly LogAnalysisService $analysisService,
private readonly SlsService $slsService,
private readonly AiService $aiService,
private readonly ConfigService $configService
) {}
/**
* 查询日志(预览,不进行 AI 分析)
*/
public function queryLogs(Request $request): JsonResponse
{
$validated = $request->validate([
'from' => 'required|date',
'to' => 'required|date|after:from',
'query' => 'nullable|string|max:1000',
'limit' => 'nullable|integer|min:1|max:1000',
'logstores' => 'nullable|array',
'logstores.*' => 'string',
]);
if (!$this->slsService->isConfigured()) {
return response()->json([
'success' => false,
'message' => 'SLS 服务未配置,请检查 .env 中的 SLS_* 配置项',
], 400);
}
try {
// 如果指定了多个 logstore使用多 logstore 查询
if (!empty($validated['logstores']) && count($validated['logstores']) > 1) {
$result = $this->analysisService->queryLogsFromMultipleStores(
Carbon::parse($validated['from']),
Carbon::parse($validated['to']),
$validated['query'] ?? null,
$validated['limit'] ?? 100,
$validated['logstores']
);
} else {
// 单个 logstore 查询
$result = $this->analysisService->queryLogs(
Carbon::parse($validated['from']),
Carbon::parse($validated['to']),
$validated['query'] ?? null,
$validated['limit'] ?? 100
);
}
return response()->json([
'success' => true,
'data' => $result,
]);
} catch (\Exception $e) {
$errorMessage = $e->getMessage();
// 优化常见错误提示
if (str_contains($errorMessage, 'key') && str_contains($errorMessage, 'is not config as key value config')) {
$errorMessage = 'SLS 查询语法错误:使用 "字段:值" 语法需要该字段配置为键值索引。建议使用全文搜索(如 "ERROR")或 SQL 语法(如 "* | where level = \"ERROR\""';
} elseif (str_contains($errorMessage, 'ParameterInvalid')) {
$errorMessage = 'SLS 查询参数无效:' . $errorMessage . '。请检查查询语法是否正确';
}
return response()->json([
'success' => false,
'message' => $errorMessage,
], 500);
}
}
/**
* 获取可用的 logstore 列表
*/
public function getLogstores(): JsonResponse
{
if (!$this->slsService->isConfigured()) {
return response()->json([
'success' => false,
'message' => 'SLS 服务未配置',
], 400);
}
try {
$logstores = $this->slsService->getLogstores();
return response()->json([
'success' => true,
'data' => [
'logstores' => $logstores,
],
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => $e->getMessage(),
], 500);
}
}
/**
* 执行异步分析(创建后台任务)
*/
public function analyze(Request $request): JsonResponse
{
$validated = $request->validate([
'from' => 'required|date',
'to' => 'required|date|after:from',
'query' => 'nullable|string|max:1000',
'mode' => 'nullable|in:logs,logs+code',
]);
if (!$this->slsService->isConfigured()) {
return response()->json([
'success' => false,
'message' => 'SLS 服务未配置',
], 400);
}
if (!$this->aiService->isConfigured()) {
return response()->json([
'success' => false,
'message' => 'AI 服务未配置,请在设置页面配置 AI 提供商',
], 400);
}
$mode = ($validated['mode'] ?? 'logs') === 'logs+code'
? AnalysisMode::LogsWithCode
: AnalysisMode::Logs;
try {
// 创建异步分析任务
$report = $this->analysisService->analyzeAsync(
Carbon::parse($validated['from']),
Carbon::parse($validated['to']),
$validated['query'] ?? null,
$mode
);
return response()->json([
'success' => true,
'message' => '分析任务已创建,请在历史报告中查看结果',
'data' => [
'report_id' => $report->id,
'status' => $report->status,
],
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => $e->getMessage(),
], 500);
}
}
/**
* 获取历史报告列表
*/
public function listReports(Request $request): JsonResponse
{
$validated = $request->validate([
'limit' => 'nullable|integer|min:1|max:100',
'offset' => 'nullable|integer|min:0',
]);
$result = $this->analysisService->getReports(
$validated['limit'] ?? 20,
$validated['offset'] ?? 0
);
return response()->json([
'success' => true,
'data' => $result,
]);
}
/**
* 获取单个报告详情
*/
public function getReport(int $id): JsonResponse
{
$report = $this->analysisService->getReport($id);
if (!$report) {
return response()->json([
'success' => false,
'message' => '报告不存在',
], 404);
}
return response()->json([
'success' => true,
'data' => $report,
]);
}
/**
* 获取配置
*/
public function getConfig(): JsonResponse
{
return response()->json([
'success' => true,
'data' => [
'sls_configured' => $this->slsService->isConfigured(),
'ai_configured' => $this->aiService->isConfigured(),
'ai_providers' => $this->aiService->getProviders(),
'active_ai_provider' => $this->aiService->getActiveProvider(),
'app_env_map' => $this->configService->get('log_analysis.app_env_map', []),
'settings' => $this->configService->get('log_analysis.settings', [
'max_logs_per_batch' => 1000,
'max_logs_per_app' => 500,
'default_time_window_minutes' => 60,
'schedule_enabled' => false,
]),
],
]);
}
/**
* 更新配置(需要管理员权限)
*/
public function updateConfig(Request $request): JsonResponse
{
$validated = $request->validate([
'app_env_map' => 'nullable|array',
'settings' => 'nullable|array',
'ai_providers' => 'nullable|array',
'active_ai_provider' => 'nullable|string',
]);
try {
if (isset($validated['app_env_map'])) {
$this->configService->set(
'log_analysis.app_env_map',
$validated['app_env_map'],
'Log analysis app to project/env mapping'
);
}
if (isset($validated['settings'])) {
$this->configService->set(
'log_analysis.settings',
$validated['settings'],
'Log analysis settings'
);
}
if (isset($validated['ai_providers'])) {
$this->aiService->saveProviders($validated['ai_providers']);
}
if (isset($validated['active_ai_provider'])) {
$this->aiService->setActiveProvider($validated['active_ai_provider']);
}
return response()->json([
'success' => true,
'message' => '配置已更新',
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => $e->getMessage(),
], 400);
}
}
/**
* 测试 SLS 连接
*/
public function testSlsConnection(): JsonResponse
{
if (!$this->slsService->isConfigured()) {
return response()->json([
'success' => false,
'message' => 'SLS 服务未配置',
]);
}
$connected = $this->slsService->testConnection();
return response()->json([
'success' => $connected,
'message' => $connected ? 'SLS 连接成功' : 'SLS 连接失败',
]);
}
/**
* 测试 AI 连接
*/
public function testAiConnection(): JsonResponse
{
$result = $this->aiService->testConnection();
return response()->json([
'success' => $result['success'],
'message' => $result['message'],
'data' => $result,
]);
}
}