• 调用链监控 CAT 之 URL埋点实践


    URL监控埋点作用

    • 一个http请求来了之后,会自动打点,能够记录每个url的访问情况,并将以此请求后续的调用链路串起来,可以在cat上查看logview
    • 可以在cat Transaction及Event 页面上都看到URL和URL.Forward(如果有Forward请求的话)两类数据;Transaction数据中URL点进去的数据就是被访问的具体URL(去掉参数的前缀部分)
    • 请将catFilter存放filter的第一个,这样可以保证最大可能性监控所有的请求

    实践

    工程说明

    工程名 端口 作用
    cat-ui 8082 调用入口服务
    cat-business-consumer 8083 业务消费服务
    cat-order-service 8084 订单服务
    cat-storage-service 8085 库存服务

    上图是本节实例的埋点图,首先 cat-ui 的入口 和 调用点 加入cat埋点,cat-business-consumer的入口和调用点加入埋点,cat-order-service 和 cat-storage-service 不再调用其他微服务,所以只在入口加入埋点。通过这样的埋点,可以组成一条完整的调用链。

    关键代码

    调用链上下文通用类

    CatContextImpl.java
    /**
     * Cat.context接口实现类,用于context调用链传递,相关方法Cat.logRemoteCall()和Cat.logRemoteServer()
     */
    public class CatContextImpl implements Cat.Context {
    
        private Map<String, String> properties = new HashMap<>(16);
    
        @Override
        public void addProperty(String key, String value) {
            properties.put(key, value);
        }
    
        @Override
        public String getProperty(String key) {
            return properties.get(key);
        }
    }
    
    CatHttpConstants
    /**
     * 添加header常量,用于http协议传输rootId、parentId、childId三个context属性
     */
    public class CatHttpConstants {
    
        /**
         * http header 常量
         */
        public static final String CAT_HTTP_HEADER_ROOT_MESSAGE_ID = "X-CAT-ROOT-MESSAGE-ID";
        public static final String CAT_HTTP_HEADER_PARENT_MESSAGE_ID = "X-CAT-ROOT-PARENT-ID";
        public static final String CAT_HTTP_HEADER_CHILD_MESSAGE_ID = "X-CAT-ROOT-CHILD-ID";
    
    }
    
    CatServletFilter
    /**
     * http协议传输,远程调用链目标端接收context的filter,
     * 通过header接收rootId、parentId、childId并放入CatContextImpl中,调用Cat.logRemoteCallServer()进行调用链关联
     * 注:若不涉及调用链,则直接使用cat-client.jar中提供的filter即可
     * 使用方法(视项目框架而定):
     *      1、web项目:在web.xml中引用此filter
     *      2、Springboot项目,通过注入bean的方式注入此filter
     */
    public class CatServletFilter implements Filter {
    
    
        private String[] urlPatterns = new String[0];
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            String patterns = filterConfig.getInitParameter("CatHttpModuleUrlPatterns");
            if (patterns != null) {
                patterns = patterns.trim();
                urlPatterns = patterns.split(",");
                for (int i = 0; i < urlPatterns.length; i++) {
                    urlPatterns[i] = urlPatterns[i].trim();
                }
            }
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
    
            String url = request.getRequestURL().toString();
            for (String urlPattern : urlPatterns) {
                if (url.startsWith(urlPattern)) {
                    url = urlPattern;
                }
            }
    
            CatContextImpl catContext = new CatContextImpl();
            catContext.addProperty( Cat.Context.ROOT, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID));
            catContext.addProperty(Cat.Context.PARENT, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID));
            catContext.addProperty(Cat.Context.CHILD, request.getHeader(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID));
            Cat.logRemoteCallServer(catContext);
    
            Transaction t = Cat.newTransaction( CatConstants.TYPE_URL, url);
    
            try {
    
                Cat.logEvent("Service.method", request.getMethod(), Message.SUCCESS, request.getRequestURL().toString());
                Cat.logEvent("Service.client", request.getRemoteHost());
    
                filterChain.doFilter(servletRequest, servletResponse);
    
                t.setStatus(Transaction.SUCCESS);
            } catch (Exception ex) {
                t.setStatus(ex);
                Cat.logError(ex);
                throw ex;
            } finally {
                t.complete();
            }
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    本节实例中每个工程都会用到调用链上下文通用类。

    cat-ui 工程

    CatRestInterceptor
    @Component
    public class CatRestInterceptor implements ClientHttpRequestInterceptor {
    
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            Transaction t = Cat.newTransaction(CatConstants.TYPE_REMOTE_CALL, request.getURI().toString());
    
            try {
                HttpHeaders headers = request.getHeaders();
    
                // 保存和传递CAT调用链上下文
                Cat.Context ctx = new CatContextImpl();
                Cat.logRemoteCallClient(ctx);
                headers.add(CatHttpConstants.CAT_HTTP_HEADER_ROOT_MESSAGE_ID, ctx.getProperty(Cat.Context.ROOT));
                headers.add(CatHttpConstants.CAT_HTTP_HEADER_PARENT_MESSAGE_ID, ctx.getProperty(Cat.Context.PARENT));
                headers.add(CatHttpConstants.CAT_HTTP_HEADER_CHILD_MESSAGE_ID, ctx.getProperty(Cat.Context.CHILD));
    
                // 保证请求继续被执行
                ClientHttpResponse response =  execution.execute(request, body);
                t.setStatus(Transaction.SUCCESS);
                return response;
            } catch (Exception e) {
                Cat.getProducer().logError(e);
                t.setStatus(e);
                throw e;
            } finally {
                t.complete();
            }
    
        }
    }
    

    CatServletFilter 对 cat-ui 的入口进行了埋点,CatRestInterceptor 实现 ClientHttpRequestInterceptor接口 可以对 RestTemplate 发起的请求进行拦截,利用这一点对调用点埋点,同时在 Http Header 中存入 调用链的上下文,将调用链传递下去。

    cat-business-consumer、cat-order-service、cat-storage-service 中的埋点与 cat-ui 埋点的方式相同。

    测试

    发起请求

    curl http://127.0.0.1:8082/start
    

    cat 监控界面可以看到本节实例的服务。

    点开 “logView” 可以看到完整的调用链信息。

    点击 “Graph” 查看图表形式的调用链信息。

    源码

    https://github.com/gf-huanchupk/SpringCloudLearning/tree/master/chapter15

    参考

    https://github.com/dianping/cat/wiki



    欢迎扫码或微信搜索公众号《程序员果果》关注我,关注有惊喜~

  • 相关阅读:
    sql语句常考知识点总结
    服务器搭建
    软件测试面试题
    linux常用命令
    kibana常用查询删除语法
    python从kafka消费数据
    foxmail客户端,写邮件窗口弹不出来
    JMeter学习——测试文件下载
    python中取两个列表中不同的元素
    MySQL主从复制
  • 原文地址:https://www.cnblogs.com/huanchupkblog/p/10714768.html
Copyright © 2020-2023  润新知