标签:
先来看下日志对于一个接口服务的作用:
上面的这几点需求,如果接口服务使用的是一些高级产品比如dubbo,其实它已经实现了大部分功能,不需要人为的去全部处理功能。
[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, current host: 10.10.50.20
上面的日志我们可以看到如下有用的信息:
1:调用方IP以及端口信息:10.10.50.20:64948
2:服务端的IP以及端口信息:10.10.50.20:20960
3:调用时间:2016-08-27 14:47:06
4:调用的接口方法:ProductFacadeService getDataDictionaryByType(DataDictionaryParamInfo)
5:调用的接口方法参数:[{"code":0,"type":1}]
其实dubbo自己提供的日志功能已经非常强了,大多数情况下已经够用,但如果想有一些更加强的功能就需要自己想想办法了:
如果你的服务接口不是dubbo,比如是基于spring mvc 实现的rest api接口,那么就没有上面dubbo帮你做的那些好用的日志功能了。但是spring mvc实现上面的日志需求方法也是很多的,典型的例子可以借助HandlerInterceptor这类拦截器,只需要实现这个接口,然后在实现类中增加日志功能即可:我们可以通过handler这个参数来获取你想要的所有数据,另外还有request以及response两个信息丰富的对象供你使用。
public interface HandlerInterceptor { boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception; }
还有一种是自己实现一个AOP功能去解决我们的需求问题。AOP不是这篇的重点,我贴一张图用来简单展示AOP的作用(上面提到的HandlerInterceptor 也属于AOP的具体应用)。
将某些非业务的功能通过拦截的形式注入到流程中,而非紧密耦合在业务逻辑中,比如下面的记录方法参数的代码就是紧耦合,不推荐:
public ValueResult<ApplyIsvRoleInfo> queryUserApplyIsvInfo(String appKey, String accessToken) { log.info("receive queryUserApplyIsvInfo! and the params appKey: [" + appKey + "], accessToken:[" + accessToken + "]"); ...... do something }
AOP我这里使用aspectj,当然也可以使用spring自带的。
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MethodLog { /** * 是否启动日志功能 * @return */ boolean enable() default true; /** * 是否记录返回值 * 列表数据不推荐记录 * @return */ boolean isLogResult() default false; /** * 是否记录方法的参数名称以及值 * @return */ boolean isLogParameter() default true; /** * 是否记录执行时间 * @return */ boolean isLogElapsed() default true; }
a:计算时间,这里采用google提供的Stopwatch,这个东西对于从.NET转JAVA的来讲太亲切了
Stopwatch sw=Stopwatch.createStarted(); Object result = joinPoint.proceed(); sw.stop(); long elapsed=sw.elapsed(TimeUnit.NANOSECONDS);
b:记录参数内容,对于object对象,我们将其序列化成json,可以利用jackson完成,其它的复杂点的就是通过反射来完成参数以及值。记录日志根据注解的配置来判断应该记录哪些日志项。
@Aspect public class ServicesLoggerInterceptor { @Pointcut("execution(* com.chanjet.csp.product.service.service.impl.*ServiceImpl*.*(..))") public void pointCut() { } @Around(value = "pointCut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { Stopwatch sw=Stopwatch.createStarted(); Object result = joinPoint.proceed(); sw.stop(); long elapsed=sw.elapsed(TimeUnit.NANOSECONDS); MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); Method targetMethod = methodSignature.getMethod(); MethodLog methodLog= targetMethod.getAnnotation(MethodLog.class); if(null!=methodLog&&methodLog.enable()){ StringBuilder logLine = new StringBuilder(joinPoint.getSignature().getName()); if(methodLog.isLogParameter()) { Object[] paramValues = joinPoint.getArgs(); CodeSignature codeSignature= ((CodeSignature) joinPoint.getSignature()); String[] paramNames = codeSignature.getParameterNames(); logLine.append("("); if (paramNames.length != 0) { AspectLogUtils.logParamValues(logLine, paramNames, paramValues); } logLine.append(") - started"); } if(methodLog.isLogResult()) { logLine.append(" Return Value : "); logLine.append(AspectLogUtils.toString(result)); } if(methodLog.isLogElapsed()) { logLine.append(" elapsed nanoseconds:" + elapsed); } AspectLogUtils.getLogger().info(logLine.toString()); } return result; } }
c:创建一个日志的工具类,用来实现具体的日志记录。
public final class AspectLogUtils { private static Logger logger = LoggerFactory.getLogger(AspectLogUtils.class); private AspectLogUtils() { } public static Logger getLogger() { return logger; } public static void logParamValues(StringBuilder logLine, String[] paramNames, Object[] paramValues) { for (int i = 0; i < paramValues.length; i++) { logLine.append(paramNames[i]).append("=").append(toString(paramValues[i])); if (i < paramValues.length - 1) { logLine.append(", "); } } } public static String toString(Object object) { return JsonUtils.toJsonString(object); } }
<bean class="ServicesLoggerInterceptor"></bean> <aop:aspectj-autoproxy proxy-target-class="true"/>
INFO getDataDictionaryByType(dataDictionaryParamInfo={"type":1,"code":0}) - started elapsed nanoseconds:11491670
http://www.cnblogs.com/ASPNET2008/p/5813518.html
标签:
原文地址:http://www.cnblogs.com/softidea/p/5813788.html