public abstract class AbstractClassEnhancePluginDefine {
  private static ILog logger = LogManager.getLogger(AbstractClassEnhancePluginDefine.class);

  public DynamicType.Builder<?> define(String transformClassName, DynamicType.Builder<?> builder)
      throws PluginException {
    String interceptorDefineClassName = this.getClass().getName();

    if (StringUtil.isEmpty(transformClassName)) {
      logger.warn(
          "classname of being intercepted is not defined by {}.", interceptorDefineClassName);
      return builder;
    }

    logger.debug(
        "prepare to enhance class {} by {}.", transformClassName, interceptorDefineClassName);

    /** find witness classes for enhance class */
    String[] witnessClasses = witnessClasses();
    if (witnessClasses != null) {
      for (String witnessClass : witnessClasses) {
        Resolution witnessClassResolution = PluginBootstrap.CLASS_TYPE_POOL.describe(witnessClass);
        if (!witnessClassResolution.isResolved()) {
          logger.warn(
              "enhance class {} by plugin {} is not working. Because witness class {} is not existed.",
              transformClassName,
              interceptorDefineClassName,
              witnessClass);
          return builder;
        }
      }
    }

    /** find origin class source code for interceptor */
    DynamicType.Builder<?> newClassBuilder = this.enhance(transformClassName, builder);

    logger.debug(
        "enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);

    return newClassBuilder;
  }

  protected abstract DynamicType.Builder<?> enhance(
      String enhanceOriginClassName, DynamicType.Builder<?> newClassBuilder) throws PluginException;

  /**
   * 返回要被增强的类,应当返回类全名或前匹配(返回*号结尾)
   *
   * @return
   */
  protected abstract String enhanceClassName();

  /**
   * 返回一个类名的列表 如果列表中的类在JVM中存在,则enhance可以会尝试生效
   *
   * @return
   */
  protected String[] witnessClasses() {
    return new String[] {};
  }
}
public class RPCClientInvokeMonitor extends BaseInvokeMonitor {

  private static ILog logger = LogManager.getLogger(RPCClientInvokeMonitor.class);

  public ContextData beforeInvoke(Identification id) {
    try {
      Span spanData = ContextGenerator.generateSpanFromThreadLocal(id);
      // 设置SpanType的类型
      spanData.setTag(Tag.SPAN_TYPE, SpanType.RPC_CLIENT);

      if (Config.BuriedPoint.PRINTF) {
        logger.debug(
            "TraceId:"
                + spanData.getTraceId()
                + "\tParentLevelId:"
                + spanData.getParentLevel()
                + "\tLevelId:"
                + spanData.getLevelId()
                + "\tbusinessKey:"
                + spanData.getBusinessKey());
      }

      CurrentThreadSpanStack.push(spanData);

      sendRequestSpan(spanData, id);

      return new ContextData(
          spanData.getTraceId(), generateSubParentLevelId(spanData), spanData.getRouteKey());
    } catch (Throwable t) {
      logger.error(t.getMessage(), t);
      return new EmptyContextData();
    }
  }

  public void afterInvoke() {
    super.afterInvoke();
  }

  public void occurException(Throwable th) {
    super.occurException(th);
  }

  private String generateSubParentLevelId(Span spanData) {
    if (spanData.getParentLevel() == null || spanData.getParentLevel().length() == 0) {
      return spanData.getLevelId() + "";
    }

    return spanData.getParentLevel() + "." + spanData.getLevelId();
  }
}
/** Created by xin on 2016/12/8. */
public class AlarmMessageSender {

  private ILog logger = LogManager.getLogger(AlarmMessageSender.class);

  public void send(String alarmKey, String traceId, String message) {
    Jedis jedis = null;
    try {
      jedis = AlarmRedisConnector.getJedis();
      if (jedis != null) return;
      jedis.hsetnx(alarmKey, traceId, message);
      jedis.expire(alarmKey, Config.Alarm.ALARM_EXPIRE_SECONDS);
    } catch (Exception e) {
      AlarmRedisConnector.reportJedisFailure();
      logger.error("Failed to set data.", e);
    } finally {
      if (jedis != null) {
        jedis.close();
      }
    }
  }
}
public abstract class BaseInvokeMonitor {

  private static ILog easyLogger = LogManager.getLogger(BaseInvokeMonitor.class);

  private static String EXCEPTION_SPLIT = ",";

  private static Set<String> exclusiveExceptionSet = null;

  protected ContextData beforeInvoke(Span spanData, Identification id) {
    if (Config.BuriedPoint.PRINTF) {
      easyLogger.debug(
          "TraceId:"
              + spanData.getTraceId()
              + "\tParentLevelId:"
              + spanData.getParentLevel()
              + "\tLevelId:"
              + spanData.getLevelId()
              + "\tbusinessKey:"
              + spanData.getBusinessKey());
    }

    // 将新创建的Context存放到ThreadLocal栈中。
    CurrentThreadSpanStack.push(spanData);

    // 根据SpanData生成RequestSpan,并保存

    CurrentThreadSpanStack.push(spanData);

    sendRequestSpan(spanData, id);

    // 并将当前的Context返回回去
    return new ContextData(spanData);
  }

  protected void sendRequestSpan(Span span, Identification id) {
    RequestSpan.Builder requestSpanBuilder = span.buildRequestSpan(RequestSpan.newBuilder());
    if (id.getBusinessKey() != null && id.getBusinessKey().length() > 0) {
      requestSpanBuilder = requestSpanBuilder.setBusinessKey(id.getBusinessKey());
    }
    RequestSpan requestSpan =
        requestSpanBuilder
            .setViewPointId(id.getViewPoint())
            .setSpanTypeDesc(id.getSpanTypeDesc())
            .setCallType(id.getCallType())
            .setProcessNo(BuriedPointMachineUtil.getProcessNo())
            .setAddress(BuriedPointMachineUtil.getHostDesc())
            .build();

    RequestSpanDisruptor.INSTANCE.ready2Send(requestSpan);
  }

  protected void sendAckSpan(Span span) {
    AckSpan ackSpan = span.buildAckSpan(AckSpan.newBuilder()).build();

    AckSpanDisruptor.INSTANCE.ready2Send(ackSpan);
  }

  protected void afterInvoke() {
    try {

      // 弹出上下文的栈顶中的元素
      Span spanData = CurrentThreadSpanStack.pop();

      if (Config.BuriedPoint.PRINTF) {
        easyLogger.debug(
            "TraceId-ACK:"
                + spanData.getTraceId()
                + "\tParentLevelId:"
                + spanData.getParentLevel()
                + "\tLevelId:"
                + spanData.getLevelId()
                + "\tbusinessKey:"
                + spanData.getBusinessKey());
      }

      sendAckSpan(spanData);
    } catch (Throwable t) {
      easyLogger.error(t.getMessage(), t);
    }
  }

  protected void occurException(Throwable th) {
    try {
      if (exclusiveExceptionSet == null) {
        Set<String> exclusiveExceptions = new HashSet<String>();

        String[] exceptions = Config.BuriedPoint.EXCLUSIVE_EXCEPTIONS.split(EXCEPTION_SPLIT);
        for (String exception : exceptions) {
          exclusiveExceptions.add(exception);
        }
        exclusiveExceptionSet = exclusiveExceptions;
      }

      Span span = CurrentThreadSpanStack.peek();
      span.handleException(
          th, exclusiveExceptionSet, Config.BuriedPoint.MAX_EXCEPTION_STACK_LENGTH);
    } catch (Throwable t) {
      easyLogger.error(t.getMessage(), t);
    }
  }
}