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);
        }
    }
}
TomcatInvokeInterceptor

 

posted @ 2022-03-12 22:16  骑着蜗牛去救你  阅读(368)  评论(0编辑  收藏  举报