未验证 提交 b1f47389 编写于 作者: wu-sheng's avatar wu-sheng 提交者: GitHub

Merge branch 'master' into feature/ui-protocol

......@@ -22,12 +22,13 @@ Underlying technology is a distributed tracing system.
* Pure Java server implementation, provide RESTful and gRPC services. Compatibility with other language agents/SDKs.
* The UI released on [skywalking-ui](https://github.com/apache/incubator-skywalking-ui)
# Architecture
<img src="https://skywalkingtest.github.io/page-resources/3.2.5%2b_architecture.jpg"/>
# Document
[![EN doc](https://img.shields.io/badge/document-English-blue.svg)](docs/README.md) [![cn doc](https://img.shields.io/badge/document-中文-blue.svg)](docs/README_ZH.md)
# 5.x Architecture
<img src="https://skywalkingtest.github.io/page-resources/5.0/architecture.png"/>
# Code of conduct
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to wusheng@apache.org.
# Screenshots
......
......@@ -24,12 +24,14 @@ Apache SkyWalking | [English](README.md)
* UI工程请查看 [skywalking-ui](https://github.com/apache/incubator-skywalking-ui)
* 中文QQ群:392443393
# Architecture
<img src="https://skywalkingtest.github.io/page-resources/3.2.5%2b_architecture.jpg"/>
# Document
[![EN doc](https://img.shields.io/badge/document-English-blue.svg)](docs/README.md) [![cn doc](https://img.shields.io/badge/document-中文-blue.svg)](docs/README_ZH.md)
[![EN doc](https://img.shields.io/badge/document-English-blue.svg)](docs/README.md) [![cn doc](https://img.shields.io/badge/-中文-blue.svg)](docs/README_ZH.md)
# 5.x Architecture
<img src="https://skywalkingtest.github.io/page-resources/5.0/architecture.png"/>
# code of conduct
This project adheres to the Contributor Covenant [code of conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to wusheng@apache.org.
# Screenshots
......
......@@ -36,7 +36,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jetty.version>9.4.2.v20170220</jetty.version>
<grpc.version>1.8.0</grpc.version>
<bytebuddy.version>1.7.6</bytebuddy.version>
<bytebuddy.version>1.7.9</bytebuddy.version>
<shade.package>org.apache.skywalking.apm.dependencies</shade.package>
<shade.com.lmax.disruptor.source>com.lmax.disruptor</shade.com.lmax.disruptor.source>
......
......@@ -33,6 +33,8 @@ public interface ILog {
void warn(String format, Object... arguments);
void warn(Throwable e, String format, Object... arguments);
void error(String format, Throwable e);
void error(Throwable e, String format, Object... arguments);
......
......@@ -26,9 +26,7 @@ package org.apache.skywalking.apm.agent.core.logging.api;
* Created by xin on 2016/11/10.
*/
public enum NoopLogger implements ILog {
INSTANCE {
};
INSTANCE;
@Override
public void info(String message) {
......@@ -89,4 +87,10 @@ public enum NoopLogger implements ILog {
public void error(Throwable e, String format, Object... arguments) {
}
@Override
public void warn(Throwable e, String format, Object... arguments) {
}
}
......@@ -105,6 +105,12 @@ public class EasyLogger implements ILog {
logger(LogLevel.WARN, replaceParam(format, arguments), null);
}
@Override
public void warn(Throwable e, String format, Object... arguments) {
if (isWarnEnable())
logger(LogLevel.WARN, replaceParam(format, arguments), e);
}
@Override
public void error(String format, Throwable e) {
if (isErrorEnable())
......
......@@ -30,6 +30,7 @@ import org.apache.skywalking.apm.agent.core.plugin.bytebuddy.AbstractJunction;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.IndirectMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.ProtectiveShieldMatcher;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.not;
......@@ -98,6 +99,6 @@ public class PluginFinder {
judge = judge.or(((IndirectMatch)match).buildJunction());
}
}
return judge;
return new ProtectiveShieldMatcher(judge);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.agent.core.plugin.match;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
/**
* In some cases, some frameworks and libraries use some binary codes tech too. From the community feedback, some of
* them have compatible issues with byte-buddy core, which trigger "Can't resolve type description" exception.
*
* So I build this protective shield by a nested matcher. When the origin matcher(s) can't resolve the type, the
* SkyWalking agent ignores this types.
*
* Notice: this ignore mechanism may miss some instrumentations, but at most cases, it's same. If missing happens,
* please pay attention to the WARNING logs.
*
* @author wu-sheng
*/
public class ProtectiveShieldMatcher<T> extends ElementMatcher.Junction.AbstractBase<T> {
private static final ILog logger = LogManager.getLogger(ProtectiveShieldMatcher.class);
private final ElementMatcher<? super T> matcher;
public ProtectiveShieldMatcher(ElementMatcher<? super T> matcher) {
this.matcher = matcher;
}
public boolean matches(T target) {
try {
return this.matcher.matches(target);
} catch (Throwable t) {
logger.warn(t, "Byte-buddy occurs exception when match type.");
return false;
}
}
}
......@@ -173,7 +173,7 @@ public class MongoDBMethodInterceptor implements InstanceMethodsAroundIntercepto
String executeMethod = arguments[0].getClass().getSimpleName();
String remotePeer = (String)objInst.getSkyWalkingDynamicField();
AbstractSpan span = ContextManager.createExitSpan(MONGO_DB_OP_PREFIX + method.getName(), new ContextCarrier(), remotePeer);
AbstractSpan span = ContextManager.createExitSpan(MONGO_DB_OP_PREFIX + executeMethod, new ContextCarrier(), remotePeer);
span.setComponent(ComponentsDefine.MONGODB);
Tags.DB_TYPE.set(span, DB_TYPE);
SpanLayer.asDB(span);
......
......@@ -122,7 +122,7 @@ public class MongoDBMethodInterceptorTest {
}
private void assertRedisSpan(AbstractTracingSpan span) {
assertThat(span.getOperationName(), is("MongoDB/getUsedDatabases"));
assertThat(span.getOperationName(), is("MongoDB/FindOperation"));
assertThat(SpanHelper.getComponentId(span), is(9));
List<KeyValuePair> tags = SpanHelper.getTags(span);
assertThat(tags.get(1).getValue(), is("FindOperation { \"name\" : \"by\" }"));
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.okhttp.v3;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Request;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
/**
* {@link AsyncCallInterceptor} get the `EnhanceRequiredInfo` instance from `SkyWalkingDynamicField` and then put it
* into `AsyncCall` instance when the `AsyncCall` constructor called.
*
* {@link AsyncCallInterceptor} also create an exit span by using the `EnhanceRequiredInfo` when the `execute` method
* called.
*
* @author zhangxin
*/
public class AsyncCallInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
/**
* The first argument of constructor is not the `real` parameter when the enhance class is an inner class. This
* is the JDK compiler mechanism.
*/
EnhancedInstance realCallInstance = (EnhancedInstance)allArguments[1];
Object enhanceRequireInfo = realCallInstance.getSkyWalkingDynamicField();
objInst.setSkyWalkingDynamicField(enhanceRequireInfo);
}
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
EnhanceRequiredInfo enhanceRequiredInfo = (EnhanceRequiredInfo)objInst.getSkyWalkingDynamicField();
Request request = (Request)enhanceRequiredInfo.getRealCallEnhance().getSkyWalkingDynamicField();
HttpUrl requestUrl = request.url();
AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri().getPath(), requestUrl.host() + ":" + requestUrl.port());
ContextManager.continued(enhanceRequiredInfo.getContextSnapshot());
ContextCarrier contextCarrier = new ContextCarrier();
ContextManager.inject(contextCarrier);
span.setComponent(ComponentsDefine.OKHTTP);
Tags.HTTP.METHOD.set(span, request.method());
Tags.URL.set(span, requestUrl.uri().toString());
SpanLayer.asHttp(span);
Field headersField = Request.class.getDeclaredField("headers");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(headersField, headersField.getModifiers() & ~Modifier.FINAL);
headersField.setAccessible(true);
Headers.Builder headerBuilder = request.headers().newBuilder();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
headerBuilder.add(next.getHeadKey(), next.getHeadValue());
}
headersField.set(request, headerBuilder.build());
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
@Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t) {
ContextManager.activeSpan().log(t);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.okhttp.v3;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
/**
* {@link EnhanceRequiredInfo} storage the `ContextSnapshot` and `RealCall` instances for support the async function of
* okhttp client.
*
* @author zhangxin
*/
public class EnhanceRequiredInfo {
private ContextSnapshot contextSnapshot;
private EnhancedInstance realCallEnhance;
public EnhanceRequiredInfo(EnhancedInstance realCallEnhance,
ContextSnapshot contextSnapshot) {
this.contextSnapshot = contextSnapshot;
this.realCallEnhance = realCallEnhance;
}
public ContextSnapshot getContextSnapshot() {
return contextSnapshot;
}
public EnhancedInstance getRealCallEnhance() {
return realCallEnhance;
}
}
......@@ -18,54 +18,40 @@
package org.apache.skywalking.apm.plugin.okhttp.v3;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import okhttp3.Headers;
import okhttp3.HttpUrl;
import okhttp3.Request;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
/**
* {@link EnqueueInterceptor} create a local span and the prefix of the span operation name is start with `Async` when
* the `enqueue` method called and also put the `ContextSnapshot` and `RealCall` instance into the
* `SkyWalkingDynamicField`.
*
* @author zhangxin
*/
public class EnqueueInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
EnhancedInstance callbackInstance = (EnhancedInstance)allArguments[0];
Request request = (Request)objInst.getSkyWalkingDynamicField();
ContextManager.createLocalSpan("Async" + request.url().uri().getPath());
ContextCarrier contextCarrier = new ContextCarrier();
HttpUrl requestUrl = request.url();
AbstractSpan span = ContextManager.createExitSpan(requestUrl.uri().getPath(), contextCarrier, requestUrl.host() + ":" + requestUrl.port());
span.setComponent(ComponentsDefine.OKHTTP);
Tags.HTTP.METHOD.set(span, request.method());
Tags.URL.set(span, requestUrl.uri().toString());
SpanLayer.asHttp(span);
Field headersField = Request.class.getDeclaredField("headers");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(headersField, headersField.getModifiers() & ~Modifier.FINAL);
headersField.setAccessible(true);
Headers.Builder headerBuilder = request.headers().newBuilder();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
headerBuilder.add(next.getHeadKey(), next.getHeadValue());
}
headersField.set(request, headerBuilder.build());
/**
* Here is the process about how to trace the async function.
*
* 1. Storage `Request` object into `RealCall` instance when the constructor of `RealCall` called.
* 2. Put the `RealCall` instance to `CallBack` instance
* 3. Get the `RealCall` instance from `CallBack` and then Put the `RealCall` into `AsyncCall` instance
* since the constructor of `RealCall` called.
* 5. Create the exit span by using the `RealCall` instance when `AsyncCall` method called.
*/
objInst.setSkyWalkingDynamicField(ContextManager.capture());
callbackInstance.setSkyWalkingDynamicField(new EnhanceRequiredInfo(objInst, ContextManager.capture()));
}
@Override
......
......@@ -20,7 +20,6 @@ package org.apache.skywalking.apm.plugin.okhttp.v3;
import java.lang.reflect.Method;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
......@@ -29,15 +28,12 @@ public class OnFailureInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
EnhancedInstance realCallInstance = (EnhancedInstance)allArguments[0];
ContextManager.createLocalSpan("CallBack/AsyncCall").errorOccurred();
ContextManager.continued((ContextSnapshot)realCallInstance.getSkyWalkingDynamicField());
ContextManager.activeSpan().errorOccurred();
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
......
......@@ -19,25 +19,32 @@
package org.apache.skywalking.apm.plugin.okhttp.v3;
import java.lang.reflect.Method;
import okhttp3.Response;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
/**
* {@link OnResponseInterceptor} validate the response code if it is great equal than 400. if so. the transaction status
* chang to `error`, or do nothing.
*
* @author zhangxin
*/
public class OnResponseInterceptor implements InstanceMethodsAroundInterceptor {
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable {
EnhancedInstance realCallInstance = (EnhancedInstance)allArguments[0];
ContextManager.createLocalSpan("CallBack/AsyncCall");
ContextManager.continued((ContextSnapshot)realCallInstance.getSkyWalkingDynamicField());
Response response = (Response)allArguments[1];
if (response.code() >= 400) {
ContextManager.activeSpan().errorOccurred();
}
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable {
ContextManager.stopSpan();
return ret;
}
......
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.skywalking.apm.plugin.okhttp.v3.define;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
public class AsyncCallInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[] {
new ConstructorInterceptPoint() {
@Override public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}
@Override public String getConstructorInterceptor() {
return "org.apache.skywalking.apm.plugin.okhttp.v3.AsyncCallInterceptor";
}
}
};
}
@Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[] {
new InstanceMethodsInterceptPoint() {
@Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("execute");
}
@Override public String getMethodsInterceptor() {
return "org.apache.skywalking.apm.plugin.okhttp.v3.AsyncCallInterceptor";
}
@Override public boolean isOverrideArgs() {
return false;
}
}
};
}
@Override protected ClassMatch enhanceClass() {
return byName("okhttp3.RealCall$AsyncCall");
}
}
okhttp-3.x=org.apache.skywalking.apm.plugin.okhttp.v3.define.RealCallInstrumentation
okhttp-3.x=org.apache.skywalking.apm.plugin.okhttp.v3.define.CallbackInstrumentation
okhttp-3.x=org.apache.skywalking.apm.plugin.okhttp.v3.define.AsyncCallInstrumentation
......@@ -38,7 +38,7 @@ import static org.apache.skywalking.apm.plugin.spring.concurrent.match.FailedCal
*/
public class FailureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public static final String FAILURE_CALLBACK_INTERCEPTOR = "FailureCallbackInterceptor";
public static final String FAILURE_CALLBACK_INTERCEPTOR = "org.apache.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor";
public static final String FAILURE_METHOD_NAME = "onFailure";
@Override
......
......@@ -38,7 +38,7 @@ import static org.apache.skywalking.apm.plugin.spring.concurrent.match.SuccessCa
public class SuccessCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
public static final String SUCCESS_CALLBACK_INTERCEPTOR =
"SuccessCallbackInterceptor";
"org.apache.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor";
public static final String SUCCESS_METHOD_NAME = "onSuccess";
@Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
......
......@@ -3,9 +3,6 @@
* Getting Started
* [Quick start](en/Quick-start.md)
* [Deploy Standalone mode collector](en/Deploy-collector-in-standalone-mode.md)
* [Deploy Cluster mode collector](en/Deploy-collector-in-cluster-mode.md)
* [Deploy javaagent](en/Deploy-skywalking-agent.md)
* [Deploy docker image](en/Deploy-docker-image.md)
* [Supported middlewares, frameworks and libraries](Supported-list.md)
* [How to disable plugins?](en/How-to-disable-plugin.md)
......@@ -21,6 +18,9 @@
* [Plugin Test](https://github.com/SkywalkingTest/agent-integration-test-report)
* [Java Agent Performance Test](https://skywalkingtest.github.io/Agent-Benchmarks/)
* Development Guides
* [Skywalking 3 Cross Process Propagation Headers Protocol, v1.0](en/Skywalking-3-Cross-Process-Propagation-Headers-Protocol.md)
* [How to build project](en/How-to-build.md)
* [Plugin development guide](en/Plugin-Development-Guide.md)
* Protocol
* [Cross Process Propagation Headers Protocol, v1.0](en/Skywalking-Cross-Process-Propagation-Headers-Protocol-v1.md)
* FAQ
......@@ -3,9 +3,6 @@
* [项目简介](/README_ZH.md)
* [快速入门](cn/Quick-start-CN.md)
* [部署单机collector](cn/Deploy-collector-in-standalone-mode-CN.md)
* [部署集群collector](cn/Deploy-collector-in-cluster-mode-CN.md)
* [部署探针Agent](cn/Deploy-skywalking-agent-CN.md)
* [部署Collector镜像](cn/Deploy-docker-image.CN.md)
* [中间件,框架与类库支持列表](Supported-list.md)
* [如何关闭特定插件](cn/How-to-disable-plugin-CN.md)
......@@ -25,8 +22,9 @@
* 开发指南
* [工程编译指南](cn/How-to-build-CN.md)
* [插件开发指南](cn/Plugin-Development-Guide-CN.md)
* [跨进程追踪上下文传递协议](cn/Skywalking-3-Cross-Process-Propagation-Headers-Protocol-CN.md)
* [探针与Collector间网络协议,v3.2+](cn/How-to-communicate-with-the-collector-CN.md)
* 交互协议
* [Cross Process Propagation Headers Protocol, v1.0 跨进程追踪上下文传递协议](cn/Skywalking-Cross-Process-Propagation-Headers-Protocol-CN-v1.md)
* [SkyWalking Trace Data Protocol 探针与Collector间网络协议](cn/Trace-Data-Protocol-CN.md)
* FAQ
* [Trace查询有数据,但是没有拓扑图和JVM数据?](cn/FAQ/Why-have-traces-no-others-CN.md)
* [加载探针,Console被GRPC日志刷屏](cn/FAQ/Too-many-gRPC-logs-CN.md)
......@@ -6,7 +6,6 @@
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-1.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-1.x/_latestVersion)
* 配置layout
```properties
......
......@@ -6,7 +6,6 @@
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-2.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-2.x/_latestVersion)
* 在log4j2.xml中的pattern 配置节,配置`[%traceId]`
```xml
......
......@@ -6,7 +6,6 @@
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-2.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-2.x/_latestVersion)
* 在logback.xml中的`Pattern`配制节中,设置`%tid`
```xml
......
......@@ -6,7 +6,6 @@
<version>${skywalking.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-trace/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-trace/_latestVersion)
* 随时使用 `TraceContext.traceId()` API,在应用程序的任何地方获取traceId.
```java
......
......@@ -2,17 +2,17 @@
本文档用于指导开发者,在本地开发环境中编译工程。
### 前言
因为工程结构和代码依赖会随版本变化,如果读者熟悉travis-ci,则可直接参考[.travis.yml](https://github.com/wu-sheng/sky-walking/blob/master/.travis.yml)
因为工程结构和代码依赖会随版本变化,如果读者熟悉travis-ci,则可直接参考[.travis.yml](../../.travis.yml)
### 编译步骤
1. 准备环境,jdk8,Maven
1. 执行`mvn clean package`
1. 生成包在`/packages`目录下,包括一个`skywalking-agent`的探针目录,以及两个collector包(.tar.gz是linux环境,.zip是windows环境)
### 在IntelliJ IDEA中编译工程
上述步骤在命令行中,能够很好的编译工程,但导入到编译器中的工程依然会有一些报错,我们需要进行几步简单的操作。
1. 在IntelliJ Terminal中,执行`mvn compile -Dmaven.test.skip=true`进行编译
1. 设置gRPC的自动生成代码目录,为源码目录
- **apm-network/target/generated--sources/protobuf**目录下的`grpc-java``java`目录
- **apm-protocol/apm-network/target/generated-sources/protobuf**目录下的`grpc-java``java`目录
- **apm-collector/apm-collector-remote/apm-remote-grpc-provider/target/protobuf**目录下的`grpc-java``java`目录
注:从3.2开始,网络通讯协议引入GRPC,所以增加上述的步骤
## 插件开发指南
本文档描述 [v3.2+](https://github.com/OpenTracing/skywalking/releases) 插件开发方法、使用的API,以及注意事项。
这边文档描述插件的开发和贡献方法
### 核心概念
#### 一. Span
## 核心概念
### 一. Span
Span是追踪系统中的通用概念(有时候被翻译成埋点),关于Span的定义,请参考[OpenTracing 中文版](https://github.com/opentracing-contrib/opentracing-specification-zh/blob/master/specification.md#opentracing数据模型)
sky-walking作为OpenTracing的支持者,在核心实现中,与标准有较高的相似度。
SkyWalking作为OpenTracing的支持者,在核心实现中,与标准有较高的相似度。当然,作为实际产品的需要,我们一会扩展相关概念。
我们将span分为三类:
......@@ -15,16 +16,19 @@ EntrySpan代表一个服务的提供方,即,服务端的入口点。它是
LocalSpan代表一个普通的Span,代表任意一个本地逻辑块(或方法)
1.3 ExitSpan
ExitSpan也可以称为LeafSpan(sky-walking的早期版本中的称呼),代表了一个远程服务的客户端调用。如:一次JDBC调用。
ExitSpan也可以称为LeafSpan(SkyWalking的早期版本中的称呼),代表了一个远程服务的客户端调用。如:一次JDBC调用。
#### 二. ContextCarrier
分布式追踪要解决的一个重要问题,就是跨进程的问题,ContextCarrier的概念就是为了解决这种场景。
### 二. ContextCarrier
分布式追踪要解决的一个重要问题,就是跨进程调用链连接的问题,ContextCarrier的概念就是为了解决这种场景。
当发生一次**A->B**的网络调用时:
1. 需要在客户端生成(inject操作)ContextCarrier,并序列化成String
1. 将这个String加入RPC调用的正文(或HEAD)中,传递到服务端
1. 创建一个空的ContextCarrier
1. 通过`ContextManager#createExitSpan`方法创建一个ExitSpan,或者使用`ContextManager#inject`,在过程中传入并初始化`ContextCarrier`
1.`ContextCarrier`中所有元素放入请求头(如:HTTP头)或消息正文(如 Kafka)
1. `ContextCarrier`随请求传输到服务端
1. 服务端收到后,转换为新的ContextCarrier
1. 通过提取操作(extract操作)建立关联
1. 通过`ContestManager#createEntrySpan`方法创建EntrySpan,或者使用`ContextManager#extract`,建立分布式调用关联
以HTTPComponent调用Tomcat为例:
1. 客户端(HTTPComponent端)
......@@ -33,8 +37,7 @@ ExitSpan也可以称为LeafSpan(sky-walking的早期版本中的称呼),代表
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
//向HTTP或者其他RPC HEAD中设置上下文
heads.put(next.getHeadKey(), next.getHeadValue());
httpRequest.setHeader(next.getHeadKey(), next.getHeadValue());
}
```
......@@ -44,23 +47,23 @@ ExitSpan也可以称为LeafSpan(sky-walking的早期版本中的称呼),代表
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
//从HTTP或者其他RPC HEAD中,根据指定的KEY,提取上下文
next.setHeadValue(heads.get(next.getHeadKey()));
next.setHeadValue(request.getHeader(next.getHeadKey()));
}
span = ContextManager.createEntrySpan(/span/operation/name, contextCarrier);
```
#### 三. ContextSnapshot
除了跨进程的RPC调用,另外一种追踪的常见场景是跨线程。跨线程和跨进程有很高的相似度,都是需要完成上下文的传递工作。所以ContextSnapshot具有和ContextCarrier十分类似的API风格。
### 三. ContextSnapshot
除了跨进程的RPC调用,另外一种追踪的常见场景是跨线程保持链路连接。跨线程和跨进程有很高的相似度,都是需要完成上下文的传递工作。
所以ContextSnapshot具有和ContextCarrier十分类似的API风格。
当发生一次**A->B**的跨线程调用时:
1. 需要在A线程中通过ContextManager#capture操作生成ContextSnapshot对象实例
1. 将这个ContextSnapshot对象传递到B线程中
1. B线程通过ContextManager#continued操作完成上下文传递
### 核心API
#### 一. ContextManager
## 核心API
### 一. ContextManager
ContextManager提供了追踪相关操作的主入口
1. 创建EntrySpan
......@@ -81,7 +84,7 @@ public static AbstractSpan createExitSpan(String operationName, ContextCarrier c
```
根据服务名,跨进程传递的ContextCarrier(空容器)和远端服务地址(IP、主机名、域名 + 端口),创建ExitSpan
#### 二. AbstractSpan
### 二. AbstractSpan
AbstractSpan提供了Span内部,进行操作的各项API
```java
......@@ -139,17 +142,21 @@ AbstractSpan提供了Span内部,进行操作的各项API
```
Span的操作语义和OpenTracing类似。
SpanLayer为我们的特有概念,如果是远程调用类的服务,请设置此属性,包括4个属性值
SpanLayer为我们的特有概念,如果是远程调用类的服务,请设置此属性,包括5个属性值
1. UNKNOWN, 默认
1. DB
1. RPC_FRAMEWORK,非HTTP类型的RPC框架,如:原生的DUBBO,MOTAN
1. HTTP
1. MQ
### 开发插件
#### 一. 简介
因为所有的程序调用都是基于方法的,所以插件实际上就是基于方法的拦截,类似面向切面编程的AOP技术。sky-walking底层已经完成相关的技术封装,所以插件开发者只需要定位需要拦截的类、方法,然后结合上文中的追踪API,即可完成插件的开发。
Component ID被SkyWalking项目组定义和保护。0到10000为保留值,如果你希望贡献新插件,可以在插件pull request通过,并提交的自动化
测试用户被接收后,申请自己的组件ID。私有插件,请使用10000以上的ID,避免重复。
## 开发插件
### 一. 简介
因为所有的程序调用都是基于方法的,所以插件实际上就是基于方法的拦截,类似面向切面编程的AOP技术。SkyWalking底层已经完成相关的技术封装,所以插件开发者只需要定位需要拦截的类、方法,然后结合上文中的追踪API,即可完成插件的开发。
#### 二. 拦截类型
### 二. 拦截类型
根据Java方法,共有三种拦截类型
1. 拦截构造函数
1. 拦截实例方法
......@@ -161,7 +168,7 @@ SpanLayer为我们的特有概念,如果是远程调用类的服务,请设
当然,也可以同时支持实例和静态方法,直接继承ClassEnhancePluginDefine。但是,这种情况很少。
#### 三. 实现自己的插件定义
### 三. 实现自己的插件定义
我们以继承ClassInstanceMethodsEnhancePluginDefine为例(ClassStaticMethodsEnhancePluginDefine十分类似,不再重复描述),描述定义插件的全过程
1. 定义目标类名称
......@@ -169,7 +176,7 @@ SpanLayer为我们的特有概念,如果是远程调用类的服务,请设
protected abstract ClassMatch enhanceClass();
```
ClassMatch反应类的匹配方式,目前提供种:
ClassMatch反应类的匹配方式,目前提供种:
* byName, 通过类名完整匹配
* byClassAnnotationMatch, 通过类标注进行匹配
......@@ -190,7 +197,7 @@ protected ClassMatch enhanceClassName() {
```
2. 定义构造函数拦截点
2. 定义方法拦截点
```java
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints();
......@@ -221,7 +228,7 @@ tomcat-7.x/8.x=TomcatInstrumentation
* 插件名称,要求全局唯一,命名规范:目标组件+版本号
* 插件定义类全名
#### 四. 实现拦截器逻辑
### 四. 实现拦截器逻辑
我们继续以实现实例方法拦截为例,拦截器需要实现org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor。
```java
/**
......@@ -262,15 +269,15 @@ public interface InstanceMethodsAroundInterceptor {
可以在方法执行前、执行后、执行异常三个点,进行拦截,设置修改方法参数(执行前),并调用核心API,设置追踪逻辑。
### 贡献插件到主仓库
## 贡献插件到主仓库
我们鼓励大家共同贡献支持各个类库的插件。
大家需支持以下步骤执行:
1. 在issue页面提出插件扩展需求,对应的版本。
1. Fork wu-sheng/sky-walking到本地
1. Fork apache/incubator-skywalking到本地
1. 在apm-sniffer/apm-sdk-plugin下新建自己的插件模块,模块名为:支持类库名称+版本号
1. 按照规范开发插件
1. 完善注释和测试用例
1. 在本地打包进行集成测试
1. 提交Pull Request到 wu-sheng/sky-walking,提供插件追踪的截图(拓扑和Trace明细),可独立运行的被追踪程序、docker镜像或docker-compose。
1. sky-walking PMC( Project Management Committee) 成员完成插件审核,确定发布版本,并合并到主仓库。
1. 提交Pull Request到 apache/incubator-skywalking,根据评审团队要求,提供相关自动化测试用例
1. SkyWalking Committer成员完成插件审核,确定发布版本,并合并到主仓库。
# Skywalking 3 Cross Process Propagation Headers Protocol
# Skywalking Cross Process Propagation Headers Protocol
* Version 1.0
这是Skywalking3跨进程传输头协议第一个公开版本。Skywalking是一个偏向APM的分布式追踪系统,所以,为了提供服务端处理性能。头信息会比其他的追踪系统要更复杂一些。你会发现,这个头信息,更像一个商业APM系统,并且,一些商业APM系统的头信息,比我们的要复杂的多。所以,如果你希望开发或者贡献其他语言探针、或者JAVA探针的其他市县模式,请耐心阅读,并理解此协议内容
Skywalking是一个偏向APM的分布式追踪系统,所以,为了提供服务端处理性能。头信息会比其他的追踪系统要更复杂一些
你会发现,这个头信息,更像一个商业APM系统,并且,一些商业APM系统的头信息,比我们的要复杂的多。
# Header Item
* Header Name: `sw3`
* Header Value: 使用`|`分隔,包含以下内容
_消息头使用sw3,因为此协议始于SkyWalking 3.x版本。_
## Values
* Trace Segment Id
......
# 探针与Collector间通讯协议
# Trace Data Protocol 中文
Trace Data Protocol协议,也就是探针与Collector间通讯协议
## 前言
这篇文章主要介绍3.2版本的Collector对外提供的服务协议。一般情况下,使用者和开发者都无需了解此协议细节。但是在庞大的开源生态中,我们已经收到过多次有公司或个人的使用案例,使用自己的非Java探针(PHP,GO等)探针,接入我们的Collector进行数据分析和监控。
此协议包含了Agent上行/下行数据的格式,可用于定制开发,或者探针的多语言扩展
## 协议类型
Collector从3.2开始,对外同时提供gRPC和HTTP RESTFul两种类型的协议。从效率上,我们推荐使用gRPC
# gRPC服务
本章节,描述官方java探针使用的网络协议
对外同时提供gRPC和HTTP RESTFul两种类型的协议。从效率上,我们推荐使用gRPC
## Collector服务发现协议
### 简介
......@@ -17,7 +16,7 @@ HTTP GET
### 协议内容
- 请求
GET操作:http://collectorIp:port/agentstream/grpc 。 其中`/agentstream/grpc`是默认值,如需修改,需要参考collector相关配置。
GET操作:http://collectorIp:port/agent/grpc 。 其中`/agent/grpc`是默认值,如需修改,需要参考collector相关配置。
- 返回
JSON数组,数组的每个元素,为一个有效的gRPC服务地址。
......@@ -33,7 +32,7 @@ JSON数组,数组的每个元素,为一个有效的gRPC服务地址。
gRPC服务
### 协议内容
https://github.com/apache/incubator-skywalking/blob/master/apm-network/src/main/proto/ApplicationRegisterService.proto
[gRPC service define](../..apm-protocol/apm-network/src/main/proto/ApplicationRegisterService.proto)
```proto
syntax = "proto3";
......@@ -44,22 +43,22 @@ import "KeyWithIntegerValue.proto";
//register service for ApplicationCode, this service is called when service starts.
service ApplicationRegisterService {
rpc register (Application) returns (ApplicationMapping) {
rpc batchRegister (Applications) returns (ApplicationMappings) {
}
}
message Application {
repeated string applicationCode = 1;
message Applications {
repeated string applicationCodes = 1;
}
message ApplicationMapping {
repeated KeyWithIntegerValue application = 1;
message ApplicationMappings {
repeated KeyWithIntegerValue applications = 1;
}
```
- 首次调用时,applicationCode为客户端设置的应用名(显示在拓扑图和应用列表上的名字)。之后随着追踪过程,会上报此应用相关的周边服务的`ip:port`地址列表
- KeyWithIntegerValue 返回,key为上报的applicationCode和ip:port地址,value为对应的id。applicationCode对应的返回id,在后续协议中,被称为applicationId。
- 此服务按需调用,本地无法找到ip:port对应的id时,可异步发起调用。
- 获取applicationId的操作是必选。
- 获取applicationId的操作是必选。后续追踪数据依赖此id
- 获取ip:port对应的id是可选,但是完成id设置,会有效提高collector处理效率,降低网络消耗。
......@@ -71,7 +70,7 @@ message ApplicationMapping {
gRPC服务
### 实例注册服务
https://github.com/apache/incubator-skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L11-L12
[gRPC service define](../../apm-protocol/apm-network/src/main/proto/DiscoveryService.proto#L11-L12)
```proto
service InstanceDiscoveryService {
rpc register (ApplicationInstance) returns (ApplicationInstanceMapping) {
......@@ -102,7 +101,7 @@ message ApplicationInstanceMapping {
- 服务端返回应用实例id,applicationInstanceId 。后续上报服务使用实例id标识。
### 实例心跳服务
https://github.com/apache/incubator-skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L14-L15
[gRPC service define](../../apm-protocol/apm-network/src/main/proto/DiscoveryService.proto#L14-L15)
```proto
service InstanceDiscoveryService {
rpc heartbeat (ApplicationInstanceHeartbeat) returns (Downstream) {
......@@ -142,7 +141,7 @@ message ApplicationInstanceRecover {
gRPC服务
### 协议内容
https://github.com/apache/incubator-skywalking/blob/master/apm-network/src/main/proto/DiscoveryService.proto#L53-L74
[gRPC service define](../../apm-protocol/apm-network/src/main/proto/DiscoveryService.proto#L53-L74)
```proto
//discovery service for ServiceName by Network address or application code
service ServiceNameDiscoveryService {
......@@ -179,7 +178,7 @@ message ServiceNameElement {
gRPC服务
### 协议内容
https://github.com/apache/incubator-skywalking/blob/master/apm-network/src/main/proto/JVMMetricsService.proto
[gRPC service define](../../apm-protocol/apm-network/src/main/proto/JVMMetricsService.proto)
```proto
syntax = "proto3";
......@@ -256,6 +255,7 @@ enum GCPhrase {
gRPC服务
### 协议内容
[gRPC service define](../../apm-protocol/apm-network/src/main/proto/TraceSegmentService.proto)
```proto
syntax = "proto3";
......@@ -281,10 +281,10 @@ message UniqueId {
message TraceSegmentObject {
UniqueId traceSegmentId = 1;
repeated TraceSegmentReference refs = 2;
repeated SpanObject spans = 3;
int32 applicationId = 4;
int32 applicationInstanceId = 5;
repeated SpanObject spans = 2;
int32 applicationId = 3;
int32 applicationInstanceId = 4;
bool isSizeLimited = 5;
}
message TraceSegmentReference {
......@@ -294,10 +294,11 @@ message TraceSegmentReference {
int32 parentApplicationInstanceId = 4;
string networkAddress = 5;
int32 networkAddressId = 6;
string entryServiceName = 7;
int32 entryServiceId = 8;
string parentServiceName = 9;
int32 parentServiceId = 10;
int32 entryApplicationInstanceId = 7;
string entryServiceName = 8;
int32 entryServiceId = 9;
string parentServiceName = 10;
int32 parentServiceId = 11;
}
message SpanObject {
......@@ -305,17 +306,18 @@ message SpanObject {
int32 parentSpanId = 2;
int64 startTime = 3;
int64 endTime = 4;
int32 operationNameId = 5;
string operationName = 6;
int32 peerId = 7;
string peer = 8;
SpanType spanType = 9;
SpanLayer spanLayer = 10;
int32 componentId = 11;
string component = 12;
bool isError = 13;
repeated KeyWithStringValue tags = 14;
repeated LogMessage logs = 15;
repeated TraceSegmentReference refs = 5;
int32 operationNameId = 6;
string operationName = 7;
int32 peerId = 8;
string peer = 9;
SpanType spanType = 10;
SpanLayer spanLayer = 11;
int32 componentId = 12;
string component = 13;
bool isError = 14;
repeated KeyWithStringValue tags = 15;
repeated LogMessage logs = 16;
}
enum RefType {
......@@ -330,10 +332,12 @@ enum SpanType {
}
enum SpanLayer {
Database = 0;
RPCFramework = 1;
Http = 2;
MQ = 3;
Unknown = 0;
Database = 1;
RPCFramework = 2;
Http = 3;
MQ = 4;
Cache = 5;
}
message LogMessage {
......@@ -342,11 +346,11 @@ message LogMessage {
}
```
- UniqueId为segment或者globalTraceId的数字表示。由3个long组成,1)applicationInstanceId,2)当前线程id,3)当前时间戳*10000 + seq(0-10000自循环)
- Span的数据,请参考[插件开发规范](https://github.com/apache/incubator-skywalking/wiki/Plugin-Development-Guide)
- Span的数据,请参考[插件开发规范](Plugin-Development-Guide-CN.md)
- 以下id和名称根据注册返回结果,优先上报id,无法获取id时,再上传name。参考之前的应用和服务注册章节。
- operationNameId/operationName
- networkAddress/networkAddressId
- entryServiceName/entryServiceId
- parentServiceName/parentServiceId
- peerId/peer
- componentId为默认支持的插件id,非官方支持,需传输名称或修改服务端源代码。[官方组件列表](../../apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java)
- componentId为默认支持的插件id,非官方支持,需传输名称或修改服务端源代码。[官方组件列表](../../apm-protocol/apm-network/src/main/java/org/apache/skywalking/apm/network/trace/component/ComponentsDefine.java)
......@@ -6,7 +6,6 @@
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-1.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apmg-toolkit-log4j-1.x/_latestVersion)
* Config a layout
```properties
......
......@@ -6,7 +6,6 @@
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-2.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-log4j-2.x/_latestVersion)
* Config the `[%traceId]` pattern in your log4j2.xml
```xml
......
......@@ -6,7 +6,6 @@
<version>{project.release.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-logback-1.x/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-logback-1.x/_latestVersion)
* set `%tid` in `Pattern` section of logback.xml
```xml
......
......@@ -6,7 +6,6 @@
<version>${skywalking.version}</version>
</dependency>
```
&nbsp;&nbsp;&nbsp;[ ![Download](https://api.bintray.com/packages/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-trace/images/download.svg) ](https://bintray.com/wu-sheng/skywalking/org.apache.skywalking.apm-toolkit-trace/_latestVersion)
* Use `TraceContext.traceId()` API to obtain traceId.
```java
......
## Download skywalking agent release version
- Go to [release page](https://github.com/wu-sheng/sky-walking/releases)
- Go to [release page](https://github.com/apache/incubator-skywalking/releases)
## Deploy skywalking javaagent
1. Copy the agent package to anywhere you like. The logs, plugins and config are all included in the package.
......@@ -42,5 +42,5 @@ CATALINA_OPTS="$CATALINA_OPTS -javaagent:/path/to/skywalking-agent/skywalking-ag
- Tomcat 8
Change the first line of `tomcat/bin/catalina.sh`.
```shell
set "CATALINA_OPTS=... -javaagent:E:\apache-tomcat-8.5.20\skywalking-agent\skywalking-agent.jar -Dconfig=\skywalking\config\dir"
set "CATALINA_OPTS=-javaagent:E:\apache-tomcat-8.5.20\skywalking-agent\skywalking-agent.jar -Dconfig=\skywalking\config\dir"
```
\ No newline at end of file
# How to build project
This document helps people to compile and build the project in your maven and IDE.
## Build in maven
1. Prepare JDK8 and maven3
1. Run `mvn clean package`
1. All packages are in `/packages`, which includes `skywalking-agent` folder, and two collector files(.tar.gz for Linux and .zip for Windows)
## Setup your IntelliJ IDEA
1. Import the project as a maven project
1. Run `mvn compile -Dmaven.test.skip=true` to compile project and generate source codes. Because we use gRPC and protobuf.
1. Set **Generated Source Codes** folders.
* `grpc-java` and `java` folders in **apm-protocol/apm-network/target/generated-sources/protobuf**
* `grpc-java` and `java` folders in **apm-collector/apm-collector-remote/apm-remote-grpc-provider/target/protobuf**
\ No newline at end of file
# Plugin Development Guide
This document describe how to understand, develop and contribute plugin.
## Concepts
### Span
Span is an important and common concept in distributed tracing system. Learn **Span** from
[Google Dapper Paper](https://research.google.com/pubs/pub36356.html) and
[OpenTracing](http://opentracing.io)
SkyWalking supports OpenTracing and OpenTracing-Java API from 2017. Our Span concepts are similar with the paper and OpenTracing.
Also we extend the Span.
There are three types of Span
1.1 EntrySpan
EntrySpan represents a service provider, also the endpoint of server side. As an APM system, we are targeting the
application servers. So almost all the services and MQ-comsumer are EntrySpan(s).
1.2 LocalSpan
LocalSpan represents a normal Java method, which don't relate with remote service, neither a MQ producer/comsumer
nor a service(e.g. HTTP service) provider/consumer.
1.3 ExitSpan
ExitSpan represents a client of service or MQ-producer, as named as `LeafSpan` at early age of SkyWalking.
e.g. accessing DB by JDBC, reading Redis/Memcached are cataloged an ExitSpan.
### ContextCarrier
In order to implement distributed tracing, the trace across process need to be bind, and the context should propagate
across the process. That is ContextCarrier's duty.
Here are the steps about how to use **ContextCarrier** in a `A->B` distributed call.
1. Create a new and empty `ContextCarrier` at client side.
1. Create an ExitSpan by `ContextManager#createExitSpan` or use `ContextManager#inject` to init the `ContextCarrier`.
1. Put all items of `ContextCarrier` into heads(e.g. HTTP HEAD), attachments(e.g. Dubbo RPC framework) or messages(e.g. Kafka)
1. The `ContextCarrier` propagates to server side by the service call.
1. At server side, get all items from heads, attachments or messages.
1. Create an EntrySpan by `ContestManager#createEntrySpan` or use `ContextManager#extract` to bind the client and server.
Let's demonstrate the steps by Apache HTTPComponent client plugin and Tomcat 7 server plugin
1. Client side steps by Apache HTTPComponent client plugin
```java
span = ContextManager.createExitSpan("/span/operation/name", contextCarrier, "ip:port");
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
httpRequest.setHeader(next.getHeadKey(), next.getHeadValue());
}
```
2. Server side steps by Tomcat 7 server plugin
```java
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(request.getHeader(next.getHeadKey()));
}
span = ContextManager.createEntrySpan(/span/operation/name, contextCarrier);
```
### ContextSnapshot
Besides across process, across thread but in a process need to be supported, because async process(In-memory MQ)
and batch process are common in Java. Across process and across thread are similar, because they are both about propagating
context. The only difference is that, don't need to serialize for across thread.
Here are the three steps about across thread propagation:
1. Use `ContextManager#capture` to get the ContextSnapshot object.
1. Let the sub-thread access the ContextSnapshot by any way, through method arguments or carried by an existed arguments
1. Use `ContextManager#continued` in sub-thread.
## Core APIs
### ContextManager
ContextManager provides all major and primary APIs.
1. Create EntrySpan
```java
public static AbstractSpan createEntrySpan(String operationName, ContextCarrier carrier)
```
Create EntrySpan by operation name(e.g. service name, uri) and **ContextCarrier**.
2. Create LocalSpan
```java
public static AbstractSpan createLocalSpan(String operationName)
```
Create LocalSpan by operation name(e.g. full method signature)
3. Create ExitSpan
```java
public static AbstractSpan createExitSpan(String operationName, ContextCarrier carrier, String remotePeer)
```
Create ExitSpan by operation name(e.g. service name, uri) and new **ContextCarrier** and peer address
(e.g. ip+port, hostname+port)
### AbstractSpan
```java
/**
* Set the component id, which defines in {@link ComponentsDefine}
*
* @param component
* @return the span for chaining.
*/
AbstractSpan setComponent(Component component);
/**
* Only use this method in explicit instrumentation, like opentracing-skywalking-bridge.
* It it higher recommend don't use this for performance consideration.
*
* @param componentName
* @return the span for chaining.
*/
AbstractSpan setComponent(String componentName);
AbstractSpan setLayer(SpanLayer layer);
/**
* Set a key:value tag on the Span.
*
* @return this Span instance, for chaining
*/
AbstractSpan tag(String key, String value);
/**
* Record an exception event of the current walltime timestamp.
*
* @param t any subclass of {@link Throwable}, which occurs in this span.
* @return the Span, for chaining
*/
AbstractSpan log(Throwable t);
AbstractSpan errorOccurred();
/**
* Record an event at a specific timestamp.
*
* @param timestamp The explicit timestamp for the log record.
* @param event the events
* @return the Span, for chaining
*/
AbstractSpan log(long timestamp, Map<String, ?> event);
/**
* Sets the string name for the logical operation this span represents.
*
* @return this Span instance, for chaining
*/
AbstractSpan setOperationName(String operationName);
```
Besides set operation name, tags and logs, two attributes shoule be set, which are component and layer,
especially for EntrySpan and ExitSpan
SpanLayer is the catalog of span. Here are 5 values:
1. UNKNOWN (default)
1. DB
1. RPC_FRAMEWORK, for a RPC framework, not an ordinary HTTP
1. HTTP
1. MQ
Component IDs are defined and protected by SkyWalking project, 0 -> 10000 IDs are reserved. If you want to contribute
a new plugin, you can ask for an official ID, after your pull request approved and automatic test cases accepted by PMC.
Please use > 10000 ID, if you are going to develop a private plugin or don't intend to contribute the plugin to community,
to avoid the ID conflict.
## Develop a plugin
### Abstract
The basic method to trace is intercepting a Java method, by using byte code manipulation tech and AOP concept.
SkyWalking boxed the byte code manipulation tech and tracing context propagation,
so you just need to define the intercept point(a.k.a. aspect pointcut in Spring)
### Intercept
SkyWalking provide two common defines to intercept Contructor, instance method and class method.
* Extend `ClassInstanceMethodsEnhancePluginDefine` defines `Contructor` intercept points and `instance method` intercept points.
* Extend `ClassStaticMethodsEnhancePluginDefine` definec `class method` intercept points.
Of course, you can extend `ClassEnhancePluginDefine` to set all intercept points. But it is unusual.
### Implement plugin
I will demonstrate about how to implement a plugin by extending `ClassInstanceMethodsEnhancePluginDefine`
1. Define the target class name
```java
protected abstract ClassMatch enhanceClass();
```
ClassMatch represents how to match the target classes, there are 4 ways:
* byName, through the full class name(package name + `.` + class name)
* byClassAnnotationMatch, through the class existed certain annotations.
* byMethodAnnotationMatch, through the class's method existed certain annotations.
* byHierarchyMatch, throught the class's parent classes or interfaces
**Attentions**:
* Forbid to use `*.class.getName()` to get the class String name. Recommend you to use literal String. This is for
avoiding ClassLoader issues.
* `by*AnnotationMatch` doesn't support the inherited annotations.
* Don't recommend use `byHierarchyMatch`, unless it is really necessary. Because using it may trigger intercepting
many unexcepted methods, which causes performance issues and concerns.
Example:
```java
@Override
protected ClassMatch enhanceClassName() {
return byName("org.apache.catalina.core.StandardEngineValve");
}
```
2. Define an instance method intercept point
```java
protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints();
public interface InstanceMethodsInterceptPoint {
/**
* class instance methods matcher.
*
* @return methods matcher
*/
ElementMatcher<MethodDescription> getMethodsMatcher();
/**
* @return represents a class name, the class instance must instanceof InstanceMethodsAroundInterceptor.
*/
String getMethodsInterceptor();
boolean isOverrideArgs();
}
```
Also use `Matcher` to set the target methods. Return **true** in `isOverrideArgs`, if you want to change the argument
ref in interceptor.
The following sections will tell you how to implement the interceptor.
3. Add plugin define into skywalking-plugin.def file
```properties
tomcat-7.x/8.x=TomcatInstrumentation
```
### Implement an interceptor
As an interceptor for an instance method, the interceptor implements
`org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor`
```java
/**
* 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 {
/**
* called before target method invocation.
*
* @param result change this result, if you want to truncate the method.
* @throws Throwable
*/
void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
MethodInterceptResult result) throws Throwable;
/**
* called after target method invocation. Even method's invocation triggers an exception.
*
* @param ret the method's original return value.
* @return the method's actual return value.
* @throws Throwable
*/
Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Object ret) throws Throwable;
/**
* called when occur exception.
*
* @param t the exception occur.
*/
void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
Throwable t);
}
```
Use the core APIs in before, after and exception handle stages.
### Contribute plugins into Apache SkyWalking repository
We are welcome everyone to contribute plugins.
Please follow there steps:
1. Submit an issue about which plugins are you going to contribute, including supported version.
1. Create sub modules under `apm-sniffer/apm-sdk-plugin`, and the name should include supported library name and versions
1. Follow this guide to develop. Make sure comments and test cases are provided.
1. Develop and test.
1. Send the pull request and ask for review, and provide the automatic test cases by following PMC members guides.
1. The plugin committers approves your plugins after automatic test cases provided and the tests passed in our CI.
1. The plugin accepted by SkyWalking.
# Skywalking 3 Cross Process Propagation Headers Protocol
# Skywalking Cross Process Propagation Headers Protocol
* Version 1.0
This is the first open edition about `Skywalking 3 Cross Process Propagation Headers Protocol`. The skywalking is more likely an APM system, rather than normal distributed tracing system. The Headers is much more complex than them in order to improving analysis performance of collector. You can find many similar mechanism in other commercial APM system.(Some even much more complex than us)
SkyWalking is more likely an APM system, rather than common distributed tracing system.
The Headers is much more complex than them in order to improving analysis performance of collector.
You can find many similar mechanism in other commercial APM system.(Some even much more complex than us)
# Header Item
* Header Name: `sw3`
* Header Value: Split by `|`, the parts are following.
_The header protocol came from SkyWalking 3, back to 2017. So sw3 header name keeps now._
## Values
* Trace Segment Id
......
#!/bin/sh
check_pull_is_tagged() {
if [ "${TRAVIS_TAG}" == "" ]; then
return 1
else
echo "This build was started by the tag ${TRAVIS_TAG}, push image"
return 0
fi
}
check_release_tag() {
tag="${TRAVIS_TAG}"
if [[ "$tag" =~ ^v[0-9.]*-[0-9]{4}$ ]]; then
return 0;
else
echo "The provided tag ${tag} doesn't match that."
return 1;
fi
}
push_image() {
IMAGE_VERSION=`echo ${TRAVIS_TAG:1}`
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
mvn clean package docker:build
docker push skywalking/skywalking-collector:latest
docker push skywalking/skywalking-collector:${IMAGE_VERSION}
}
if check_pull_is_tagged && check_release_tag; then
push_image
echo "Push is Done!"
fi
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册