skywalking的agent如何创建span(一)
这里以tomcat插件为例
可以看到在tomcat插件TomcatInstrumentation中定义的Enhance class(被增强的目标类),以及拦截器的路径
/** * Enhance class. */ private static final String ENHANCE_CLASS = "org.apache.catalina.core.StandardHostValve";
/**
* The intercept class for "invoke" method in the class "org.apache.catalina.core.StandardHostValve"
*/
private static final String INVOKE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat78x.TomcatInvokeInterceptor";
可以在getInstanceMethodsInterceptPoints()方法中看到指定了需要被拦截的方法为invoke,同时可以看到指定了具体的拦截器INVOKE_INTERCEPT_CLASS
@Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { return new InstanceMethodsInterceptPoint[] { new InstanceMethodsInterceptPoint() { @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { return named("invoke"); } @Override public String getMethodsInterceptor() { return INVOKE_INTERCEPT_CLASS; } @Override public boolean isOverrideArgs() { return false; } }, new InstanceMethodsInterceptPoint() { @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { return named("throwable"); } @Override public String getMethodsInterceptor() { return EXCEPTION_INTERCEPT_CLASS; } @Override public boolean isOverrideArgs() { return false; } } }; }
在拦截器TomcatInvokeInterceptor中定义了 beforeMethod、afterMethod以及handleMethodException几个主要方法。beforeMethod的作用为在invoke执行前做的增强,同理afterMethod为在invoke方法执行之后做的增强,handleMethodException为当invoke方法发生异常时做的增强。
public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor { private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST; private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse"; private static final String GET_STATUS_METHOD = "getStatus"; static { IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist( TomcatInvokeInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD); } @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { Request request = (Request) allArguments[0]; ContextCarrier contextCarrier = new ContextCarrier(); CarrierItem next = contextCarrier.items(); while (next.hasNext()) { next = next.next(); next.setHeadValue(request.getHeader(next.getHeadKey())); } AbstractSpan span = ContextManager.createEntrySpan(request.getRequestURI(), contextCarrier); String url = request.getRequestURL().toString(); Tags.URL.set(span, url); Tags.HTTP.METHOD.set(span, request.getMethod()); //设置组件类型 span.setComponent(ComponentsDefine.TOMCAT); //当前span所处的位置 SpanLayer.asHttp(span); //设置扩展信息 if (span instanceof AbstractTracingSpan) { AbstractTracingSpan ats = (AbstractTracingSpan) span; //Http服务端口,大部分情况下是80 Pair hpPair = new Pair("http_port", MyUtil.getPortByURL(url)); ats.addPair(hpPair); //关联服务实例 String insName = ServiceManagementClient.getInsName(); Pair inPair = new Pair("ins_name", insName); ats.addPair(inPair); //设置方法名称 if (method != null && method.getName() != null) { Pair snPair = new Pair("span_name", method.getName()); ats.addPair(snPair); } //设置客户端IP String clientIP = request.getRemoteAddr(); if (!MyUtil.empty(clientIP)) { Pair ciPair = new Pair("client_ip", clientIP); ats.addPair(ciPair); } //设置客户端类型 String userAgentInfo = request.getHeader("User-Agent"); if (!MyUtil.empty(userAgentInfo)) { String clientType = MyUtil.getBrowserInfo(userAgentInfo); if (!MyUtil.empty(clientType)) { Pair ctPair = new Pair("client_type", clientType); ats.addPair(ctPair); } } //设置request_url //@author itw_huangkun01 if (!MyUtil.empty(url)) { Pair ciPair = new Pair("url", url); ats.addPair(ciPair); } //设置请求类型:GET\POST…… //@author itw_huangkun01 if (!MyUtil.empty(request.getMethod())) { Pair ciPair = new Pair("http_method", request.getMethod()); ats.addPair(ciPair); } //设置请求头预留字段 //@author itw_huangkun01 Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames != null) { Pair ciPair = new Pair("http_headers", headerNames.toString()); ats.addPair(ciPair); } } if (TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS) { collectHttpParam(request, span); } } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { Request request = (Request) allArguments[0]; HttpServletResponse response = (HttpServletResponse) allArguments[1]; AbstractSpan span = ContextManager.activeSpan(); //设置所处的类信息 Tags.LOCATION.set(span, objInst.getClass().getName()); /**设置扩展信息; * @author itw_huangkun01 * */ if (span instanceof AbstractTracingSpan) { AbstractTracingSpan ats = (AbstractTracingSpan) span; //设置返回状态码; if (IS_SERVLET_GET_STATUS_METHOD_EXIST && response.getStatus() != 0) { Pair ciPair = new Pair("http_code", String.valueOf(response.getStatus())); ats.addPair(ciPair); } } if (IS_SERVLET_GET_STATUS_METHOD_EXIST && response.getStatus() >= 400) { span.errorOccurred(); Tags.STATUS_CODE.set(span, Integer.toString(response.getStatus())); } // Active HTTP parameter collection automatically in the profiling context. if (!TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS && span.isProfiling()) { collectHttpParam(request, span); } ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG); ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) { AbstractSpan span = ContextManager.activeSpan(); span.log(t); } private void collectHttpParam(Request request, AbstractSpan span) { final Map<String, String[]> parameterMap = new HashMap<>(); final org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest(); final Parameters parameters = coyoteRequest.getParameters(); for (final Enumeration<String> names = parameters.getParameterNames(); names.hasMoreElements(); ) { final String name = names.nextElement(); parameterMap.put(name, parameters.getParameterValues(name)); } if (!parameterMap.isEmpty()) { String tagValue = CollectionUtil.toString(parameterMap); tagValue = TomcatPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ? StringUtil.cut(tagValue, TomcatPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue; Tags.HTTP.PARAMS.set(span, tagValue); } } }