|
@@ -0,0 +1,181 @@
|
|
|
|
|
+package com.seecoder.ai.alarm.controller;
|
|
|
|
|
+
|
|
|
|
|
+import com.seecoder.ai.alarm.common.ApiResult;
|
|
|
|
|
+import com.seecoder.ai.alarm.dto.LogQueryDTO;
|
|
|
|
|
+import com.seecoder.ai.alarm.service.LogService;
|
|
|
|
|
+import com.seecoder.ai.alarm.vo.LogVO;
|
|
|
|
|
+import org.springframework.data.domain.Page;
|
|
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
|
|
+
|
|
|
|
|
+import jakarta.validation.Valid;
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+
|
|
|
|
|
+@RestController
|
|
|
|
|
+@RequestMapping("/logs")
|
|
|
|
|
+public class LogController {
|
|
|
|
|
+
|
|
|
|
|
+ private final LogService logService;
|
|
|
|
|
+
|
|
|
|
|
+ public LogController(LogService logService) {
|
|
|
|
|
+ this.logService = logService;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取20条模拟日志数据
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ // 保留原有的其他方法...
|
|
|
|
|
+ @PostMapping("/query")
|
|
|
|
|
+ public ApiResult<Page<LogVO>> queryLogs(@Valid @RequestBody LogQueryDTO queryDTO) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Page<LogVO> result = logService.queryLogs(queryDTO);
|
|
|
|
|
+ return ApiResult.success(result);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return ApiResult.error("查询日志失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @GetMapping("/trace/{traceId}")
|
|
|
|
|
+ public ApiResult<Page<LogVO>> queryByTraceId(@RequestParam String traceId) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Page<LogVO> result = logService.queryLogsByTraceId(traceId);
|
|
|
|
|
+ return ApiResult.success(result);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return ApiResult.error("查询trace日志失败: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @PostMapping("/parse")
|
|
|
|
|
+ public ApiResult<LogVO> parseLog(@RequestBody String rawLog) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ LogVO result = logService.parseRawLog(rawLog);
|
|
|
|
|
+ if (result != null) {
|
|
|
|
|
+ return ApiResult.success(result);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return ApiResult.error("日志解析失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return ApiResult.error("解析日志异常: " + e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @GetMapping("/mock-process")
|
|
|
|
|
+ public ApiResult<List<LogVO>> getProcessMockLogs() {
|
|
|
|
|
+ List<LogVO> mockLogs = new ArrayList<>();
|
|
|
|
|
+ String traceId = "" + System.currentTimeMillis(); // 统一的traceId
|
|
|
|
|
+
|
|
|
|
|
+ // 模拟完整的考试系统调用流程
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 门户登录流程
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:30:00.000", "portal-login", "http-nio-8080-exec-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.portal.controller.LoginController", "用户登录请求",
|
|
|
|
|
+ traceId, "0", List.of("userId=10001", "username=student001", "ip=192.168.1.100")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:30:00.100", "portal-login", "auth-service-thread-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.portal.service.AuthService", "验证用户凭证",
|
|
|
|
|
+ traceId, "0.0", List.of("username=student001", "password=encrypted")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:30:00.200", "portal-login", "db-pool-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.portal.repository.UserRepository", "查询用户信息",
|
|
|
|
|
+ traceId, "0.0.0", List.of("sql=SELECT * FROM users WHERE username=?", "params=[student001]")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:30:00.250", "portal-login", "redis-client-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.portal.cache.SessionCache", "生成会话信息",
|
|
|
|
|
+ traceId, "0.0.1", List.of("sessionId=SID123456", "expire=7200")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:30:00.300", "portal-login", "http-nio-8080-exec-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.portal.controller.LoginController", "登录成功返回token",
|
|
|
|
|
+ traceId, "0", List.of("token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", "expires_in=7200")));
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 考试开始流程
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:35:00.000", "coder-exam", "http-nio-8080-exec-2", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.controller.ExamController", "开始考试请求",
|
|
|
|
|
+ traceId, "0.1", List.of("examId=EXAM20251201", "userId=10001")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:35:00.050", "coder-exam", "exam-service-thread-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.service.ExamService", "验证考试权限",
|
|
|
|
|
+ traceId, "0.1.0", List.of("userId=10001", "examId=EXAM20251201", "status=authorized")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:35:00.100", "coder-exam", "question-service-client", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.client.QuestionClient", "获取考试题目列表",
|
|
|
|
|
+ traceId, "0.1.0.0", List.of("examId=EXAM20251201", "count=10")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:35:00.200", "coder-exam", "db-pool-2", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.repository.QuestionRepository", "查询题目详情",
|
|
|
|
|
+ traceId, "0.1.0.0.0", List.of("questionIds=[Q001,Q002,Q003]", "fields=title,content,options")));
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 代码编写和提交流程
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:45:00.000", "coder-exam", "http-nio-8080-exec-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.controller.CodeController", "保存代码草稿",
|
|
|
|
|
+ traceId, "0.2", List.of("examId=EXAM20251201", "questionId=Q001", "language=java")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:45:00.050", "coder-exam", "redis-client-2", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.cache.CodeCache", "缓存代码内容",
|
|
|
|
|
+ traceId, "0.2.0", List.of("key=code:10001:EXAM20251201:Q001", "expire=3600")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:00.000", "coder-exam", "http-nio-8080-exec-2", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.controller.CodeController", "提交最终代码",
|
|
|
|
|
+ traceId, "0.3", List.of("examId=EXAM20251201", "questionId=Q001", "submit=true")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:00.050", "coder-exam", "compile-service-client", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.coder.client.CompileClient", "代码编译请求",
|
|
|
|
|
+ traceId, "0.3.0", List.of("language=java", "source_length=1234", "timeout=30s")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:01.000", "coder-exam", "docker-container-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.compile.Compiler", "执行编译过程",
|
|
|
|
|
+ traceId, "0.3.0.0", List.of("container_id=compile-java-123", "command=javac Main.java")));
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 判题服务调用流程
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:02.000", "jenkins-judge", "judge-worker-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.judge.JudgeService", "开始代码评判",
|
|
|
|
|
+ traceId, "0.3.0.1", List.of("submission_id=SUB20251201001", "question_id=Q001")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:02.100", "jenkins-judge", "test-runner-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.judge.TestCaseRunner", "执行测试用例",
|
|
|
|
|
+ traceId, "0.3.0.1.0", List.of("test_cases=5", "timeout=10s")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:03.500", "jenkins-judge", "result-service-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.judge.ResultService", "汇总评判结果",
|
|
|
|
|
+ traceId, "0.3.0.1.1", List.of("passed=4", "failed=1", "score=80")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:50:03.600", "jenkins-judge", "db-pool-3", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.judge.repository.ResultRepository", "保存评判结果",
|
|
|
|
|
+ traceId, "0.3.0.1.2", List.of("sql=INSERT INTO results VALUES (?, ?, ?)", "params=[SUB20251201001, 80, PASSED]")));
|
|
|
|
|
+
|
|
|
|
|
+ // 5. GitLab代码管理流程
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:55:00.000", "gitlab-manager", "gitlab-client-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.gitlab.GitLabService", "创建代码仓库",
|
|
|
|
|
+ traceId, "0.4", List.of("project_name=exam_EXAM20251201_10001", "visibility=private")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:55:00.500", "gitlab-manager", "http-client-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.gitlab.GitLabClient", "调用GitLab API",
|
|
|
|
|
+ traceId, "0.4.0", List.of("api=/api/v4/projects", "method=POST", "response_code=201")));
|
|
|
|
|
+
|
|
|
|
|
+ mockLogs.add(createProcessLogVO("2025-12-01 14:55:01.000", "gitlab-manager", "webhook-service-1", "INFO",
|
|
|
|
|
+ "com.seecoder.exam.gitlab.WebHookService", "配置仓库Webhook",
|
|
|
|
|
+ traceId, "0.4.1", List.of("url=https://exam-system/callback", "events=[push,merge_request]")));
|
|
|
|
|
+
|
|
|
|
|
+ return ApiResult.success(mockLogs);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 创建流程调用日志的辅助方法
|
|
|
|
|
+ */
|
|
|
|
|
+ private LogVO createProcessLogVO(String timestampStr, String appName, String threadName, String level,
|
|
|
|
|
+ String className, String operation, String traceId, String spanId,
|
|
|
|
|
+ List<String> otherInfo) {
|
|
|
|
|
+ LogVO logVO = new LogVO();
|
|
|
|
|
+ logVO.setTimestamp(LocalDateTime.parse(timestampStr.replace(" ", "T").substring(0, 23)));
|
|
|
|
|
+ logVO.setAppName(appName);
|
|
|
|
|
+ logVO.setThreadName(threadName);
|
|
|
|
|
+ logVO.setLevel(level);
|
|
|
|
|
+ logVO.setClassName(className);
|
|
|
|
|
+ logVO.setTraceId(traceId);
|
|
|
|
|
+ logVO.setSpanId(spanId);
|
|
|
|
|
+ logVO.setOtherInfo(otherInfo);
|
|
|
|
|
+
|
|
|
|
|
+ return logVO;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|