package server.debug; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; /** * GET /debug/ws/logs?limit=200&runId=dbg-... */ public class DebugLogsServlet extends HttpServlet { private static final ObjectMapper MAPPER = new ObjectMapper(); private final DebugTokenProvider tokenProvider; public DebugLogsServlet(DebugTokenProvider tokenProvider) { this.tokenProvider = tokenProvider; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { if (!tokenProvider.isEnabled()) { writeError(resp, 503, "DEBUG_DISABLED", "Debug API отключен: .debug-token не найден или пуст"); return; } if (!tokenProvider.matchesBearerHeader(req.getHeader("Authorization"))) { writeError(resp, 401, "UNAUTHORIZED", "Неверный Bearer token"); return; } int limit = parseLimit(req.getParameter("limit")); String runId = safe(req.getParameter("runId")); List list = DebugRunLogBuffer.getInstance().tail(limit, runId); ArrayNode rows = MAPPER.createArrayNode(); for (DebugRunLogBuffer.Entry e : list) { ObjectNode row = MAPPER.createObjectNode(); row.put("ts", e.ts); row.put("level", e.level); row.put("runId", e.runId); row.put("source", e.source); row.put("sessionId", e.sessionId); row.put("login", e.login); row.put("message", e.message); row.put("details", e.details); rows.add(row); } ObjectNode payload = MAPPER.createObjectNode(); payload.put("count", rows.size()); payload.put("limit", limit); payload.put("runIdFilter", runId); payload.set("logs", rows); writeOk(resp, payload); } private static int parseLimit(String raw) { try { int n = Integer.parseInt(String.valueOf(raw)); if (n < 1) return 100; return Math.min(n, 1000); } catch (Exception e) { return 100; } } private static String safe(String value) { return value == null ? "" : value.trim(); } private static void writeOk(HttpServletResponse resp, ObjectNode payload) throws IOException { ObjectNode root = MAPPER.createObjectNode(); root.put("ok", true); root.set("payload", payload == null ? MAPPER.createObjectNode() : payload); writeJson(resp, 200, root); } private static void writeError(HttpServletResponse resp, int status, String code, String message) throws IOException { ObjectNode root = MAPPER.createObjectNode(); root.put("ok", false); root.put("code", code); root.put("message", message); writeJson(resp, status, root); } private static void writeJson(HttpServletResponse resp, int status, ObjectNode root) throws IOException { resp.setStatus(status); resp.setCharacterEncoding("UTF-8"); resp.setContentType("application/json; charset=UTF-8"); resp.getWriter().write(MAPPER.writeValueAsString(root)); } }