提交 d0bb8725 编写于 作者: wu-sheng's avatar wu-sheng

Add sniffer core classes’s comments. #78

上级 a1f4e82f
......@@ -24,6 +24,12 @@ import java.net.URL;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.not;
/**
* The main entrance of sky-waking agent.
* It bases on javaagent mechanism.
*
* @author wusheng
*/
public class SkyWalkingAgent {
static {
LogManager.setLogResolver(new EasyLogResolver());
......@@ -31,6 +37,14 @@ public class SkyWalkingAgent {
private static ILog logger;
/**
* Main entrance.
* Use byte-buddy transform to enhance all classes, which define in plugins.
*
* @param agentArgs
* @param instrumentation
* @throws PluginException
*/
public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
logger = LogManager.getLogger(SkyWalkingAgent.class);
......@@ -64,7 +78,13 @@ public class SkyWalkingAgent {
}).installOn(instrumentation);
}
/**
* Get the enhance target classes matcher.
*
* @param pluginDefineCategory
* @param <T>
* @return class matcher.
*/
private static <T extends NamedElement> ElementMatcher.Junction<T> enhanceClassMatcher(PluginDefineCategory pluginDefineCategory) {
return new SkyWalkingEnhanceMatcher<T>(pluginDefineCategory);
}
......@@ -81,6 +101,12 @@ public class SkyWalkingAgent {
ConfigInitializer.initialize();
}
/**
* Try to allocate the skywalking-agent.jar
* Some config files or output resources are from this path.
*
* @return the path, where the skywalking-agent.jar is.
*/
private static String initAgentBasePath() {
try {
String urlString = SkyWalkingAgent.class.getClassLoader().getSystemClassLoader().getResource(generateLocationPath()).toString();
......
......@@ -4,6 +4,9 @@ import com.a.eye.skywalking.plugin.PluginDefineCategory;
import net.bytebuddy.description.NamedElement;
/**
* The matcher bases on byte-buddy {@link AbstractJunction} class.
* Judge the target class in transforming, should be enhanced or not.
* <p>
* Created by wusheng on 16/7/31.
*/
public class SkyWalkingEnhanceMatcher<T extends NamedElement> extends AbstractJunction<T> {
......
......@@ -6,6 +6,14 @@ import com.a.eye.skywalking.model.Span;
import java.util.ArrayList;
import java.util.List;
/**
* Core in-process propagation context accessor.
* You can push, peek, pop {@link Span}s.
* In processing, every span be created and pushed into the context when begin
* This context based on stack structure. see the stack on {@link SpanNodeStack}
*
* @author wusheng
*/
public class CurrentThreadSpanStack {
private static ThreadLocal<SpanNodeStack> nodes = new ThreadLocal<SpanNodeStack>();
......@@ -36,8 +44,8 @@ public class CurrentThreadSpanStack {
static class SpanNodeStack {
/**
* 单JVM的单线程,埋点数量一般不会超过20.
* 超过20会影响性能,不推荐使用
* The depth of call stack should less than 20, in most cases.
* The depth is calculated by span, not class or the depth of java stack.
*/
private List<SpanNode> spans = new ArrayList<SpanNode>(20);
......
......@@ -10,15 +10,18 @@ import com.a.eye.skywalking.model.ContextData;
import com.a.eye.skywalking.model.Identification;
import com.a.eye.skywalking.model.Span;
import com.a.eye.skywalking.model.SpanTagBuilder;
import com.a.eye.skywalking.network.dependencies.com.google.protobuf.ByteString;
import com.a.eye.skywalking.network.grpc.AckSpan;
import com.a.eye.skywalking.network.grpc.RequestSpan;
import com.a.eye.skywalking.network.model.Tag;
import com.a.eye.skywalking.util.BuriedPointMachineUtil;
import java.util.HashSet;
import java.util.Set;
/**
* Basic invoke monitor.
*
* @author wusheng
*/
public abstract class BaseInvokeMonitor {
private static ILog easyLogger = LogManager.getLogger(BaseInvokeMonitor.class);
......@@ -27,10 +30,18 @@ public abstract class BaseInvokeMonitor {
private static Set<String> exclusiveExceptionSet = null;
/**
* Create the request span before invoke method.
*
* @param spanData {@link Span} represents the before invoke.
* @param id
* @return
*/
protected ContextData beforeInvoke(Span spanData, Identification id) {
if (Config.BuriedPoint.PRINTF) {
easyLogger.debug("TraceId:" + spanData.getTraceId() + "\tParentLevelId:" + spanData.getParentLevel()
+ "\tLevelId:" + spanData.getLevelId() + "\tbusinessKey:" + spanData.getBusinessKey());
easyLogger
.debug("TraceId:" + spanData.getTraceId() + "\tParentLevelId:" + spanData.getParentLevel() + "\tLevelId:" + spanData.getLevelId() + "\tbusinessKey:" + spanData
.getBusinessKey());
}
// 将新创建的Context存放到ThreadLocal栈中。
......@@ -42,24 +53,33 @@ public abstract class BaseInvokeMonitor {
return new ContextData(spanData);
}
/**
* Change the {@link Span} to {@link RequestSpan}, and prepare to send to routing server.
*
* @param span
* @param id
*/
protected void sendRequestSpan(Span span, Identification id) {
RequestSpan requestSpan= SpanTagBuilder.newBuilder(span)
.setBusinessKey(id.getBusinessKey())
.setSpanTypeDesc(id.getSpanTypeDesc()).setCallType(id.getCallType())
.setProcessNo(BuriedPointMachineUtil.getProcessNo())
.setAddress(BuriedPointMachineUtil.getHostDesc()).buildRequestSpan(RequestSpan.newBuilder());
RequestSpan requestSpan = SpanTagBuilder.newBuilder(span).setBusinessKey(id.getBusinessKey()).setSpanTypeDesc(id.getSpanTypeDesc()).setCallType(id.getCallType())
.setProcessNo(BuriedPointMachineUtil.getProcessNo()).setAddress(BuriedPointMachineUtil.getHostDesc()).buildRequestSpan(RequestSpan.newBuilder());
RequestSpanDisruptor.INSTANCE.ready2Send(requestSpan);
}
/**
* Change the {@link Span} to {@link AckSpan}, and prepare to send to routing server.
*
* @param span
*/
protected void sendAckSpan(Span span) {
AckSpan ackSpan = SpanTagBuilder.newBuilder(span)
.setStatusCode(span.getStatusCode())
.setExceptionStack(span.getExceptionStack()).buildAckSpan(AckSpan.newBuilder());
AckSpan ackSpan = SpanTagBuilder.newBuilder(span).setStatusCode(span.getStatusCode()).setExceptionStack(span.getExceptionStack()).buildAckSpan(AckSpan.newBuilder());
AckSpanDisruptor.INSTANCE.ready2Send(ackSpan);
}
/**
* Create the ack span before invoke method.
*/
protected void afterInvoke() {
try {
......@@ -67,8 +87,8 @@ public abstract class BaseInvokeMonitor {
Span spanData = CurrentThreadSpanStack.pop();
if (Config.BuriedPoint.PRINTF) {
easyLogger.debug("TraceId-ACK:" + spanData.getTraceId() + "\tParentLevelId:" + spanData.getParentLevel()
+ "\tLevelId:" + spanData.getLevelId() + "\tbusinessKey:" + spanData.getBusinessKey());
easyLogger.debug("TraceId-ACK:" + spanData.getTraceId() + "\tParentLevelId:" + spanData.getParentLevel() + "\tLevelId:" + spanData.getLevelId() + "\tbusinessKey:"
+ spanData.getBusinessKey());
}
sendAckSpan(spanData);
......@@ -77,6 +97,11 @@ public abstract class BaseInvokeMonitor {
}
}
/**
* Process when method invocation occurs exception.
*
* @param th
*/
protected void occurException(Throwable th) {
try {
if (exclusiveExceptionSet == null) {
......
......@@ -8,11 +8,22 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* Plugins finder.
* Use {@link PluginResourcesResolver} to find all plugins,
* and ask {@link PluginCfg} to load all plugin definitions.
*
* @author wusheng
*/
public class PluginBootstrap {
private static ILog logger = LogManager.getLogger(PluginBootstrap.class);
public static TypePool CLASS_TYPE_POOL = null;
/**
* load all plugins.
* @return plugin definition list.
*/
public List<AbstractClassEnhancePluginDefine> loadPlugins() {
CLASS_TYPE_POOL = TypePool.Default.ofClassPath();
......
......@@ -4,22 +4,25 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Just category the plugins.
* Change the store structure from {@link List} to {@link Map}
*/
public class PluginDefineCategory {
private static PluginDefineCategory pluginDefineCategory;
private final Map<String, AbstractClassEnhancePluginDefine> exactClassEnhancePluginDefineMapping =
new HashMap<String, AbstractClassEnhancePluginDefine>();
private final Map<String, AbstractClassEnhancePluginDefine> exactClassEnhancePluginDefineMapping = new HashMap<String, AbstractClassEnhancePluginDefine>();
private PluginDefineCategory(List<AbstractClassEnhancePluginDefine> plugins) {
for (AbstractClassEnhancePluginDefine plugin : plugins) {
String enhanceClassName = plugin.enhanceClassName();
if (enhanceClassName == null){
if (enhanceClassName == null) {
continue;
}
exactClassEnhancePluginDefineMapping.put(enhanceClassName, plugin);
exactClassEnhancePluginDefineMapping.put(enhanceClassName, plugin);
}
}
......
......@@ -9,45 +9,57 @@ import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
/**
* Use the current classloader to read all plugin define file.
* The file must be named 'skywalking-plugin.def'
*
* @author wusheng
*/
public class PluginResourcesResolver {
private static ILog logger = LogManager.getLogger(PluginResourcesResolver.class);
public List<URL> getResources(){
List<URL> cfgUrlPaths = new ArrayList<URL>();
Enumeration<URL> urls;
try {
urls = getDefaultClassLoader().getResources("skywalking-plugin.def");
if(!urls.hasMoreElements()){
logger.info("no plugin files (skywalking-plugin.properties) found");
}
while(urls.hasMoreElements()){
URL pluginUrl = urls.nextElement();
cfgUrlPaths.add(pluginUrl);
logger.info("find skywalking plugin define in {}", pluginUrl);
}
return cfgUrlPaths;
} catch (IOException e) {
logger.error("read resources failure.", e);
}
return null;
}
private ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = PluginResourcesResolver.class.getClassLoader();
}
return cl;
}
private static ILog logger = LogManager.getLogger(PluginResourcesResolver.class);
public List<URL> getResources() {
List<URL> cfgUrlPaths = new ArrayList<URL>();
Enumeration<URL> urls;
try {
urls = getDefaultClassLoader().getResources("skywalking-plugin.def");
if (!urls.hasMoreElements()) {
logger.info("no plugin files (skywalking-plugin.def) found");
}
while (urls.hasMoreElements()) {
URL pluginUrl = urls.nextElement();
cfgUrlPaths.add(pluginUrl);
logger.info("find skywalking plugin define in {}", pluginUrl);
}
return cfgUrlPaths;
} catch (IOException e) {
logger.error("read resources failure.", e);
}
return null;
}
/**
* Get the classloader.
* First get current thread's classloader,
* if fail, get {@link PluginResourcesResolver}'s classloader.
*
* @return the classloader to find plugin definitions.
*/
private ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = PluginResourcesResolver.class.getClassLoader();
}
return cl;
}
}
......@@ -23,6 +23,9 @@ public enum AllObjectDefaultMethodsMatch implements ElementMatcher<MethodDescrip
*/
private final ElementMatcher.Junction<MethodDescription> matcher;
/**
* Init the match, include {@link Object}'s methods.
*/
AllObjectDefaultMethodsMatch() {
ElementMatcher.Junction<MethodDescription>[] allDefaultMethods = new ElementMatcher.Junction[] {named("finalize").and(takesArguments(0)).and(ElementMatchers.<MethodDescription>isPublic()),
named("wait").and(takesArguments(0)).and(ElementMatchers.<MethodDescription>isPublic()),
......@@ -48,6 +51,10 @@ public enum AllObjectDefaultMethodsMatch implements ElementMatcher<MethodDescrip
matcher = newMatcher;
}
/**
* @param target method description.
* @return true, if the method inherit from {@link Object}'s methods.
*/
@Override
public boolean matches(MethodDescription target) {
return matcher.matches(target);
......
......@@ -4,14 +4,24 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
/**
* One of the three "Intercept Point".
* "Intercept Point" is a definition about where and how intercept happens.
* In this "Intercept Point", the definition targets class's constructors, and the interceptor.
* <p>
* ref to two others: {@link StaticMethodsInterceptPoint} and {@link InstanceMethodsInterceptPoint}
* <p>
* Created by wusheng on 2016/11/29.
*/
public interface ConstructorInterceptPoint{
public interface ConstructorInterceptPoint {
/**
* Constructor matcher
*
* @return matcher instance.
*/
ElementMatcher<MethodDescription> getConstructorMatcher();
/**
*
* @return represents a class name, the class instance must instanceof InstanceConstructorInterceptor.
* @return represents a class name, the class instance must be a instance of {@link com.a.eye.skywalking.plugin.interceptor.enhance.InstanceConstructorInterceptor}.
*/
String getConstructorInterceptor();
}
......@@ -4,13 +4,19 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
/**
* One of the three "Intercept Point".
* "Intercept Point" is a definition about where and how intercept happens.
* In this "Intercept Point", the definition targets class's instance methods, and the interceptor.
*
* ref to two others: {@link ConstructorInterceptPoint} and {@link StaticMethodsInterceptPoint}
*
* Created by wusheng on 2016/11/29.
*/
public interface InstanceMethodsInterceptPoint {
/**
* 返回需要被增强的方法列表
* class instance methods matcher.
*
* @return
* @return methods matcher
*/
ElementMatcher<MethodDescription> getMethodsMatcher();
......
......@@ -4,19 +4,24 @@ import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
/**
* One of the three "Intercept Point".
* "Intercept Point" is a definition about where and how intercept happens.
* In this "Intercept Point", the definition targets class's static methods, and the interceptor.
*
* ref to two others: {@link ConstructorInterceptPoint} and {@link InstanceMethodsInterceptPoint}
*
* Created by wusheng on 2016/11/29.
*/
public interface StaticMethodsInterceptPoint {
/**
* 返回需要被增强的方法列表
* static methods matcher.
*
* @return
* @return matcher instance.
*/
ElementMatcher<MethodDescription> getMethodsMatcher();
/**
*
* @return represents a class name, the class instance must instanceof StaticMethodsAroundInterceptor.
* @return represents a class name, the class instance must instanceof {@link com.a.eye.skywalking.plugin.interceptor.enhance.StaticMethodsAroundInterceptor}.
*/
String getMethodsInterceptor();
}
package com.a.eye.skywalking.plugin.interceptor.enhance;
/**
* Constructor context.
*
* @author wusheng
*/
public class ConstructorInvokeContext {
/**
* 代理对象实例
* object instance
*/
private Object objInst;
/**
* 构造函数参数
* constructor's arguments list.
*/
private Object[] allArguments;
......@@ -14,11 +19,17 @@ public class ConstructorInvokeContext {
this.objInst = objInst;
this.allArguments = allArguments;
}
/**
* @return object instance
*/
public Object inst(){
return objInst;
}
/**
* @return arguments list.
*/
public Object[] allArguments(){
return this.allArguments;
}
......
......@@ -3,8 +3,17 @@ package com.a.eye.skywalking.plugin.interceptor.enhance;
import com.a.eye.skywalking.plugin.interceptor.EnhancedClassInstanceContext;
/**
* The instance constructor's interceptor interface.
* Any plugin, which wants to intercept constructor, must implement this interface.
* <p>
* Created by wusheng on 2016/11/29.
*/
public interface InstanceConstructorInterceptor {
/**
* Called before the origin constructor invocation.
*
* @param context a new added instance field
* @param interceptorContext constructor invocation context.
*/
void onConstruct(EnhancedClassInstanceContext context, ConstructorInvokeContext interceptorContext);
}
......@@ -3,10 +3,10 @@ package com.a.eye.skywalking.plugin.interceptor.enhance;
import com.a.eye.skywalking.plugin.interceptor.EnhancedClassInstanceContext;
/**
*
* A interceptor, which intercept method's invocation.
* The target methods will be defined in {@link ClassEnhancePluginDefine}'s subclass, most likely in {@link ClassInstanceMethodsEnhancePluginDefine}
*
* @author wusheng
*/
public interface InstanceMethodsAroundInterceptor {
/**
......@@ -21,7 +21,7 @@ public interface InstanceMethodsAroundInterceptor {
* called after target method invocation. Even method's invocation triggers an exception.
* @param context instance context, a class instance only has one {@link EnhancedClassInstanceContext} instance.
* @param interceptorContext method context, includes class name, method name, etc.
* @param ret the method's return original value.
* @param ret the method's original return value.
* @return the method's actual return value.
*/
Object afterMethod(EnhancedClassInstanceContext context, InstanceMethodInvokeContext interceptorContext, Object ret);
......
package com.a.eye.skywalking.plugin.interceptor.enhance;
import com.a.eye.skywalking.plugin.interceptor.EnhancedClassInstanceContext;
/**
* 通过拦截器的before方法,指定被拦截方法的返回值,不再调用原始方法取得返回值
* This is a method return value manipulator.
* When a interceptor's method, such as {@link InstanceMethodsAroundInterceptor#beforeMethod(EnhancedClassInstanceContext, InstanceMethodInvokeContext, MethodInterceptResult)}, has this as a method argument,
* the interceptor can manipulate the method's return value.
* <p>
* The new value set to this object, by {@link MethodInterceptResult#defineReturnValue(Object)}, will override the origin return value.
*
* @author wusheng
*/
public class MethodInterceptResult {
private boolean isContinue = true;
private Object _ret = null;
public void defineReturnValue(Object ret){
this.isContinue = false;
this._ret = ret;
}
private boolean isContinue = true;
private Object _ret = null;
/**
* define the new return value.
*
* @param ret new return value.
*/
public void defineReturnValue(Object ret) {
this.isContinue = false;
this._ret = ret;
}
/**
* @return true, will trigger method interceptor({@link ClassInstanceMethodsInterceptor} and {@link ClassStaticMethodsInterceptor}) to invoke the origin method. Otherwise, not.
*/
public boolean isContinue() {
return isContinue;
}
public boolean isContinue() {
return isContinue;
}
Object _ret(){
return _ret;
}
/**
* @return the new return value.
*/
Object _ret() {
return _ret;
}
}
package com.a.eye.skywalking.plugin.interceptor.enhance;
/**
* The static method's interceptor interface.
* Any plugin, which wants to intercept static methods, must implement this interface.
*
* @author wusheng
*/
public interface StaticMethodsAroundInterceptor {
void beforeMethod(StaticMethodInvokeContext interceptorContext, MethodInterceptResult result);
Object afterMethod(StaticMethodInvokeContext interceptorContext, Object ret);
void handleMethodException(Throwable t, MethodInvokeContext interceptorContext);
/**
* called before target method invocation.
*
* @param interceptorContext method context, includes class name, method name, etc.
* @param result change this result, if you want to truncate the method.
*/
void beforeMethod(StaticMethodInvokeContext interceptorContext, MethodInterceptResult result);
/**
* called after target method invocation. Even method's invocation triggers an exception.
*
* @param interceptorContext method context, includes class name, method name, etc.
* @param ret the method's original return value.
* @return the method's actual return value.
*/
Object afterMethod(StaticMethodInvokeContext interceptorContext, Object ret);
/**
* called when occur exception.
*
* @param t the exception occur.
* @param interceptorContext method context, includes class name, method name, etc.
*/
void handleMethodException(Throwable t, MethodInvokeContext interceptorContext);
}
......@@ -13,6 +13,12 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
/**
* The Classloader controller.
* This is a very important class in sky-walking's auto-instrumentation mechanism.
* If you want to fully understand why need this, and how it works, you need have knowledge about Classloader appointment mechanism.
* <p>
* The loader will load a class, and focus the target class loader (be intercepted class's classloader) loads it.
* <p>
* Created by wusheng on 16/8/2.
*/
public class InterceptorInstanceLoader {
......@@ -56,12 +62,13 @@ public class InterceptorInstanceLoader {
}
/**
* 通过二进制读取,直接加载类文件,然后通过上下文所需的classLoader强制加载
* load class from class binary files.
* Most likely all the interceptor implementations should be loaded by this.
*
* @param className
* @param targetClassLoader
* @param className interceptor class name.
* @param targetClassLoader the classloader, which should load the interceptor.
* @param <T>
* @return
* @return interceptor instance.
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
......@@ -111,12 +118,13 @@ public class InterceptorInstanceLoader {
}
/**
* 在当前classloader中查找是否已经加载此类。
* Find loaded class in the current classloader.
* Just in case some classes have already been loaded for some reasons.s
*
* @param className
* @param targetClassLoader
* @param className interceptor class name.
* @param targetClassLoader the classloader, which should load the interceptor.
* @param <T>
* @return
* @return interceptor instance.
*/
private static <T> T findLoadedClass(String className, ClassLoader targetClassLoader) throws InvocationTargetException, IllegalAccessException, InstantiationException {
Method defineClassMethod = null;
......
package com.a.eye.skywalking.toolkit.activation.opentracing;
import com.a.eye.skywalking.plugin.bytebuddy.ArgumentTypeNameMatch;
import com.a.eye.skywalking.plugin.interceptor.ConstructorInterceptPoint;
import com.a.eye.skywalking.plugin.interceptor.InstanceMethodsInterceptPoint;
import com.a.eye.skywalking.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册