APM - 零侵入监控Http服务

本文涉及的产品
应用实时监控服务ARMS - 应用监控,每月50GB免费额度
简介: APM - 零侵入监控Http服务

20201008114455965.png


Pre

APM - 零侵入监控Service服务


HTTP采集入口

  1. DispacherServlet .doServer() ?
  1. @Control ?
  2. javax.servlet.http.HttpServlet ?

很显然第三种更具有通用性,不管是DispacherServlet 还是@Control 都会是基于HttpServlet#service

20201008121038867.png


Code

package com.artisan.collects;
import com.artisan.ApmContext;
import com.artisan.intf.ICollect;
import com.artisan.model.HttpStatistics;
import javassist.*;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.Map;
/**
 * Http采集器
 */
public class HttpCollect extends AbstractByteTransformCollect implements ICollect {
    // 采集目标
    // 1.DispatchServlet
    // 2.@control 下的方法
    // 3.采集 javax.servlet.service()  ---- 采用这种通用的方式
    private static final String TARGET_CLASS = "javax.servlet.http.HttpServlet";
    private static final String TARGET_METHOD = "service";
    private static ApmContext context;
    public HttpCollect(ApmContext context, Instrumentation instrumentation) {
        super(instrumentation);
        this.context = context;
    }
    public byte[] buildClass(ClassLoader loader) throws Exception {
        ClassPool pool = new ClassPool();
        pool.insertClassPath(new LoaderClassPath(loader));
        CtClass ctClass = pool.get(TARGET_CLASS);
        CtMethod oldMethod = ctClass.getDeclaredMethod(TARGET_METHOD);
        CtMethod newMethod = CtNewMethod.copy(oldMethod, ctClass, null);
        oldMethod.setName(oldMethod.getName() + "$agent");
        //HttpServlet.service()'
        String beginSrc = "Object stat=com.artisan.collects.HttpCollect.begin($args);";
        String errorSrc = "com.artisan.collects.HttpCollect.error(e,stat);";
        String endSrc = "com.artisan.collects.HttpCollect.end(stat);";
        newMethod.setBody(String.format(voidSource, beginSrc, TARGET_METHOD, errorSrc, endSrc));
        ctClass.addMethod(newMethod);
        return ctClass.toBytecode();
    }
    // url,client IP
    public static HttpStatistics begin(Object args[]) {
        HttpStatistics httpStatistics = new HttpStatistics();
        httpStatistics.setBeginTime(System.currentTimeMillis());
        // 采用适配器的方式 ,避免在tomcat下  agent【appLauncher装载】无法获取到HttpServletRequest【common加载】(classLoader机制)
        HttpServletRequestAdapter adapter = new HttpServletRequestAdapter(args[0]);
        httpStatistics.setUrl(adapter.getRequestURI());
        httpStatistics.setClientIp(adapter.getClientIp());
        return httpStatistics;
    }
    public static void end(Object obj) {
        HttpStatistics stat = (HttpStatistics) obj;
        ((HttpStatistics) obj).setUseTime(System.currentTimeMillis() - stat.getBeginTime());
        context.submitCollectResult(stat);
    }
    public static void error(Throwable error, Object obj) {
        HttpStatistics stat = (HttpStatistics) obj;
        stat.setError(error.getMessage());
        System.out.println(stat);
    }
    final static String voidSource = "{\n"
            + "%s"
            + "        try {\n"
            + "            %s$agent($$);\n"
            + "        } catch (Throwable e) {\n"
            + "%s"
            + "            throw e;\n"
            + "        }finally{\n"
            + "%s"
            + "        }\n"
            + "}\n";
    @Override
    public byte[] transform(ClassLoader loader, String className) throws Exception {
        if (!TARGET_CLASS.equals(className)) {
            return null;
        }
        try {
            return buildClass(loader);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    private static class HttpServletRequestAdapter {
        private final Object target;
        private final Method _getRequestURI;
        private final Method _getRequestURL;
        private final Method _getParameterMap;
        private final Method _getMethod;
        private final Method _getHeader;
        private final Method _getRemoteAddr;
        private final static String targetClassName = "javax.servlet.http.HttpServletRequest";
        public HttpServletRequestAdapter(Object target) {
            this.target = target;
            try {
                Class<?> targetClass = target.getClass().getClassLoader().loadClass(targetClassName);
                _getRequestURI = targetClass.getMethod("getRequestURI");
                _getParameterMap = targetClass.getMethod("getParameterMap");
                _getMethod = targetClass.getMethod("getMethod");
                _getHeader = targetClass.getMethod("getHeader", String.class);
                _getRemoteAddr = targetClass.getMethod("getRemoteAddr");
                _getRequestURL = targetClass.getMethod("getRequestURL");
            } catch (NoSuchMethodException e) {
                throw new IllegalArgumentException("error :" + e.getMessage() + ". probable cause the target is not belong javax.servlet.http.HttpServletRequest ");
            } catch (ClassNotFoundException e) {
                throw new IllegalArgumentException("error :" + e.getMessage() + ". probable cause the target is not belong javax.servlet.http.HttpServletRequest ");
            }
        }
        public String getRequestURI() {
            try {
                return (String) _getRequestURI.invoke(target);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public String getRequestURL() {
            try {
                return _getRequestURL.invoke(target).toString();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public Map<String, String[]> getParameterMap() {
            try {
                return (Map<String, String[]>) _getParameterMap.invoke(target);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public String getMethod() {
            try {
                return (String) _getMethod.invoke(target);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public String getHeader(String name) {
            try {
                return (String) _getHeader.invoke(target, name);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public String getRemoteAddr() {
            try {
                return (String) _getRemoteAddr.invoke(target);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        public String getClientIp() {
            String ip = getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = getRemoteAddr();
            }
            return ip;
        }
    }
}


相关实践学习
通过云拨测对指定服务器进行Ping/DNS监测
本实验将通过云拨测对指定服务器进行Ping/DNS监测,评估网站服务质量和用户体验。
相关文章
|
2月前
|
运维 监控 数据可视化
ARMS的微服务监控
【8月更文挑战第23天】
44 6
|
24天前
|
Java Maven Windows
使用Java创建集成JACOB的HTTP服务
本文介绍了如何在Java中创建一个集成JACOB的HTTP服务,使Java应用能够调用Windows的COM组件。文章详细讲解了环境配置、动态加载JACOB DLL、创建HTTP服务器、实现IP白名单及处理HTTP请求的具体步骤,帮助读者实现Java应用与Windows系统的交互。作者拥有23年编程经验,文章来源于稀土掘金。著作权归作者所有,商业转载需授权。
使用Java创建集成JACOB的HTTP服务
|
2月前
|
监控 前端开发 JavaScript
ARMS的Web应用监控
【8月更文挑战第23天】
46 8
|
2月前
|
监控 JavaScript 前端开发
ARMS的移动应用监控
【8月更文挑战第23天】
41 6
|
2月前
|
Prometheus 监控 前端开发
ARMS设置监控规则
【8月更文挑战第24天】
56 9
|
2月前
|
监控 前端开发 JavaScript
ARMS集成监控代码
【8月更文挑战第24天】
39 6
|
2月前
|
数据采集 运维 监控
ARMS自定义监控
【8月更文挑战第25天】
46 3
|
2月前
|
SQL 运维 监控
ARMS全链路监控
【8月更文挑战第22天】
47 3
|
2月前
|
机器学习/深度学习 Ubuntu Linux
在Linux中,如何按照该要求抓包:只过滤出访问http服务的,目标ip为192.168.0.111,一共抓1000个包,并且保存到1.cap文件中?
在Linux中,如何按照该要求抓包:只过滤出访问http服务的,目标ip为192.168.0.111,一共抓1000个包,并且保存到1.cap文件中?
|
3月前
|
运维 Serverless API
Serverless 应用引擎使用问题之如何开发HTTP服务
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
下一篇
无影云桌面