在正式進入編寫環節以前,建議先花一點時間瞭解下javaagent(這是JDK 5引入的一個玩意兒,最好了解下其工做原理);另外,Skywalking用到了byte-buddy(一個動態操做二進制碼的庫),因此最好也熟悉下。html
固然不瞭解關係也不大,通常不影響你玩轉Skywalking。java
Span:可理解爲一次方法調用,一個程序塊的調用,或一次RPC/數據庫訪問。只要是一個具備完整時間週期的程序訪問,均可以被認爲是一個span。SkyWalking Span
對象中的重要屬性git
屬性 | 名稱 | 備註 |
---|---|---|
component | 組件 | 插件的組件名稱,如:Lettuce,詳見:ComponentsDefine.Class。 |
tag | 標籤 | k-v結構,關鍵標籤,key詳見:Tags.Class。 |
peer | 對端資源 | 用於拓撲圖,若DB組件,需記錄集羣信息。 |
operationName | 操做名稱 | 若span=0,operationName將會搜索的下拉列表。 |
layer | 顯示 | 在鏈路頁顯示,詳見SpanLayer.Class。 |
Trace:調用鏈,經過歸屬於其的Span來隱性的定義。一條Trace可被認爲是一個由多個Span組成的有向無環圖(DAG圖),在SkyWalking鏈路模塊你能夠看到,Trace又由多個歸屬於其的trace segment組成。github
Trace segment:Segment是SkyWalking中的一個概念,它應該包括單個OS進程中每一個請求的全部範圍,一般是基於語言的單線程。由多個歸屬於本線程操做的Span組成。數據庫
TIPSSkywalking的這幾個術語和Spring Cloud Sleuth相似,借鑑自谷歌的Dapper。我在 《Spring Cloud Alibaba微服務從入門到進階》 課程中有詳細剖析調用鏈的實現原理,而且用數據庫作了通俗的類比,本文再也不贅述。apache
詳見 http://www.itmuch.com/books/s... 文章有很是詳細的描述。app
本文以監控 org.apache.commons.lang3.StringUtils.replace
爲例,手把手教你編寫Skywalking插件。框架
首先,建立一個Maven項目,Pom.xml以下。maven
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itmuch.skywalking</groupId> <artifactId>apm-string-replace-plugin</artifactId> <packaging>jar</packaging> <version>1.0.0-SNAPSHOT</version> <properties> <skywalking.version>6.6.0</skywalking.version> <shade.package>org.apache.skywalking.apm.dependencies</shade.package> <shade.net.bytebuddy.source>net.bytebuddy</shade.net.bytebuddy.source> <shade.net.bytebuddy.target>${shade.package}.${shade.net.bytebuddy.source}</shade.net.bytebuddy.target> </properties> <dependencies> <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-agent-core</artifactId> <version>${skywalking.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-util</artifactId> <version>${skywalking.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-shade-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <shadedArtifactAttached>false</shadedArtifactAttached> <createDependencyReducedPom>true</createDependencyReducedPom> <createSourcesJar>true</createSourcesJar> <shadeSourcesContent>true</shadeSourcesContent> <relocations> <relocation> <pattern>${shade.net.bytebuddy.source}</pattern> <shadedPattern>${shade.net.bytebuddy.target}</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>6</source> <target>6</target> </configuration> </plugin> </plugins> </build> </project>
這個Pom.xml中,除以下依賴之外,其餘都得照抄,無論你開發什麼框架的Skywalking插件,不然沒法正常構建插件!!ide
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> <scope>provided</scope> </dependency>
public class StringReplaceInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { @Override protected ClassMatch enhanceClass() { // 指定想要監控的類 return NameMatch.byName("org.apache.commons.lang3.StringUtils"); } @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { return new ConstructorInterceptPoint[0]; } @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { // 指定想要監控的實例方法,每一個實例方法對應一個InstanceMethodsInterceptPoint return new InstanceMethodsInterceptPoint[0]; } @Override public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { // 指定想要監控的靜態方法,每個方法對應一個StaticMethodsInterceptPoint return new StaticMethodsInterceptPoint[]{ new StaticMethodsInterceptPoint() { @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { // 靜態方法名稱 return ElementMatchers.named("replace"); } @Override public String getMethodsInterceptor() { // 該靜態方法的監控攔截器類名全路徑 return "com.itmuch.skywalking.plugin.stringreplace.StringReplaceInterceptor"; } @Override public boolean isOverrideArgs() { return false; } } }; } }
public class StringReplaceInterceptor implements StaticMethodsAroundInterceptor { @Override public void beforeMethod(Class aClass, Method method, Object[] argumentsTypes, Class<?>[] classes, MethodInterceptResult methodInterceptResult) { // 建立span(監控的開始),本質上是往ThreadLocal對象裏面設值 AbstractSpan span = ContextManager.createLocalSpan("replace"); /* * 可用ComponentsDefine工具類指定Skywalking官方支持的組件 * 也可本身new OfficialComponent或者Component * 不過在Skywalking的控制檯上不會被識別,只會顯示N/A */ span.setComponent(ComponentsDefine.TOMCAT); span.tag(new StringTag(1000, "params"), argumentsTypes[0].toString()); // 指定該調用的layer,layer是個枚舉 span.setLayer(SpanLayer.CACHE); } @Override public Object afterMethod(Class aClass, Method method, Object[] objects, Class<?>[] classes, Object o) { String retString = (String) o; // 激活span,本質上是讀取ThreadLocal對象 AbstractSpan span = ContextManager.activeSpan(); // 狀態碼,任意寫,Tags也是個Skywalking的工具類,用來比較方便地操做tag Tags.STATUS_CODE.set(span, "20000"); // 中止span(監控的結束),本質上是清理ThreadLocal對象 ContextManager.stopSpan(); return retString; } @Override public void handleMethodException(Class aClass, Method method, Object[] objects, Class<?>[] classes, Throwable throwable) { AbstractSpan activeSpan = ContextManager.activeSpan(); // 記錄日誌 activeSpan.log(throwable); activeSpan.errorOccurred(); } }
建立resources/skywalking-plugin.def
,內容以下:
# Key=value的形式 # key隨便寫;value是Instrumentation類的包名類名全路徑 my-string-replace- plugin=org.apache.skywalking.apm.plugin.stringreplace.define.StringReplaceInstrumentation
mvn clean install
構建完成後,到target目錄中,找到JAR包(非 origin-xxx.jar
、非xxx-source.jar
),扔到 agent/plugins
目錄裏面去,便可啓動。
插件的編寫可能不是一步到位的,有時候可能會報點錯什麼的。若是想要Debug本身的插件,那麼須要將你的插件代碼和接入Java Agent的項目(也就是你配置了-javaagent啓動的項目)扔到同一個工做空間內,能夠這麼玩:
想辦法讓你接入Java Agent的項目,調用到以下代碼
String replace = StringUtils.replace("oldString", "old","replaced"); System.out.println(replace);
以後,就能夠看到相似以下的圖啦:
本文只是弄了一個簡單的例子,講解插件編寫的套路。總的來講,插件編寫仍是很是順利的,單純代碼的層面,不多會遇到坑;但搜遍各類搜索引擎,居然沒有一篇手把手的文章…並且也沒有文章講解依賴該如何引入、Maven插件如何引入。因而只好參考Skywalking官方插件的寫法,引入依賴和Maven插件了,這塊反卻是費了點時間。
此外,若是你想真正掌握乃至精通skywalking插件編寫,最好的辦法,仍是閱讀官方的插件代碼,詳見:https://github.com/apache/skywalking/tree/master/apm-sniffer/apm-sdk-plugin
,隨便挑兩款看一下就知道怎麼玩了。我在學習過程當中參考的插件代碼有:
http://www.itmuch.com/skywalk...
本文由博客一文多發平臺 OpenWrite 發佈!