[DUBBO] [2016-08-27 14:47:06] 10.10.50.20:64948 -> 10.10.50.20:20960
- ProductFacadeService getDataDictionaryByType(DataDictionaryParamInfo)
[{"code":0,"type":1}], dubbo version: 2.8.1
自動包含:雙向 IP/端口、調用時間、接口方法、入參、版本信息。
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView);
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}
preHandle:記錄入參、開始時間postHandle:記錄返回值afterCompletion:計算耗時、記錄異常@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLog {
boolean enable() default true;
boolean isLogResult() default false; // 列表查詢建議關閉
boolean isLogParameter() default true;
boolean isLogElapsed() default true;
}
@Aspect
public class ServicesLoggerInterceptor {
@Pointcut("execution(* com.chanjet.csp.product.service.service.impl.*ServiceImpl*.*(..))")
public void pointCut() {}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Stopwatch sw = Stopwatch.createStarted(); // Guava 高精度計時
Object result = joinPoint.proceed();
sw.stop();
long elapsed = sw.elapsed(TimeUnit.NANOSECONDS);
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
MethodLog logAnn = ms.getMethod().getAnnotation(MethodLog.class);
if (logAnn != null && logAnn.enable()) {
StringBuilder log = new StringBuilder(ms.getName());
if (logAnn.isLogParameter()) {
log.append("(");
Object[] args = joinPoint.getArgs();
String[] paramNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();
AspectLogUtils.logParamValues(log, paramNames, args);
log.append(") - started");
}
if (logAnn.isLogResult()) {
log.append(" Return: ").append(AspectLogUtils.toString(result));
}
if (logAnn.isLogElapsed()) {
log.append(" elapsed ns: ").append(elapsed);
}
AspectLogUtils.getLogger().info(log.toString());
}
return result;
}
}
public final class AspectLogUtils {
private static Logger logger = LoggerFactory.getLogger(AspectLogUtils.class);
public static void logParamValues(StringBuilder sb, String[] names, Object[] values) {
for (int i = 0; i < values.length; i++) {
sb.append(names[i]).append("=").append(toString(values[i]));
if (i < values.length - 1) sb.append(", ");
}
}
public static String toString(Object obj) { return JsonUtils.toJsonString(obj); }
public static Logger getLogger() { return logger; }
}
<bean class="ServicesLoggerInterceptor"/> <aop:aspectj-autoproxy proxy-target-class="true"/>
INFO getDataDictionaryByType(dataDictionaryParamInfo={"type":1,"code":0}) - started elapsed nanoseconds:11491670
// ❌ 緊耦合業務代碼,難以維護
public ValueResult query(String appKey, String token) {
log.info("receive query! params: appKey=[" + appKey + "], token=[" + token + "]");
// ...
}
AOP 實現關注點分離,業務代碼零侵入,配置靈活控制日誌粒度。