文章目录
PreHTTP采集入口Code
Pre
APM - 零侵入监控Service服务
HTTP采集入口
DispacherServlet .doServer() ?@Control ?javax.servlet.http.HttpServlet ?
很显然第三种更具有通用性,不管是DispacherServlet 还是@Control 都会是基于HttpServlet#service
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
;
public class HttpCollect extends AbstractByteTransformCollect implements ICollect {
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");
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();
}
public static HttpStatistics
begin(Object args
[]) {
HttpStatistics httpStatistics
= new HttpStatistics();
httpStatistics
.setBeginTime(System
.currentTimeMillis());
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
;
}
}
}