场景:现在项目中对外部服务的调用主要分为三类,RPC方式,REST方式和SDK方式。分别在RPCServiceManager和RestServiceManager以及SDKServiceManager中管理。现在希望的是能够对所有的第三方调用实现日志记录,包括参数,返回值,异常信息。
首先自定义一个枚举类,用来表示第三方调用的类型:
/**
* @author <u>zongtengfei</u>
* @date 2019年10月22日 下午3:19:20
* @Description:
*/
public enum ExternalInvokeType {
RPC, REST, SDK;
}
自定义一个日志记录的注解:
/**
* @author <u>zongtengfei</u>
* @date 2019年10月22日 下午2:48:37
* @Description:第三方调用日志记录
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogRecord {
/**
* 第三方调用方式
*
* @return
*/
ExternalInvokeType type();
/**
* 服务名
*
* @return
*/
String serviceName();
}
定义日志记录切面实现:
/**
* @author zongtengfei
* @date 2019年10月22日 下午2:50:32
* @Description:
*/
@Component
@Aspect
public class LogRecordAspect {
private static final Map<ExternalInvokeType, Logger> loggerFactory = new HashMap<ExternalInvokeType, Logger>(3);
static {
loggerFactory.put(ExternalInvokeType.RPC, LoggerFactory.getLogger("external-rpc"));
loggerFactory.put(ExternalInvokeType.REST, LoggerFactory.getLogger("external-rest"));
loggerFactory.put(ExternalInvokeType.SDK, LoggerFactory.getLogger("external-sdk"));
}
/**
* 记录第三方调用日志
*
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("@annotation(com.yonyou.iuap.message.platform.annotation.LogRecord)")
public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
LogRecord logRecord = method.getAnnotation(LogRecord.class);
ExternalInvokeType type = logRecord.type();
String serviceName = logRecord.serviceName();
Logger logger = loggerFactory.get(type);
String paramsStr = getMethodParams(methodSignature.getParameterNames(), joinPoint.getArgs());
String traceId = generateTraceId();
logger.info(type.name() + " invoke start, " + traceId + "-" + serviceName + "-" + method.getName() + "-"
+ paramsStr);
Object result = null;
try {
result = joinPoint.proceed();
logger.info(traceId + " invoke success with result is : " + JSON.toJSONString(result));
} catch (Exception e) {
logger.info(traceId + " invoke failed with exception : ", e);
throw e;
}
return result;
}
private String getMethodParams(String[] parameterNames, Object[] args) {
StringBuilder paramsStr = new StringBuilder();
for (int i = 0; i < parameterNames.length; i++) {
paramsStr.append(parameterNames[i]).append(":").append(JSON.toJSONString(args[i]));
if (i < parameterNames.length - 1) {
paramsStr.append(",");
}
}
return paramsStr.toString();
}
private String generateTraceId() {
return "" + UUID.randomUUID().toString().replace("-", "") + "";
}
}
以RPCServiceManager为例,我们只需要在对应的方法上加上LogRecord注解,即可实现该方法的日志记录:
@Component
public class ExternalRPCServiceManager {
@Autowired
private IBillEntityQueryService billEntityQueryService;
@LogRecord(type = ExternalInvokeType.RPC, serviceName =
"IBillEntityQueryService")
public List<Map<String, Object>> getBillList(String appcode, String
billLabel) throws Exception {
List<Map<String, Object>> result =
billEntityQueryService.getbillList(appcode, billLabel);
return result;
}
}