| New file |
| | |
| | | package com.zy.acs.manager.common.interceptor; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.zy.acs.framework.common.Cools; |
| | | import com.zy.acs.framework.common.R; |
| | | import com.zy.acs.framework.common.SnowflakeIdWorker; |
| | | import com.zy.acs.manager.common.interceptor.IntegrationOpenApiInterceptor.IntegrationRequestContext; |
| | | import com.zy.acs.manager.common.utils.IpTools; |
| | | import com.zy.acs.manager.manager.entity.IntegrationRecord; |
| | | import com.zy.acs.manager.manager.enums.IntegrationDirectionType; |
| | | import com.zy.acs.manager.manager.enums.StatusType; |
| | | import com.zy.acs.manager.manager.service.IntegrationRecordService; |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Getter; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.jetbrains.annotations.NotNull; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.core.MethodParameter; |
| | | import org.springframework.http.MediaType; |
| | | import org.springframework.http.converter.HttpMessageConverter; |
| | | import org.springframework.http.server.ServerHttpRequest; |
| | | import org.springframework.http.server.ServerHttpResponse; |
| | | import org.springframework.http.server.ServletServerHttpRequest; |
| | | import org.springframework.web.bind.annotation.ControllerAdvice; |
| | | import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; |
| | | |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.util.Date; |
| | | import java.util.UUID; |
| | | |
| | | @Slf4j |
| | | @ControllerAdvice |
| | | public class IntegrationRecordAdvice implements ResponseBodyAdvice<Object> { |
| | | |
| | | private static final String HEADER_APP_KEY = "appkey"; |
| | | private static final String HEADER_CALLER = "caller"; |
| | | |
| | | @Autowired |
| | | private IntegrationRecordService integrationRecordService; |
| | | @Resource |
| | | private SnowflakeIdWorker snowflakeIdWorker; |
| | | |
| | | @Override |
| | | public boolean supports(@NotNull MethodParameter methodParameter, |
| | | @NotNull Class<? extends HttpMessageConverter<?>> aClass) { |
| | | return true; |
| | | } |
| | | |
| | | @Override |
| | | public Object beforeBodyWrite(Object body, |
| | | @NotNull MethodParameter methodParameter, |
| | | @NotNull MediaType mediaType, |
| | | @NotNull Class<? extends HttpMessageConverter<?>> aClass, |
| | | @NotNull ServerHttpRequest serverHttpRequest, |
| | | @NotNull ServerHttpResponse serverHttpResponse) { |
| | | if (!(serverHttpRequest instanceof ServletServerHttpRequest)) { |
| | | return body; |
| | | } |
| | | HttpServletRequest request = ((ServletServerHttpRequest) serverHttpRequest).getServletRequest(); |
| | | IntegrationRequestContext context = IntegrationOpenApiInterceptor.getContext(request); |
| | | if (context == null) { |
| | | return body; |
| | | } |
| | | try { |
| | | IntegrationRecord record = buildRecord(body, request, context); |
| | | integrationRecordService.syncRecord(record); |
| | | } catch (Exception e) { |
| | | log.error("Failed to persist integration log for {}", context.getHandler(), e); |
| | | } |
| | | return body; |
| | | } |
| | | |
| | | private IntegrationRecord buildRecord(Object responseBody, |
| | | HttpServletRequest request, |
| | | IntegrationRequestContext context) { |
| | | Date now = new Date(); |
| | | ResultView resultView = resolveResult(responseBody); |
| | | |
| | | IntegrationRecord record = new IntegrationRecord(); |
| | | record.setUuid(nextUuid()); |
| | | record.setNamespace(context.getNamespace()); |
| | | record.setUrl(context.getUri()); |
| | | record.setAppkey(request.getHeader(HEADER_APP_KEY)); |
| | | record.setCaller(resolveCaller(request)); |
| | | record.setDirection(IntegrationDirectionType.INBOUND.value); |
| | | record.setTimestamp(String.valueOf(context.getStartAt())); |
| | | record.setClientIp(IpTools.gainRealIp(request)); |
| | | record.setRequest(safeToJson(context.getRequestSnapshot())); |
| | | record.setResponse(safeToJson(responseBody)); |
| | | record.setErr(resultView.getError()); |
| | | record.setResult(resultView.getResult()); |
| | | record.setCostMs(cost(context.getStartAt())); |
| | | record.setStatus(StatusType.ENABLE.val); |
| | | record.setCreateTime(now); |
| | | record.setUpdateTime(now); |
| | | record.setMemo(context.getHandler()); |
| | | return record; |
| | | } |
| | | |
| | | private ResultView resolveResult(Object body) { |
| | | if (!(body instanceof R)) { |
| | | return ResultView.unknown(); |
| | | } |
| | | R response = (R) body; |
| | | Integer code = parseInteger(response.get("code")); |
| | | if (code == null) { |
| | | return ResultView.unknown(); |
| | | } |
| | | boolean success = code == 200; |
| | | String error = success ? null : safeToString(response.get("msg")); |
| | | return new ResultView(success ? 1 : 0, error); |
| | | } |
| | | |
| | | private Integer parseInteger(Object codeObj) { |
| | | if (codeObj == null) { |
| | | return null; |
| | | } |
| | | if (codeObj instanceof Integer) { |
| | | return (Integer) codeObj; |
| | | } |
| | | try { |
| | | return Integer.parseInt(String.valueOf(codeObj)); |
| | | } catch (NumberFormatException e) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private String safeToJson(Object value) { |
| | | if (value == null) { |
| | | return null; |
| | | } |
| | | try { |
| | | return JSON.toJSONString(value); |
| | | } catch (Exception e) { |
| | | log.warn("Failed to serialize value for integration log: {}", value.getClass().getName(), e); |
| | | return String.valueOf(value); |
| | | } |
| | | } |
| | | |
| | | private String resolveCaller(HttpServletRequest request) { |
| | | String caller = request.getHeader(HEADER_CALLER); |
| | | if (Cools.isEmpty(caller)) { |
| | | caller = request.getHeader(HEADER_APP_KEY); |
| | | } |
| | | return caller; |
| | | } |
| | | |
| | | private int cost(long startAt) { |
| | | long duration = System.currentTimeMillis() - startAt; |
| | | if (duration < 0) { |
| | | return 0; |
| | | } |
| | | return (int) duration; |
| | | } |
| | | |
| | | private String nextUuid() { |
| | | if (snowflakeIdWorker != null) { |
| | | return String.valueOf(snowflakeIdWorker.nextId()).substring(3); |
| | | } |
| | | return UUID.randomUUID().toString().replace("-", ""); |
| | | } |
| | | |
| | | private String safeToString(Object value) { |
| | | return value == null ? null : String.valueOf(value); |
| | | } |
| | | |
| | | @Getter |
| | | @AllArgsConstructor |
| | | private static class ResultView { |
| | | private final Integer result; |
| | | private final String error; |
| | | |
| | | private static ResultView unknown() { |
| | | return new ResultView(null, null); |
| | | } |
| | | } |
| | | } |