Files
toolbox/app/Http/Controllers/LogAnalysisController.php

316 lines
9.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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,
]);
}
}