方法調用日誌記錄攔截器的一個實現

概述

工做中常常調用外部接口, 須要進行詳細日誌記錄, 防止扯皮. 在調用失敗之後, 要及時通知警告. 下面是攔截器的實現, 使用方式參考: http://www.javashuo.com/article/p-wqblcmcg-r.htmlhtml

攔截器實現

/**
 * 攔截有註解的方法. 方法調用前, 會 info 級別打印全部入參; 調用之後, 會打印返回結果. <br/>
 * 若是產生異常, 會 error 級別打印異常信息, 同時發送報警郵件, 異常不會被攔截, 會正常拋出. <br/>
 * 報警郵件送達規則符合 {@link EmailWarnUtil} 定義規則.
 * 
 * @see
 *      https://my.oschina.net/u/1169457/blog/1489113
 *      http://todayleave.blogspot.jp/2016/02/spring-methodinterceptor.html
 *      http://blog.javaforge.net/post/76125490725/spring-aop-method-interceptor-annotation
 *
 */
@Slf4j
@Component
public class LogAndWarnInterceptor implements MethodInterceptor {

  @Autowired
  private JsonUtil jsonUtil;

  @Autowired
  private EmailWarnUtil emailWarnUtil;

  private ConcurrentHashMap<Method, List<String>> methodParameterNamesCache = new ConcurrentHashMap<>();

  @Override
  public Object invoke(MethodInvocation invocation) throws Throwable {
    Method method = invocation.getMethod();
    Object[] args = invocation.getArguments();
    List<String> paramNames = getMethodParamNames(method);
    String className = invocation.getThis().getClass().getSimpleName();
    String classMethodName = className + "." + method.getName();
    long timestamp = System.currentTimeMillis();


    log.info("before invoke method:{}, parameter names:{}, args:{}, timestamp:{}", classMethodName, paramNames,
        jsonUtil.toJsonString(args), timestamp);
    try {
      Object retVal = invocation.proceed();
      log.info("after invoke method:{}, result:{}, invoke timestamp:{}, call duration:{}", classMethodName,
          jsonUtil.toJsonString(retVal), timestamp, System.currentTimeMillis() - timestamp);
      return retVal;
    } catch (Exception exception) {
      String errMessage = "exception!!! invoke method:" + classMethodName + ",  parameter names:" + paramNames
          + ", args:" + jsonUtil.toJsonString(args) + ", invoke timestamp:" + timestamp;
      log.error(errMessage, exception);
      emailWarnUtil.muteWarn(NotifyEmailGroup.ERROR_WARN, errMessage, exception);
      throw exception;
      // throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR, "服務器調用後端服務錯誤, 請稍後重試.");
    }
  }

  /**
   * @see https://stackoverflow.com/questions/2237803/can-i-obtain-method-parameter-name-using-java-reflection
   *      <b>Bozho's answer</b>
   * 
   * @param method
   * @return
   */
  private List<String> getMethodParamNames(Method method) {
    List<String> paramNames = methodParameterNamesCache.get(method);
    if (paramNames != null) {
      return paramNames;
    }
    Parameter[] parameters = method.getParameters();
    paramNames = new ArrayList<>();
    for (Parameter parameter : parameters) {
      paramNames.add(parameter.getName());
    }
    methodParameterNamesCache.put(method, paramNames);
    return paramNames;
  }

}

pom 配置

在用反射獲取方法簽名(方法入參名字)時, 須要在pom文件添加 -parameters 參數, 並且jdk8以上版本. 要否則獲取的參數名字將會是: arg0, rags1 這樣. 更改配置之後, 須要 mvn clean package 一下生效.java

<properties>
    <!-- PLUGIN VERSIONS -->
    <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>

    <!-- OTHER PROPERTIES -->
    <java.version>1.8</java.version>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>${maven-compiler-plugin.version}</version>
            <configuration>
                <compilerArgument>-parameters</compilerArgument>
                <testCompilerArgument>-parameters</testCompilerArgument>
                <source>${java.version}</source>
                <target>${java.version}</target>
            </configuration>
        </plugin>
    </plugins>
</build>

結果示例

2017-07-26 18:33:38 [XNIO-1 task-1] INFO  c.y.o.c.global.LogAndWarnInterceptor - before invoke method:SmsService.send, parameter names:[mobile, templeId, params], args:["12222222222","string",{}], timestamp:1501065218633
2017-07-26 18:33:38 [XNIO-1 task-1] INFO  c.y.o.c.global.LogAndWarnInterceptor - after invoke method:SmsService.send, result:, invoke timestamp:1501065218633, call duration:43

參考

http://www.javashuo.com/article/p-wqblcmcg-r.html
https://stackoverflow.com/questions/2237803/can-i-obtain-method-parameter-name-using-java-reflectionspring

相關文章
相關標籤/搜索