123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- package io.github.qifan777.knowledge.code.arthas;
- import com.fasterxml.jackson.annotation.JsonProperty;
- import com.fasterxml.jackson.annotation.JsonPropertyDescription;
- import com.fasterxml.jackson.databind.JsonNode;
- import io.github.qifan777.knowledge.code.graph.entity.MethodNode;
- import io.github.qifan777.knowledge.code.graph.service.CodeGraphService;
- import io.github.qifan777.knowledge.infrastructure.code.CodeAssistantProperties;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.experimental.Accessors;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.ai.chat.model.ChatModel;
- import org.springframework.ai.chat.prompt.PromptTemplate;
- import org.springframework.context.annotation.Description;
- import org.springframework.http.HttpEntity;
- import org.springframework.http.HttpHeaders;
- import org.springframework.http.HttpMethod;
- import org.springframework.stereotype.Service;
- import org.springframework.web.client.RestTemplate;
- import java.nio.charset.StandardCharsets;
- import java.util.Base64;
- import java.util.List;
- import java.util.Map;
- import java.util.function.Function;
- import java.util.stream.Collectors;
- @Slf4j
- @Service
- @AllArgsConstructor
- @Description("诊断方法出现异常的原因")
- public class ArthasFunction implements Function<ArthasFunction.Request, String> {
- private final CodeGraphService codeGraphService;
- private final CodeAssistantProperties properties;
- private final ChatModel chatModel;
- public record Request(@JsonProperty(required = true)
- @JsonPropertyDescription("类名") String className,
- @JsonProperty(required = true)
- @JsonPropertyDescription("类名") String methodName) {
- }
- @Override
- public String apply(Request request) {
- String methodId = request.className + "#" + request.methodName;
- log.info("监听目标:{}", methodId);
- JobResult jobResult = startWatch(request.className, request.methodName);
- if (jobResult == null) {
- return "无异常信息";
- }
- String analyzeResult = jobResult
- .getBody()
- .getResults()
- .stream()
- .filter(r -> r.getType().equals("tt"))
- .findFirst()
- .map(result -> {
- String methods = codeGraphService.findChildMethods(methodId).stream().map(MethodNode::getContent)
- .distinct()
- .collect(Collectors.joining("\n"));
- TimeFragment timeFragment = result.getTimeFragmentList().get(0);
- String content = new PromptTemplate("""
- 根据下面提供的内容分析异常原因,回答结果用中文
- 方法名称:{methodName}
- 方法调用链: {methods}
- 方法参数:{params}
- 异常信息:{exp}
- """)
- .createMessage(Map.of("methodName", timeFragment.getMethodName(),
- "methods", methods,
- "params", timeFragment.getParams().stream().map(param -> param.getObject() == null ? "" : param.getObject().toString()).collect(Collectors.joining("\n")),
- "exp", timeFragment.getThrowExp()))
- .getContent();
- log.info("代码诊断prompt: {}", content);
- return chatModel.call(content);
- })
- .orElse("无异常信息");
- log.info("诊断结果: {}", analyzeResult);
- return analyzeResult;
- }
- public JobResult startWatch(String className, String method) {
- CodeAssistantProperties.ArthasProperties arthasProperties = properties.getArthas();
- RestTemplate restTemplate = new RestTemplate();
- String encode = Base64.getEncoder().encodeToString((arthasProperties.getUsername() + ":" + arthasProperties.getPassword()).getBytes(StandardCharsets.UTF_8));
- ArthasRequest arthasRequest = new ArthasRequest().setAction("exec").setCommand("tt -t " + className + " " + method + " -n 1");
- HttpHeaders httpHeaders = new HttpHeaders();
- httpHeaders.add("Authorization", "Basic " + encode);
- HttpEntity<ArthasRequest> requestHttpEntity = new HttpEntity<>(arthasRequest, httpHeaders);
- return restTemplate.exchange(arthasProperties.getUrl(), HttpMethod.POST, requestHttpEntity, JobResult.class).getBody();
- }
- @Accessors(chain = true)
- @Data
- public static class ArthasRequest {
- private String action;
- private String command;
- }
- @Data
- public static class JobResult {
- @JsonProperty("body")
- private Body body;
- private String message;
- private String sessionId;
- private String state;
- }
- @Data
- public static class Body {
- @JsonProperty("command")
- private String command;
- private int jobId;
- private String jobStatus;
- @JsonProperty("results")
- private List<Result> results;
- @JsonProperty("timeExpired")
- private boolean timeExpired;
- private int timeout;
- }
- @Data
- public static class Result {
- private Effect effect;
- private int jobId;
- private boolean success;
- private String type;
- @JsonProperty("timeFragmentList")
- private List<TimeFragment> timeFragmentList;
- private int statusCode;
- private boolean first;
- }
- @Data
- public static class Effect {
- private int classCount;
- private int cost;
- private int listenerId;
- private int methodCount;
- }
- @Data
- public static class TimeFragment {
- private String className;
- private double cost;
- private int index;
- private String methodName;
- private String object;
- private List<Param> params;
- @JsonProperty("return")
- private boolean isReturn;
- private String returnObj;
- @JsonProperty("throw")
- private boolean isThrow;
- @JsonProperty("throwExp")
- private String throwExp;
- @JsonProperty("timestamp")
- private String timestamp;
- }
- @Data
- public static class Param {
- private int expand;
- private JsonNode object;
- }
- }
|