Add finagle plugin (#4441)

* Add finagle plugin (#4433)

* fix failed checks for pr(#4441)
* Add licenses for some files
* Update Supported doc
* Add finagle to test component-libraries.yml

* Add finagle automatic tests into CI

* Add comments

* update comments

* Remove CompatibilityChecker

* Move query-protocol submodule to the right version

* Remove `enhancedInstance.setSkyWalkingDynamicField` in `ClientTracingFilterInterceptor`.

* Update expectedData.yaml of finagle tests

* Use lazy ContextCarrier injection.

* Add comments for `ContextCarrierHelper`

* Fix ContextHolderFactory to avoid context pollution

Co-authored-by: huangyongjie <huangyongjie@tigerbrokers>
Co-authored-by: 吴晟 Wu Sheng <wu.sheng@foxmail.com>
This commit is contained in:
yoje 2020-03-11 13:04:58 +08:00 committed by GitHub
parent 069b99bdbc
commit ced5cb2828
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 3868 additions and 1 deletions

View File

@ -239,7 +239,7 @@ jobs:
- name: Run kotlin coroutine 1.0.1-1.3.3 (4)
run: bash test/plugin/run.sh kotlin-coroutine-scenario
Ehcache_Undertow_Jedis:
Ehcache_Undertow_Jedis_Finagle:
runs-on: ubuntu-18.04
timeout-minutes: 90
strategy:
@ -271,6 +271,12 @@ jobs:
run: bash test/plugin/run.sh undertow-scenario
- name: Run jedis 2.4.0-2.9.0 (18)
run: bash test/plugin/run.sh jedis-scenario
- name: Run finagle 6.25.0-6.43.0
run: bash test/plugin/run.sh finagle-6.25.x-scenario
- name: Run finagle 6.44.0-7.1.0
run: bash test/plugin/run.sh finagle-6.44.x-scenario
- name: Run finagle 17.10.0-20.1.0
run: bash test/plugin/run.sh finagle-17.10.x-scenario
Spring41x_SolrJ-Http:
runs-on: ubuntu-18.04

View File

@ -154,4 +154,6 @@ public class ComponentsDefine {
public static final OfficialComponent AVRO_CLIENT = new OfficialComponent(83, "AvroClient");
public static final OfficialComponent UNDERTOW = new OfficialComponent(84, "Undertow");
public static final OfficialComponent FINAGLE = new OfficialComponent(85, "Finagle");
}

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<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">
<parent>
<artifactId>apm-sdk-plugin</artifactId>
<groupId>org.apache.skywalking</groupId>
<version>7.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>apm-finagle-6.25.x-plugin</artifactId>
<packaging>jar</packaging>
<name>apm-finagle-6.25.x-plugin</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<finagle.version>6.34.0</finagle.version>
<scala.library.version>2.11.8</scala.library.version>
</properties>
<dependencies>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-core_2.11</artifactId>
<version>${finagle.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.library.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.3.1</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,112 @@
/*
* 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.finagle;
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 java.lang.reflect.Method;
/**
* Finagle is an asynchronous rpc framework, every method in its rpc call stack return a future, which means each
* method may be executed in other thread. The data transfer mechanism across threads or across processes of finagle is
* achieved by using com.twitter.finagle.context. There are two kinds of context, LocalContext used to transfer data
* across threads, MarshalledContext used to transfer data across processes.
*
* <h3> A simple finagle rpc stack </h3>
*
* +-----------------------------------------------------------------------------------------------+
* | Client Server |
* | |
* | initiate rpc (user thread) invoke service (usually io thread) |
* | | /|\ |
* | \|/ | |
* | ClientTracingFilter (user thread) +------------------+ |
* | | | other filters | |
* | \|/ | in the | |
* | +------------------+ | rpc call stack | |
* | | other filters | +------------------+ |
* | | in the | (other thread) /|\ |
* | | rpc call stack | | |
* | +----------+-------+ | |
* | | ServerTracingFilter (usually io thread) |
* | \|/ /|\ |
* | ClientDestTracingFilter (other thread) | |
* | | +------------------+ |
* | \|/ | other filters | |
* | +------------------+ | in the | (usually io thread) |
* | | other filters | | rpc call stack | |
* | | in the | (other thread) +------------------+ |
* | | rpc call stack | /|\ |
* | +----------+-------+ | |
* | | | |
* | \|/ | |
* | +----------------------------------------------------------------------------------+ |
* | | Protocol specified transport | |
* | | such as http, thrift, redis, mysql, etc. | |
* | +----------------------------------------------------------------------------------+ |
* +-----------------------------------------------------------------------------------------------+
*
* <h3> Plugin Implementation </h3>
*
* In client side, We create finagle exitspan in the ClientTracingFilter, then add SWContextCarrier into the
* MarshalledContext, however in ClientTracingFilter, we can not know the remote address, So we add exitspan
* into the LocalContext, when the request reaches ClientDestTracingFilter, we know the remote address, then we can get
* exitspan from LocalContext and set remote address.
*
* In Server side, with default config, the ServerTracingFilter and the user code will be executed in the same thread,
* unless users use a com.twitter.util.FuturePool to execute business code or the com.twitter.finagle.filter
* .OffloadFilter is enabled which default is disabled, in bose cases, we had better do nothing and leave this to
* users, they can custom FuturePool to propagate context correctly. So we just create finagel entryspan in
* ServerTracingFilter to meet the default behavior of finagle.
*/
abstract class AbstractInterceptor implements InstanceConstructorInterceptor, InstanceMethodsAroundInterceptor {
@Override
public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
onConstructImpl(objInst, allArguments);
}
@Override
public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
beforeMethodImpl(objInst, method, allArguments, argumentsTypes, result);
}
@Override
public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
return afterMethodImpl(objInst, method, allArguments, argumentsTypes, ret);
}
@Override
public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
handleMethodExceptionImpl(objInst, method, allArguments, argumentsTypes, t);
}
abstract protected void onConstructImpl(EnhancedInstance objInst, Object[] allArguments);
abstract protected void beforeMethodImpl(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable;
abstract protected Object afterMethodImpl(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Object ret) throws Throwable;
abstract protected void handleMethodExceptionImpl(EnhancedInstance objInst, Method method, Object[] allArguments,
Class<?>[] argumentsTypes, Throwable t);
}

View File

@ -0,0 +1,74 @@
/*
* 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.finagle;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
import static org.apache.skywalking.apm.plugin.finagle.ContextCarrierHelper.tryInjectContext;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan;
/**
* Finagle use Annotation to represent data that tracing system interested, usually these annotations are created by
* filters after ClientTracingFilter in the rpc call stack. We can intercept annotations that we interested.
*/
public class AnnotationInterceptor {
abstract static class Abstract implements InstanceConstructorInterceptor {
@Override
public void onConstruct(EnhancedInstance enhancedInstance, Object[] objects) {
onConstruct(enhancedInstance, objects, getSpan());
}
protected abstract void onConstruct(EnhancedInstance enhancedInstance, Object[] objects, AbstractSpan span);
}
/**
* When we create exitspan in ClientTracingFilter, we can't know the operation name, however the Rpc annotation
* contains the operation name we need, so we intercept the constructor of this Annotation and set operation name
* to exitspan.
*/
public static class Rpc extends Abstract {
@Override
protected void onConstruct(EnhancedInstance enhancedInstance, Object[] objects, AbstractSpan span) {
if (objects != null && objects.length == 1) {
String rpc = (String) objects[0];
if (span != null && span.isExit()) {
/*
* The Rpc Annotation is created both in client side and server side, in server side, this
* annotation is created only in finagle versions below 17.12.0.
*
* If the span is not null, which means we are in the client side, we just set op name to the
* exitspan.
*
* If the span is null, which means we are in the server side with finagle version below 17.12.0.
* In server side, we don't need this annotation, because we can get op name from Contexts.broadcast
* which comes from client.
*/
span.setOperationName(rpc);
tryInjectContext((ExitSpan) span);
}
}
}
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.finagle;
import com.twitter.finagle.Address;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import static org.apache.skywalking.apm.plugin.finagle.ContextCarrierHelper.tryInjectContext;
import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan;
/**
* When we create exitspan in ClientTracingFilter, we can't know the remote address because the ClientTracingFilter
* is above the loadbalancefilter in the rpc call stack. However by intercept the ClientDestTracingFilter, we can get
* the remote adress and set it to exitspan and contextCarrier.
*/
public class ClientDestTracingFilterInterceptor extends AbstractInterceptor {
@Override
public void onConstructImpl(EnhancedInstance enhancedInstance, Object[] objects) {
enhancedInstance.setSkyWalkingDynamicField(getRemote(objects));
}
@Override
public void beforeMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, MethodInterceptResult methodInterceptResult) throws Throwable {
String peer = (String) enhancedInstance.getSkyWalkingDynamicField();
getLocalContextHolder().let(FinagleCtxs.PEER_HOST, peer);
tryInjectContext((ExitSpan) getSpan());
}
@Override
public Object afterMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, Object o) throws Throwable {
getLocalContextHolder().remove(FinagleCtxs.PEER_HOST);
return o;
}
@Override
public void handleMethodExceptionImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects,
Class<?>[] classes, Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
private String getRemote(Object[] objects) {
if (objects == null || objects.length == 0) {
return "";
}
if (objects[0] instanceof InetSocketAddress) {
/*
* Compatible with versions below 6.33.0
* 6.33.0 and below use {@link java.net.SocketAddress} as parameter
*/
return formatPeer((InetSocketAddress) objects[0]);
} else if (objects[0] instanceof Address.Inet) {
return formatPeer(((Address.Inet) objects[0]).addr());
}
return "";
}
private String formatPeer(InetSocketAddress socketAddress) {
return socketAddress.getAddress().getHostAddress() + ":" + socketAddress.getPort();
}
}

View File

@ -0,0 +1,92 @@
/*
* 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.finagle;
import com.twitter.util.Future;
import com.twitter.util.FutureEventListener;
import org.apache.skywalking.apm.agent.core.context.ContextManager;
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.MethodInterceptResult;
import java.lang.reflect.Method;
import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.FINAGLE;
import static org.apache.skywalking.apm.plugin.finagle.Constants.PENDING_OP_NAME;
import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder;
import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getMarshalledContextHolder;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.SW_SPAN;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan;
public class ClientTracingFilterInterceptor extends AbstractInterceptor {
@Override
protected void onConstructImpl(EnhancedInstance objInst, Object[] allArguments) {
}
@Override
public void beforeMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes,
MethodInterceptResult methodInterceptResult) throws Throwable {
/*
* At this time, we can't know the operation name and peer address, so we just use placeholders here, the
* operation name will be filled by {@link AnnotationInterceptor$Rpc} and the peer address will be filled by
* {@link ClientDestTracingFilterInterceptor} later.
*/
AbstractSpan finagleSpan = ContextManager.createExitSpan(PENDING_OP_NAME, "");
finagleSpan.setComponent(FINAGLE);
SpanLayer.asRPCFramework(finagleSpan);
getLocalContextHolder().let(SW_SPAN, finagleSpan);
getMarshalledContextHolder().let(SWContextCarrier$.MODULE$, new SWContextCarrier());
}
@Override
public Object afterMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, Object ret) throws Throwable {
final AbstractSpan finagleSpan = getSpan();
getLocalContextHolder().remove(SW_SPAN);
getMarshalledContextHolder().remove(SWContextCarrier$.MODULE$);
finagleSpan.prepareForAsync();
ContextManager.stopSpan(finagleSpan);
((Future<?>) ret).addEventListener(new FutureEventListener<Object>() {
@Override
public void onSuccess(Object value) {
finagleSpan.asyncFinish();
}
@Override
public void onFailure(Throwable cause) {
finagleSpan.errorOccurred();
finagleSpan.log(cause);
finagleSpan.asyncFinish();
}
});
return ret;
}
@Override
public void handleMethodExceptionImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, Throwable throwable) {
ContextManager.activeSpan().errorOccurred().log(throwable);
}
}

View File

@ -0,0 +1,155 @@
/*
* 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.finagle;
import com.twitter.io.Buf;
import com.twitter.io.Bufs;
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.logging.api.ILog;
import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
public class CodecUtils {
static ILog LOGGER = LogManager.getLogger(CodecUtils.class);
private static ThreadLocal<ByteArrayOutputStream> REUSED_BOS = new ThreadLocal<ByteArrayOutputStream>() {
@Override
protected ByteArrayOutputStream initialValue() {
return new ByteArrayOutputStream(128);
}
};
private static ByteArrayOutputStream getBos() {
ByteArrayOutputStream bos = REUSED_BOS.get();
bos.reset();
return bos;
}
/**
* Encodes the swContextCarrier to byte array.
*
* SWContextCarrier consists of some strings, such as operation name, {@link CarrierItem#getHeadKey()},
* {@link CarrierItem#getHeadValue()}. We encode each string to byte array by
* {@link #encodeStringToBytes(String)}, then assemble these byte arrays in a certain order, each byte array has
* a fixed length of 4 bytes before it to record the length. The format as follow:
*
* |length of following byte array,4 byte|byte array|length of following byte array,4 byte|byte array|...
*
* The first byte array is operation name, followed by byte array of the key of first {@code CarrierItem},
* followed by byte array of the value of first {@code CarrierItem}, followed by byte array of second {@code
* CarrierItem}, and so on.
*
* @param swContextCarrier the swContextCarrier to encode
* @return
*/
static Buf encode(SWContextCarrier swContextCarrier) {
ByteArrayOutputStream bos = getBos();
try (DataOutputStream dos = new DataOutputStream(bos)) {
putString(dos, swContextCarrier.getOperationName());
CarrierItem next = swContextCarrier.getCarrier().items();
while (next.hasNext()) {
next = next.next();
if (next.getHeadKey() != null && next.getHeadValue() != null) {
putString(dos, next.getHeadKey());
putString(dos, next.getHeadValue());
}
}
bos.flush();
return Bufs.ownedBuf(bos.toByteArray());
} catch (Exception e) {
LOGGER.error("encode swContextCarrier exception.", e);
}
return Bufs.EMPTY;
}
/**
* Decodes byte array to SWContextCarrier.
*
* First we read 4 bytes from byte array, composing them into an int value n, and read the following n bytes,
* decodes them to a string by {@link #decodeStringFromBytes(byte[])}, and so on.
*
* The first string is operation name, other strings are a list pair of key and value, can be translated to
* {@link ContextCarrier}
*
* For convenient, we use {@link ByteBuffer} to wrap byte array.
*
* @param buf the byte array to decode
* @return
*/
static SWContextCarrier decode(Buf buf) {
ContextCarrier contextCarrier = new ContextCarrier();
SWContextCarrier swContextCarrier = new SWContextCarrier();
swContextCarrier.setContextCarrier(contextCarrier);
ByteBuffer byteBuffer = ByteBuffer.wrap(Bufs.ownedByteArray(buf));
String operationName = getNextString(byteBuffer);
if (operationName != null) {
swContextCarrier.setOperationName(operationName);
}
Map<String, String> data = readToMap(byteBuffer);
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(data.get(next.getHeadKey()));
}
return swContextCarrier;
}
private static void putString(DataOutputStream dos, String value) throws IOException {
byte[] bytes = encodeStringToBytes(value);
dos.writeInt(bytes.length);
dos.write(bytes);
}
private static String getNextString(ByteBuffer byteBuffer) {
if (byteBuffer.hasRemaining()) {
byte[] bytes = new byte[byteBuffer.getInt()];
byteBuffer.get(bytes);
return decodeStringFromBytes(bytes);
}
return null;
}
private static Map<String, String> readToMap(ByteBuffer byteBuffer) {
Map<String, String> data = new HashMap<>();
String key = null;
while ((key = getNextString(byteBuffer)) != null) {
data.put(key, getNextString(byteBuffer));
}
return data;
}
private static byte[] encodeStringToBytes(String value) {
return value.getBytes(StandardCharsets.UTF_8);
}
private static String decodeStringFromBytes(byte[] bytes) {
return new String(bytes, StandardCharsets.UTF_8);
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.finagle;
public class Constants {
public static final String PENDING_OP_NAME = "pending";
}

View File

@ -0,0 +1,56 @@
/*
* 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.finagle;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan;
import static org.apache.skywalking.apm.plugin.finagle.Constants.PENDING_OP_NAME;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getPeerHost;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSWContextCarrier;
class ContextCarrierHelper {
/**
* In {@link ClientTracingFilterInterceptor}, we create {@link ExitSpan} without op name and peer information, and
* we use {@link AnnotationInterceptor.Rpc} and {@link ClientDestTracingFilterInterceptor} to put op name and
* peer information into LocalContext, but the order of these two interceptors are uncertain, so after each
* interceptor, we check if the op name and peer information are exists in LocalContext, if it exists, we set it
* to span and inject to contextCarrier.
*/
static void tryInjectContext(ExitSpan span) {
String operationName = span.getOperationName();
if (PENDING_OP_NAME.equals(operationName)) {
return;
}
String peer = getPeerHost();
if (peer == null) {
return;
}
span.setPeer(peer);
ContextCarrier contextCarrier = new ContextCarrier();
span.inject(contextCarrier);
SWContextCarrier swContextCarrier = getSWContextCarrier();
// we can ensure swContextCarrier is not null here
swContextCarrier.setContextCarrier(contextCarrier);
swContextCarrier.setOperationName(operationName);
}
}

View File

@ -0,0 +1,90 @@
/*
* 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.finagle;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
/**
* <h3> Finagle context usage </h3>
*
* The only way we can transfer data through finagle context as below:
* <pre>{@code
* Context context = Contexts.local(); // Contexts.broadcast()
* context.let(key, value, (Function0) fn);
* }</pre>
*
* which means bind value to key in the scope of fn, even if fn may be executed in any threads. But we can't use this
* method directly, for example, when we intercept ClientTracingFilter, what we need is add SWContextCarrier
* into the MarshalledContext in beforeMethod, and remove it in afterMethod, as below:
* <pre>{@code
* abstract ClientTracingFilterInterceptor extends InstanceMethodsAroundInterceptor {
* void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes
* MethodInterceptResult result) throws Throwable {
* Context context = Contexts.broadcast();
* SWContextCarrier swContextCarrier = new SWContextCarrier();
* context.let(key, swContextCarrier);
* }
*
* Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes
* Object ret) throws Throwable {
* Context context = Contexts.broadcast();
* context.remove(key);
* }
* }}</pre>
*
* So we use ContextHolder to achieve this, the {@link #let(Object, Object)} and {@link #remove(Object)} methos split
* the function of <pre>let(key, value, (Function0) fn)</pre> into two methods.
*
* <h3> ContextHolder usage </h3>
*
* 1. For each let operation, there MUST be a corresponding remove operaton.
* 2. The order of remove operation MUST be the opposite of the order of let operation, that is, first let last remove
* 3. This class can ONLY be used in subclasses of {@link InstanceMethodsAroundInterceptor}, and the let method can
* ONLY called in {@link InstanceMethodsAroundInterceptor#beforeMethod}, the remove method can ONLY be called in
* {@link InstanceMethodsAroundInterceptor#afterMethod}.
*
* <pre>{@code
* class Interceptor implements InstanceMethodsAroundInterceptor {
*
* @Override
* public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
* MethodInterceptResult result) throws Throwable {
* ContextHolder contextHolder = ...;
* contextHolder.let(key1, value1);
* contextHolder.let(key2, value2);
* contextHolder.let(key3, value3);
* }
*
* @Override
* public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
* Object ret) throws Throwable {
* ContextHolder contextHolder = ...;
* contextHolder.remove(key3);
* contextHolder.remove(key2);
* contextHolder.remove(key1);
* return afterMethodImpl(objInst, method, allArguments, argumentsTypes, ret);
* }
* }}</pre>
*/
abstract class ContextHolder {
abstract void let(Object key, Object value);
abstract void remove(Object key);
}

View File

@ -0,0 +1,238 @@
/*
* 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.finagle;
import com.twitter.finagle.context.Context;
import com.twitter.finagle.context.Contexts;
import com.twitter.finagle.context.LocalContext;
import com.twitter.finagle.context.MarshalledContext;
import com.twitter.io.Buf;
import com.twitter.util.Local;
import scala.Some;
import scala.Some$;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.LinkedList;
/**
* The implementation of {@link ContextHolder} depend on implementation detail of LocalContext and MarshalledContext of
* finagle. To implement {@link ContextHolder}, we need know the actual data struct that the underlying Context use,
* and use that data struct to impelment {@link ContextHolder#let(Object, Object)} and
* {@link ContextHolder#remove(Object)}.
*/
class ContextHolderFactory {
/*
* Below version 6.41.0(inclusive), this class is used to implement Context, above version 6.41.0, ImmutableMap
* is used. we check if this class is on the classpath, then we can know the actual data struct the underlying
* finagle used.
*/
private static final String CONTEXT_ENV_CLASS = "com.twitter.finagle.context.Context$Env";
private static ContextHolder MARSHALLED_CONTEXT_HOLDER;
private static ContextHolder LOCAL_CONTEXT_HOLDER;
static {
try {
Class.forName(CONTEXT_ENV_CLASS);
/*
* Compatible with versions 6.41.0 and below
*/
MARSHALLED_CONTEXT_HOLDER = new EnvContextHolder(Contexts.broadcast());
LOCAL_CONTEXT_HOLDER = new EnvContextHolder(Contexts.local());
} catch (ClassNotFoundException e) {
/*
* Compatible with versions above 6.41.0
*/
LOCAL_CONTEXT_HOLDER = new MapLocalContextHolder(Contexts.local());
MARSHALLED_CONTEXT_HOLDER = new MapMarshalledContextHolder(Contexts.broadcast());
}
}
static ContextHolder getMarshalledContextHolder() {
return MARSHALLED_CONTEXT_HOLDER;
}
static ContextHolder getLocalContextHolder() {
return LOCAL_CONTEXT_HOLDER;
}
static abstract class AbstractContextHolder<S> extends ContextHolder {
final Local<S> local;
final S initContext;
/**
* We push each let operation to the stack, when there is a remove operation, the key must be the same with
* key of let operation on the stack head.
*/
private final ThreadLocal<LinkedList<Snapshot<S>>> snapshots;
static class Snapshot<S> {
/**
* key from let operation
*/
private Object key;
/**
* value of {@link #local} before current let operation
*/
private S saved;
private Snapshot(Object key, S saved) {
this.key = key;
this.saved = saved;
}
}
AbstractContextHolder(Context context, String localFieldName) {
this.local = getLocal(context, localFieldName);
this.initContext = getInitContext(context);
this.snapshots = new ThreadLocal<LinkedList<Snapshot<S>>>() {
@Override
protected LinkedList<Snapshot<S>> initialValue() {
return new LinkedList<>();
}
};
}
@Override
void let(Object key, Object value) {
S currentContext = getCurrentContext();
snapshots.get().push(new Snapshot<>(key, currentContext));
local.update(getUpdatedContext(currentContext, key, value));
}
@Override
void remove(Object key) {
Snapshot<S> snapshot = snapshots.get().peek();
if (snapshot == null || !snapshot.key.equals(key)) {
throw new IllegalStateException(String.format("can't remove %s. the order of remove must be opposite with" +
" let.", key));
}
local.update(snapshot.saved);
snapshots.get().pop();
}
private S getCurrentContext() {
if (local.apply().isDefined()) {
return local.apply().get();
}
return initContext;
}
abstract protected S getUpdatedContext(S currentContext, Object key, Object value);
@SuppressWarnings("unchecked")
private Local<S> getLocal(Context context, String localFieldName) {
try {
Field localField = context.getClass().getDeclaredField(localFieldName);
localField.setAccessible(true);
return (Local<S>) localField.get(context);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
private S getInitContext(Context context) {
try {
Method method = context.getClass().getDeclaredMethod("env");
method.setAccessible(true);
return (S) method.invoke(context);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
static class EnvContextHolder extends AbstractContextHolder<Context.Env> {
private static final String LOCAL_FIELD_NAME = "com$twitter$finagle$context$Context$$local";
EnvContextHolder(Context context) {
super(context, LOCAL_FIELD_NAME);
}
@Override
protected Context.Env getUpdatedContext(Context.Env currentContext, Object key, Object value) {
return currentContext.bound(key, value);
}
}
static class MapLocalContextHolder extends ContextHolderFactory.AbstractContextHolder<scala.collection.immutable.Map<LocalContext.Key, Object>> {
private static final String LOCAL_FIELD_NAME = "local";
MapLocalContextHolder(LocalContext context) {
super(context, LOCAL_FIELD_NAME);
}
@Override
protected scala.collection.immutable.Map<LocalContext.Key, Object> getUpdatedContext(scala.collection.immutable.Map<LocalContext.Key, Object> currentContext, Object key, Object value) {
checkKeyType(key);
return currentContext.updated((LocalContext.Key) key, value);
}
private void checkKeyType(Object key) {
if (!(key instanceof LocalContext.Key)) {
throw new IllegalArgumentException("key should be subclass of LocalContext.Key");
}
}
}
static class MapMarshalledContextHolder extends ContextHolderFactory.AbstractContextHolder<scala.collection.immutable.Map<Buf, Object>> {
private static final String LOCAL_FIELD_NAME = "local";
private static final Constructor REAL_CONSTRUCTOR;
static {
try {
Class<?> clz = Class.forName(MarshalledContext.class.getName() + "$Real");
REAL_CONSTRUCTOR = clz.getDeclaredConstructor(MarshalledContext.class,
MarshalledContext.Key.class, Some.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
MapMarshalledContextHolder(MarshalledContext context) {
super(context, LOCAL_FIELD_NAME);
}
@Override
protected scala.collection.immutable.Map<Buf, Object> getUpdatedContext(scala.collection.immutable.Map<Buf, Object> currentContext, Object key, Object value) {
checkKeyType(key);
try {
MarshalledContext.Key marshalledContextKey = (MarshalledContext.Key) key;
Object real = REAL_CONSTRUCTOR.newInstance(Contexts.broadcast(), marshalledContextKey, Some$.MODULE$.apply(value));
return currentContext.updated(marshalledContextKey.marshalId(), real);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void checkKeyType(Object key) {
if (!(key instanceof MarshalledContext.Key)) {
throw new IllegalArgumentException("key should be subclass of MarshalledContext.Key");
}
}
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.finagle;
import com.twitter.finagle.context.Contexts;
import com.twitter.finagle.context.LocalContext;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
import javax.annotation.Nullable;
import java.lang.reflect.Constructor;
class FinagleCtxs {
static LocalContext.Key<AbstractSpan> SW_SPAN = null;
static LocalContext.Key<String> PEER_HOST = null;
static {
try {
Constructor constructor = LocalContext.Key.class.getConstructor(LocalContext.class);
SW_SPAN = (LocalContext.Key<AbstractSpan>) constructor.newInstance(Contexts.local());
PEER_HOST = (LocalContext.Key<String>) constructor.newInstance(Contexts.local());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Nullable
static AbstractSpan getSpan() {
if (Contexts.local().contains(SW_SPAN)) {
AbstractSpan abstractSpan = Contexts.local().apply(SW_SPAN);
return abstractSpan;
}
return null;
}
@Nullable
static SWContextCarrier getSWContextCarrier() {
if (Contexts.broadcast().contains(SWContextCarrier$.MODULE$)) {
SWContextCarrier swContextCarrier = Contexts.broadcast().apply(SWContextCarrier$.MODULE$);
return swContextCarrier;
}
return null;
}
@Nullable
static String getPeerHost() {
if (Contexts.local().contains(PEER_HOST)) {
String peerHost = Contexts.local().apply(PEER_HOST);
return peerHost;
}
return null;
}
}

View File

@ -0,0 +1,88 @@
/*
* 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.finagle;
import com.twitter.finagle.context.Contexts;
import com.twitter.util.Future;
import com.twitter.util.FutureEventListener;
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.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.MethodInterceptResult;
import java.lang.reflect.Method;
import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.FINAGLE;
import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder;
import static org.apache.skywalking.apm.plugin.finagle.FinagleCtxs.getSpan;
public class ServerTracingFilterInterceptor extends AbstractInterceptor {
@Override
protected void onConstructImpl(EnhancedInstance objInst, Object[] allArguments) {
}
@Override
public void beforeMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes,
MethodInterceptResult methodInterceptResult) throws Throwable {
AbstractSpan span = null;
if (Contexts.broadcast().contains(SWContextCarrier$.MODULE$)) {
SWContextCarrier swContextCarrier = Contexts.broadcast().apply(SWContextCarrier$.MODULE$);
span = ContextManager.createEntrySpan(swContextCarrier.getOperationName(), swContextCarrier.getCarrier());
} else {
span = ContextManager.createEntrySpan("unknown", new ContextCarrier());
}
span.setComponent(FINAGLE);
SpanLayer.asRPCFramework(span);
getLocalContextHolder().let(FinagleCtxs.SW_SPAN, span);
}
@Override
public Object afterMethodImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects, Class<?>[] classes, Object ret) throws Throwable {
final AbstractSpan finagleSpan = getSpan();
getLocalContextHolder().remove(FinagleCtxs.SW_SPAN);
finagleSpan.prepareForAsync();
ContextManager.stopSpan(finagleSpan);
((Future<?>) ret).addEventListener(new FutureEventListener<Object>() {
@Override
public void onSuccess(Object value) {
finagleSpan.asyncFinish();
}
@Override
public void onFailure(Throwable cause) {
finagleSpan.errorOccurred();
finagleSpan.log(cause);
finagleSpan.asyncFinish();
}
});
return ret;
}
@Override
public void handleMethodExceptionImpl(EnhancedInstance enhancedInstance, Method method, Object[] objects,
Class<?>[] classes, Throwable t) {
ContextManager.activeSpan().errorOccurred().log(t);
}
}

View File

@ -0,0 +1,34 @@
/*
* 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.finagle.define;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
public abstract class AbstractInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
/**
* this class exists in version 6.25.0 and above
*/
private static final String ADDRMETADATAEXTRACTION_CLASS = "com.twitter.finagle.client.AddrMetadataExtraction";
@Override
protected String[] witnessClasses() {
return new String[]{ADDRMETADATAEXTRACTION_CLASS};
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.finagle.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.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
public class AnnotationInstrumentation {
private static final String ANNOTATION_CLASS = "com.twitter.finagle.tracing.Annotation$";
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.AnnotationInterceptor$";
abstract static class Abstract extends AbstractInstrumentation {
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ANNOTATION_CLASS + getAnnoationName());
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return getConstructor();
}
@Override
public String getConstructorInterceptor() {
return INTERCEPT_CLASS + getAnnoationName();
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[0];
}
protected abstract String getAnnoationName();
protected abstract ElementMatcher<MethodDescription> getConstructor();
}
public static class Rpc extends Abstract {
@Override
protected String getAnnoationName() {
return "Rpc";
}
@Override
protected ElementMatcher<MethodDescription> getConstructor() {
return takesArgument(0, String.class);
}
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.finagle.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.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class ClientDestTracingFilterInstrumetation extends AbstractInstrumentation {
private static final String ENHANCE_CLASS = "com.twitter.finagle.tracing.ClientDestTracingFilter";
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.ClientDestTracingFilterInterceptor";
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return new ConstructorInterceptPoint[]{
new ConstructorInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getConstructorMatcher() {
return any();
}
@Override
public String getConstructorInterceptor() {
return INTERCEPT_CLASS;
}
}
};
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("apply");
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.finagle.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.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class ClientTracingFilterInstrumentation extends AbstractInstrumentation {
private static final String ENHANCE_CLASS = "com.twitter.finagle.tracing.ClientTracingFilter$TracingFilter";
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.ClientTracingFilterInterceptor";
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("apply");
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.finagle.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.match.ClassMatch;
import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
import static net.bytebuddy.matcher.ElementMatchers.named;
public class ServerTracingFilterInstrumentation extends AbstractInstrumentation {
private static final String ENHANCE_CLASS = "com.twitter.finagle.tracing.ServerTracingFilter$TracingFilter";
private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.finagle.ServerTracingFilterInterceptor";
@Override
protected ClassMatch enhanceClass() {
return NameMatch.byName(ENHANCE_CLASS);
}
@Override
public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
return null;
}
@Override
public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
return new InstanceMethodsInterceptPoint[]{
new InstanceMethodsInterceptPoint() {
@Override
public ElementMatcher<MethodDescription> getMethodsMatcher() {
return named("apply");
}
@Override
public String getMethodsInterceptor() {
return INTERCEPT_CLASS;
}
@Override
public boolean isOverrideArgs() {
return false;
}
}
};
}
}

View File

@ -0,0 +1,20 @@
# 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.
finagle=org.apache.skywalking.apm.plugin.finagle.define.AnnotationInstrumentation$Rpc
finagle=org.apache.skywalking.apm.plugin.finagle.define.ClientTracingFilterInstrumentation
finagle=org.apache.skywalking.apm.plugin.finagle.define.ClientDestTracingFilterInstrumetation
finagle=org.apache.skywalking.apm.plugin.finagle.define.ServerTracingFilterInstrumentation

View File

@ -0,0 +1,57 @@
/*
* 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.finagle
import com.twitter.finagle.context.Contexts
import com.twitter.io.Buf
import com.twitter.util.{Return, Try}
import org.apache.skywalking.apm.agent.core.context.ContextCarrier
class SWContextCarrier() {
private var operationName: String = ""
private var carrier: ContextCarrier = null;
def setOperationName(op: String): Unit = {
operationName = op
}
def setContextCarrier(carrier: ContextCarrier): Unit = this.carrier = carrier;
def getOperationName: String = operationName
def getCarrier(): ContextCarrier = carrier;
}
object SWContextCarrier extends Contexts.broadcast.Key[SWContextCarrier]("org.apache.skywalking.apm.plugin.finagle.SWContextCarrier") {
def of(carrier: ContextCarrier): SWContextCarrier = {
val sWContextCarrier = new SWContextCarrier()
sWContextCarrier.setContextCarrier(carrier)
sWContextCarrier
}
override def marshal(context: SWContextCarrier): Buf = {
CodecUtils.encode(context)
}
override def tryUnmarshal(buf: Buf): Try[SWContextCarrier] = {
val context = CodecUtils.decode(buf)
Return(context)
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.finagle;
import com.twitter.finagle.Service;
import com.twitter.util.Future;
import com.twitter.util.Promise;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.mockito.Mock;
import java.util.List;
import static org.apache.skywalking.apm.network.trace.component.ComponentsDefine.FINAGLE;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
public abstract class AbstractTracingFilterTest {
@Rule
public AgentServiceRule agentServiceRule = new AgentServiceRule();
@Mock
protected MethodInterceptResult methodInterceptResult;
protected EnhancedInstance enhancedInstance = new MockEnhancedInstance();
protected AnnotationInterceptor.Rpc rpcInterceptor = new AnnotationInterceptor.Rpc();
protected String rpc = "finagleRpc";
protected Object[] allArguments;
protected Class[] argumentTypes;
protected Promise result;
@Before
public void setup() throws Throwable {
result = new Promise();
allArguments = new Object[]{new Object(), new Service() {
@Override
public Future apply(Object request) {
return result;
}
} };
argumentTypes = new Class[]{Object.class, Service.class};
prepareForTest();
}
protected abstract void prepareForTest() throws Throwable;
protected abstract void assertSpan(AbstractTracingSpan span);
protected void assertTraceSegments(List<TraceSegment> traceSegments) {
assertThat(traceSegments.size(), is(1));
TraceSegment traceSegment = traceSegments.get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertFinagleSpan(spans.get(0));
}
protected void assertTraceSegmentsWithError(List<TraceSegment> traceSegments) {
assertThat(traceSegments.size(), is(1));
TraceSegment traceSegment = traceSegments.get(0);
List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
assertThat(spans.size(), is(1));
assertFinagleSpan(spans.get(0));
assertThat(SpanHelper.getLogs(spans.get(0)).size(), is(1));
assertErrorLog(SpanHelper.getLogs(spans.get(0)).get(0));
}
private void assertFinagleSpan(AbstractTracingSpan span) {
List<TagValuePair> tags = SpanHelper.getTags(span);
assertThat(tags.size(), is(0));
assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.RPC_FRAMEWORK));
assertThat(SpanHelper.getComponentId(span), is(FINAGLE.getId()));
assertThat(span.getOperationName(), is(rpc));
assertSpan(span);
}
private void assertErrorLog(LogDataEntity logData) {
assertThat(logData.getLogs().size(), is(4));
assertThat(logData.getLogs().get(0).getValue(), CoreMatchers.<Object>is("error"));
assertThat(logData.getLogs().get(1).getValue(), CoreMatchers.<Object>is(RuntimeException.class.getName()));
assertNull(logData.getLogs().get(2).getValue());
}
}

View File

@ -0,0 +1,112 @@
/*
* 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.finagle;
import com.twitter.finagle.Address;
import com.twitter.finagle.Addresses$;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.ExitTypeSpan;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class ClientTracingFilterInterceptorTest extends AbstractTracingFilterTest {
@SegmentStoragePoint
protected SegmentStorage segmentStorage;
private ClientTracingFilterInterceptor clientTracingFilterInterceptor;
private ClientDestTracingFilterInterceptor clientDestTracingFilterInterceptor =
new ClientDestTracingFilterInterceptor();
private EnhancedInstance enhancedClientDestTracingFilter = new MockEnhancedInstance();
private InetSocketAddress serverSocketAddress;
private Address serverAddr;
@Override
protected void prepareForTest() throws Throwable {
clientTracingFilterInterceptor = new ClientTracingFilterInterceptor();
serverSocketAddress = new InetSocketAddress(Inet4Address.getLocalHost(), 9999);
serverAddr = Addresses$.MODULE$.newInetAddress(serverSocketAddress);
}
@Override
protected void assertSpan(AbstractTracingSpan span) {
assertTrue(span.isExit());
assertThat(((ExitTypeSpan) span).getPeer(), is(serverSocketAddress.getAddress().getHostAddress() + ":" + serverSocketAddress.getPort()));
}
@Test
public void testClient() throws Throwable {
clientTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
result.setValue(new Object());
rpcInterceptor.onConstruct(null, new Object[]{rpc});
clientDestTracingFilterInterceptor.onConstruct(enhancedClientDestTracingFilter, new Object[]{serverAddr});
clientDestTracingFilterInterceptor.beforeMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, methodInterceptResult);
clientDestTracingFilterInterceptor.afterMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, result);
clientTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertTraceSegments(segmentStorage.getTraceSegments());
}
@Test
public void testClientWithException() throws Throwable {
clientTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
result.setValue(new Object());
rpcInterceptor.onConstruct(null, new Object[]{rpc});
clientDestTracingFilterInterceptor.onConstruct(enhancedClientDestTracingFilter, new Object[]{serverAddr});
clientDestTracingFilterInterceptor.beforeMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, methodInterceptResult);
clientDestTracingFilterInterceptor.afterMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, result);
clientTracingFilterInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException());
clientTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertTraceSegmentsWithError(segmentStorage.getTraceSegments());
}
@Test
public void testClientWithResultHasException() throws Throwable {
clientTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
result.setException(new RuntimeException());
rpcInterceptor.onConstruct(null, new Object[]{rpc});
clientDestTracingFilterInterceptor.onConstruct(enhancedClientDestTracingFilter, new Object[]{serverAddr});
clientDestTracingFilterInterceptor.beforeMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, methodInterceptResult);
clientDestTracingFilterInterceptor.afterMethod(enhancedClientDestTracingFilter, null, allArguments, argumentTypes, result);
clientTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertTraceSegments(segmentStorage.getTraceSegments());
}
}

View File

@ -0,0 +1,79 @@
/*
* 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.finagle;
import com.twitter.io.Bufs;
import org.apache.skywalking.apm.agent.core.context.CarrierItem;
import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
public class CodecUtilsTest {
@Test
public void encode() {
SWContextCarrier swContextCarrier = makeSWContextCarrier();
assertSwContextCarrier(swContextCarrier, CodecUtils.decode(CodecUtils.encode(swContextCarrier)));
swContextCarrier = makeSWContextCarrier();
assertSwContextCarrier(swContextCarrier, CodecUtils.decode(CodecUtils.encode(swContextCarrier)));
swContextCarrier = makeSWContextCarrier();
assertSwContextCarrier(swContextCarrier, CodecUtils.decode(CodecUtils.encode(swContextCarrier)));
ContextCarrier contextCarrier = new ContextCarrier();
swContextCarrier = new SWContextCarrier();
swContextCarrier.setContextCarrier(contextCarrier);
assertSwContextCarrier(swContextCarrier, CodecUtils.decode(Bufs.EMPTY));
}
private SWContextCarrier makeSWContextCarrier() {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
next.setHeadValue(UUID.randomUUID().toString());
}
SWContextCarrier swContextCarrier = new SWContextCarrier();
swContextCarrier.setContextCarrier(contextCarrier);
swContextCarrier.setOperationName(UUID.randomUUID().toString());
return swContextCarrier;
}
private void assertSwContextCarrier(SWContextCarrier expected, SWContextCarrier actual) {
assertThat(expected.getOperationName(), is(actual.getOperationName()));
Map<String, String> data = new HashMap<>();
CarrierItem next = expected.getCarrier().items();
while (next.hasNext()) {
next = next.next();
data.put(next.getHeadKey(), next.getHeadValue());
}
next = actual.getCarrier().items();
while (next.hasNext()) {
next = next.next();
assertThat(next.getHeadValue(), is(data.get(next.getHeadKey())));
}
}
}

View File

@ -0,0 +1,145 @@
/*
* 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.finagle;
import com.twitter.finagle.context.Contexts;
import com.twitter.finagle.context.LocalContext;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.lang.reflect.Constructor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getLocalContextHolder;
import static org.apache.skywalking.apm.plugin.finagle.ContextHolderFactory.getMarshalledContextHolder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class ContextHolderFactoryTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
private static LocalContext.Key<String> KEY1;
private static LocalContext.Key<String> KEY2;
private static LocalContext.Key<String> KEY3;
@BeforeClass
public static void setup() throws Exception {
Constructor constructor = LocalContext.Key.class.getConstructor(LocalContext.class);
KEY1 = (LocalContext.Key<String>) constructor.newInstance(Contexts.local());
KEY2 = (LocalContext.Key<String>) constructor.newInstance(Contexts.local());
KEY3 = (LocalContext.Key<String>) constructor.newInstance(Contexts.local());
}
@Test
public void testLCRemoveNonExistKey() {
testRemoveNonExistKey(getLocalContextHolder());
}
@Test
public void testLCRemoveWrongOrder() {
ContextHolder localContextHolder = getLocalContextHolder();
try {
localContextHolder.let(KEY1, "key1");
localContextHolder.let(KEY2, "key2");
testLCRemoveWrongOrder(localContextHolder, KEY1);
} finally {
localContextHolder.remove(KEY2);
localContextHolder.remove(KEY1);
}
}
@Test
public void testLCLetAndRemove() {
ContextHolder localContextHolder = getLocalContextHolder();
localContextHolder.let(KEY1, Thread.currentThread().getName() + KEY1);
localContextHolder.let(KEY2, Thread.currentThread().getName() + KEY2);
localContextHolder.let(KEY3, Thread.currentThread().getName() + KEY3);
localContextHolder.let(KEY2, Thread.currentThread().getName() + KEY2 + KEY2);
assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1);
assertEquals(Contexts.local().apply(KEY2), Thread.currentThread().getName() + KEY2 + KEY2);
assertEquals(Contexts.local().apply(KEY3), Thread.currentThread().getName() + KEY3);
localContextHolder.remove(KEY2);
assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1);
assertEquals(Contexts.local().apply(KEY2), Thread.currentThread().getName() + KEY2);
assertEquals(Contexts.local().apply(KEY3), Thread.currentThread().getName() + KEY3);
localContextHolder.remove(KEY3);
assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1);
assertEquals(Contexts.local().apply(KEY2), Thread.currentThread().getName() + KEY2);
assertFalse(Contexts.local().get(KEY3).isDefined());
localContextHolder.remove(KEY2);
assertEquals(Contexts.local().apply(KEY1), Thread.currentThread().getName() + KEY1);
assertFalse(Contexts.local().get(KEY2).isDefined());
assertFalse(Contexts.local().get(KEY3).isDefined());
localContextHolder.remove(KEY1);
assertFalse(Contexts.local().get(KEY1).isDefined());
assertFalse(Contexts.local().get(KEY2).isDefined());
assertFalse(Contexts.local().get(KEY3).isDefined());
}
@Test
public void testLCLetAndRemoveMultiThread() throws InterruptedException {
ExecutorService exec = Executors.newFixedThreadPool(5);
final AtomicInteger exceptions = new AtomicInteger(0);
for (int i = 0; i < 30; i++) {
exec.submit(new Runnable() {
@Override
public void run() {
try {
testLCLetAndRemove();
} catch (Exception e) {
exceptions.incrementAndGet();
}
}
});
}
exec.shutdown();
exec.awaitTermination(3, TimeUnit.MINUTES);
assertEquals(exceptions.get(), 0);
}
@Test
public void testMCRemoveNonExistKey() {
testRemoveNonExistKey(getMarshalledContextHolder());
}
private void testRemoveNonExistKey(ContextHolder contextHolder) {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("can't remove");
contextHolder.remove(new Object());
}
private void testLCRemoveWrongOrder(ContextHolder contextHolder, Object key) {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("can't remove");
thrown.expectMessage(key.toString());
contextHolder.remove(key);
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.finagle;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
public class MockEnhancedInstance implements EnhancedInstance {
private Object object;
@Override
public Object getSkyWalkingDynamicField() {
return object;
}
@Override
public void setSkyWalkingDynamicField(Object value) {
this.object = value;
}
}

View File

@ -0,0 +1,144 @@
/*
* 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.finagle;
import com.twitter.finagle.context.Contexts;
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.SW6CarrierItem;
import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
import org.apache.skywalking.apm.agent.test.helper.SegmentRefHelper;
import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import scala.runtime.AbstractFunction0;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(TracingSegmentRunner.class)
public class ServerTracingFilterInterceptorTest extends AbstractTracingFilterTest {
@SegmentStoragePoint
protected SegmentStorage segmentStorage;
private ServerTracingFilterInterceptor serverTracingFilterInterceptor;
@Override
protected void prepareForTest() {
serverTracingFilterInterceptor = new ServerTracingFilterInterceptor();
}
@Override
protected void assertSpan(AbstractTracingSpan span) {
assertTrue(span.isEntry());
}
@Test
public void testServer() {
runWithContext(new TestFunction() {
@Override
public void apply() throws Throwable {
rpcInterceptor.onConstruct(null, new Object[]{rpc});
serverTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
result.setValue(new Object());
serverTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertServer();
assertTraceSegments(segmentStorage.getTraceSegments());
}
});
}
@Test
public void testServerWithException() {
runWithContext(new TestFunction() {
@Override
public void apply() throws Throwable {
rpcInterceptor.onConstruct(null, new Object[]{rpc});
serverTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
result.setValue(new Object());
serverTracingFilterInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException());
serverTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertServer();
assertTraceSegmentsWithError(segmentStorage.getTraceSegments());
}
});
}
@Test
public void testServerWithResultHasException() {
runWithContext(new TestFunction() {
@Override
public void apply() throws Throwable {
rpcInterceptor.onConstruct(null, new Object[]{rpc});
serverTracingFilterInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
result.setException(new RuntimeException());
serverTracingFilterInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
assertServer();
assertTraceSegmentsWithError(segmentStorage.getTraceSegments());
}
});
}
private void runWithContext(final TestFunction function) {
ContextCarrier contextCarrier = new ContextCarrier();
CarrierItem next = contextCarrier.items();
while (next.hasNext()) {
next = next.next();
if (next.getHeadKey().equals(SW6CarrierItem.HEADER_NAME)) {
next.setHeadValue("1-MC4wLjA=-MS4zMjMuNDQzMw==-3-1-1-IzE5Mi4xNjguMS44IDoxODAwMg==-Iy9wb3J0Y" +
"Wwv-Iy90ZXN0RW50cnlTcGFu");
}
}
SWContextCarrier swContextCarrier = new SWContextCarrier();
swContextCarrier.setContextCarrier(contextCarrier);
swContextCarrier.setOperationName(rpc);
Contexts.broadcast().let(SWContextCarrier$.MODULE$, swContextCarrier, new AbstractFunction0<Void>() {
@Override
public Void apply() {
try {
function.apply();
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
return null;
}
});
}
interface TestFunction {
void apply() throws Throwable;
}
private void assertServer() {
TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
TraceSegmentRef actual = traceSegment.getRefs().get(0);
assertThat(SegmentRefHelper.getSpanId(actual), is(3));
assertThat(SegmentRefHelper.getEntryServiceInstanceId(actual), is(1));
assertThat(SegmentRefHelper.getTraceSegmentId(actual).toString(), is("1.323.4433"));
}
}

View File

@ -88,6 +88,7 @@
<module>play-2.x-plugin</module>
<module>lettuce-5.x-plugin</module>
<module>avro-plugin</module>
<module>finagle-6.25.x-plugin</module>
</modules>
<packaging>pom</packaging>

View File

@ -42,6 +42,7 @@
* [SOFARPC](https://github.com/alipay/sofa-rpc) 5.4.0
* [Armeria](https://github.com/line/armeria) 0.63.0 -> 0.98.0
* [Apache Avro](http://avro.apache.org) 1.7.0 - 1.8.x
* [Finagle](https://github.com/twitter/finagle) 6.25.0 -> 20.1.0
* MQ
* [RocketMQ](https://github.com/apache/rocketmq) 4.x
* [Kafka](http://kafka.apache.org) 0.11.0.0 -> 1.0

View File

@ -281,6 +281,9 @@ AvroClient:
Undertow:
id: 84
languages: Java
Finagle:
id: 85
languages: Java,Scala
# .NET/.NET Core components
# [3000, 4000) for C#/.NET only

View File

@ -248,6 +248,9 @@ AvroServer:
AvroClient:
id: 83
languages: Java
Finagle:
id: 85
languages: Java,Scala
# .NET/.NET Core components

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# 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.
home="$(cd "$(dirname $0)"; pwd)"
java -jar ${agent_opts} ${home}/../libs/finagle-17.10.x-scenario.jar &

View File

@ -0,0 +1,78 @@
# 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.
registryItems:
services:
- {finagle-17.10.x-scenario: 2}
instances:
- {finagle-17.10.x-scenario: 1}
operationNames:
- finagle-17.10.x-scenario: [hello, /finagle-17.10.x-scenario/case/finagle]
heartbeat: []
segmentItems:
- serviceName: finagle-17.10.x-scenario
segmentSize: gt 2
segments:
- segmentId: not null
spans:
- operationName: hello
operationId: 0
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 85
componentName: ''
isError: false
spanType: Entry
peer: ''
peerId: 0
refs:
- {parentEndpointId: 0, parentEndpoint: /finagle-17.10.x-scenario/case/finagle, networkAddressId: 0,
entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstanceId: 1, networkAddress: '127.0.0.1:12220', entryEndpoint: /finagle-17.10.x-scenario/case/finagle,
entryServiceInstanceId: 1}
- segmentId: not null
spans:
- operationName: hello
operationId: 0
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 85
componentName: ''
isError: false
spanType: Exit
peer: 127.0.0.1:12220
peerId: 0
- operationName: /finagle-17.10.x-scenario/case/finagle
operationId: 0
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
componentName: ''
isError: false
spanType: Entry
peer: ''
peerId: 0
tags:
- {key: url, value: 'http://localhost:8080/finagle-17.10.x-scenario/case/finagle'}
- {key: http.method, value: GET}

View File

@ -0,0 +1,23 @@
# 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.
type: jvm
entryService: http://localhost:8080/finagle-17.10.x-scenario/case/finagle
healthCheck: http://localhost:8080/finagle-17.10.x-scenario/case/healthCheck
startScript: ./bin/startup.sh
framework: finagle-17.10.x-scenario
environment:
dependencies:

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<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">
<groupId>org.apache.skywalking.apm.testcase</groupId>
<artifactId>finagle-17.10.x-scenario</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler.version>1.8</compiler.version>
<test.framework.version>17.10.0</test.framework.version>
<spring-boot-version>2.1.6.RELEASE</spring-boot-version>
<lombok.version>1.18.10</lombok.version>
</properties>
<name>skywalking-finagle-17.10.x-scenario</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-core_2.11</artifactId>
<version>${test.framework.version}</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-thrift_2.11</artifactId>
<version>${test.framework.version}</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>scrooge-core_2.11</artifactId>
<version>${test.framework.version}</version>
</dependency>
</dependencies>
<build>
<finalName>finagle-17.10.x-scenario</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
<outputDirectory>./target/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.twitter</groupId>
<artifactId>scrooge-maven-plugin</artifactId>
<version>${test.framework.version}</version>
<configuration>
<language>java</language>
<thriftOpts>
<thriftOpt>--finagle</thriftOpt>
</thriftOpts>
<buildExtractedThrift>false</buildExtractedThrift>
</configuration>
<executions>
<execution>
<id>generate-thrift-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>thrift-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>./bin</directory>
<fileMode>0775</fileMode>
</fileSet>
</fileSets>
<files>
<file>
<source>${project.build.directory}/finagle-17.10.x-scenario.jar</source>
<outputDirectory>./libs</outputDirectory>
<fileMode>0775</fileMode>
</file>
</files>
</assembly>

View File

@ -0,0 +1,55 @@
/*
* 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.testcase.finagle;
import com.twitter.finagle.ListeningServer;
import com.twitter.finagle.Thrift;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
import org.apache.skywalking.apm.testcase.finagle.service.FinagleRpcDemoServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class FinagleRpcApplication {
public static void main(String[] args) {
SpringApplication.run(FinagleRpcApplication.class, args);
}
@Configuration
public static class FinagleRpcConfiguration {
@Bean(destroyMethod = "close")
public ListeningServer server() {
ListeningServer server = Thrift.server()
.serveIface(":12220", new FinagleRpcDemoServiceImpl());
return server;
}
@Bean
public FinagleRpcDemoService.ServiceIface client() {
return Thrift.client()
.newIface("localhost:12220", FinagleRpcDemoService.ServiceIface.class);
}
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.testcase.finagle.controller;
import com.twitter.util.Await;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/case")
public class CaseController {
private static final String SUCCESS = "Success";
@Autowired
private FinagleRpcDemoService.ServiceIface finagleRpcDemoService;
@RequestMapping("/healthCheck")
@ResponseBody
public String healthCheck() {
return SUCCESS;
}
@RequestMapping("/finagle")
@ResponseBody
public String finagle() throws Exception {
System.out.println(Await.result(finagleRpcDemoService.hello("finagle")));
return SUCCESS;
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.testcase.finagle.service;
import com.twitter.util.Future;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
public class FinagleRpcDemoServiceImpl implements FinagleRpcDemoService.ServiceIface {
public Future<String> hello(String name) {
return Future.value("hello, " + name);
}
}

View File

@ -0,0 +1,21 @@
#
# 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.
#
#
server:
port: 8080
servlet:
context-path: /finagle-17.10.x-scenario

View File

@ -0,0 +1,23 @@
/*
* 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.
*
*/
namespace java org.apache.skywalking.apm.testcase.finagle.interfaces
service FinagleRpcDemoService {
string hello(string name);
}

View File

@ -0,0 +1,46 @@
# 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
# "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.
17.10.0
17.11.0
17.12.0
18.1.0
18.2.0
18.3.0
18.4.0
18.5.0
18.6.0
18.7.0
18.8.0
18.9.0
18.9.1
18.10.0
18.11.0
18.12.0
19.1.0
19.2.0
19.3.0
19.4.0
19.5.0
19.5.1
19.6.0
19.7.0
19.8.0
19.9.0
19.10.0
19.11.0
19.12.0
20.1.0

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# 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.
home="$(cd "$(dirname $0)"; pwd)"
java -jar ${agent_opts} ${home}/../libs/finagle-6.25.x-scenario.jar &

View File

@ -0,0 +1,86 @@
# 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.
registryItems:
services:
- {finagle-6.25.x-scenario: 2}
instances:
- {finagle-6.25.x-scenario: 1}
operationNames:
- finagle-6.25.x-scenario: [hello, /finagle-6.25.x-scenario/case/finagle]
heartbeat: []
segmentItems:
- serviceName: finagle-6.25.x-scenario
segmentSize: gt 2
segments:
- segmentId: not null
spans:
- operationName: hello
operationId: 0
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 85
componentName: ''
isError: false
spanType: Entry
peer: ''
peerId: 0
refs:
- {parentEndpointId: 0, parentEndpoint: /finagle-6.25.x-scenario/case/finagle, networkAddressId: 0,
entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstanceId: 1, networkAddress: '127.0.0.1:12220', entryEndpoint: /finagle-6.25.x-scenario/case/finagle,
entryServiceInstanceId: 1}
- segmentId: not null
spans:
- operationName: hello
operationId: 0
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 85
componentName: ''
isError: false
spanType: Exit
peer: 127.0.0.1:12220
peerId: 0
- operationName: /finagle-6.25.x-scenario/case/finagle
operationId: 0
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
componentName: ''
isError: false
spanType: Entry
peer: ''
peerId: 0
tags:
- {key: url, value: 'http://localhost:8080/finagle-6.25.x-scenario/case/finagle'}
- {key: http.method, value: GET}

View File

@ -0,0 +1,21 @@
# 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.
type: jvm
entryService: http://localhost:8080/finagle-6.25.x-scenario/case/finagle
healthCheck: http://localhost:8080/finagle-6.25.x-scenario/case/healthCheck
startScript: ./bin/startup.sh
framework: finagle

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<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>org.apache.skywalking</groupId>
<artifactId>finagle-6.25.x-scenario</artifactId>
<packaging>jar</packaging>
<version>5.0.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler.version>1.8</compiler.version>
<spring.boot.version>2.1.6.RELEASE</spring.boot.version>
<test.framework>finagle</test.framework>
<test.framework.version>6.25.0</test.framework.version>
</properties>
<name>skywalking-finagle-6.25.x-scenario</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-core_2.11</artifactId>
<version>${test.framework.version}</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-thrift_2.11</artifactId>
<version>${test.framework.version}</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.thrift</groupId>
<artifactId>libthrift</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>scrooge-core_2.11</artifactId>
<version>4.7.0</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>scrooge-runtime_2.11</artifactId>
<version>4.5.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<finalName>finagle-6.25.x-scenario</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
<outputDirectory>./target/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.twitter</groupId>
<artifactId>scrooge-maven-plugin</artifactId>
<version>4.5.0</version>
<configuration>
<language>experimental-java</language>
<thriftOpts>
<thriftOpt>--finagle</thriftOpt>
</thriftOpts>
<buildExtractedThrift>false</buildExtractedThrift>
</configuration>
<executions>
<execution>
<id>generate-thrift-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>thrift-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>http://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>http://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>./bin</directory>
<fileMode>0775</fileMode>
</fileSet>
</fileSets>
<files>
<file>
<source>${project.build.directory}/finagle-6.25.x-scenario.jar</source>
<outputDirectory>./libs</outputDirectory>
<fileMode>0775</fileMode>
</file>
</files>
</assembly>

View File

@ -0,0 +1,55 @@
/*
* 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.testcase.finagle;
import com.twitter.finagle.ListeningServer;
import com.twitter.finagle.Thrift;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
import org.apache.skywalking.apm.testcase.finagle.service.FinagleRpcDemoServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class FinagleRpcApplication {
public static void main(String[] args) {
SpringApplication.run(FinagleRpcApplication.class, args);
}
@Configuration
public static class FinagleRpcConfiguration {
@Bean(destroyMethod = "close")
public ListeningServer server() {
ListeningServer server = Thrift.server()
.serveIface(":12220", new FinagleRpcDemoServiceImpl());
return server;
}
@Bean
public FinagleRpcDemoService.FutureIface client() {
return Thrift.client()
.newIface("localhost:12220", FinagleRpcDemoService.FutureIface.class);
}
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.testcase.finagle.controller;
import com.twitter.util.Await;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/case")
public class CaseController {
private static final String SUCCESS = "Success";
@Autowired
private FinagleRpcDemoService.FutureIface finagleRpcDemoService;
@RequestMapping("/healthCheck")
@ResponseBody
public String healthCheck() {
return SUCCESS;
}
@RequestMapping("/finagle")
@ResponseBody
public String finagle() throws Exception {
System.out.println(Await.result(finagleRpcDemoService.hello("finagle")));
return SUCCESS;
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.testcase.finagle.service;
import com.twitter.util.Future;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
public class FinagleRpcDemoServiceImpl implements FinagleRpcDemoService.FutureIface {
public Future<String> hello(String name) {
return Future.value("hello, " + name);
}
}

View File

@ -0,0 +1,20 @@
# 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.
server:
port: 8080
servlet:
context-path: /finagle-6.25.x-scenario

View File

@ -0,0 +1,23 @@
/*
* 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.
*
*/
namespace java org.apache.skywalking.apm.testcase.finagle.interfaces
service FinagleRpcDemoService {
string hello(string name);
}

View File

@ -0,0 +1,34 @@
# 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
# "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.
6.25.0
6.26.0
6.27.0
6.28.0
6.29.0
6.30.0
6.31.0
6.33.0
6.34.0
6.35.0
6.36.0
6.37.0
6.38.0
6.39.0
6.40.0
6.41.0
6.42.0
6.43.0

View File

@ -0,0 +1,21 @@
#!/bin/bash
#
# 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.
home="$(cd "$(dirname $0)"; pwd)"
java -jar ${agent_opts} ${home}/../libs/finagle-6.44.x-scenario.jar &

View File

@ -0,0 +1,78 @@
# 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.
registryItems:
services:
- {finagle-6.44.x-scenario: 2}
instances:
- {finagle-6.44.x-scenario: 1}
operationNames:
- finagle-6.44.x-scenario: [hello, /finagle-6.44.x-scenario/case/finagle]
heartbeat: []
segmentItems:
- serviceName: finagle-6.44.x-scenario
segmentSize: gt 2
segments:
- segmentId: not null
spans:
- operationName: hello
operationId: 0
parentSpanId: -1
spanId: 0
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 85
componentName: ''
isError: false
spanType: Entry
peer: ''
peerId: 0
refs:
- {parentEndpointId: 0, parentEndpoint: /finagle-6.44.x-scenario/case/finagle, networkAddressId: 0,
entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not null,
parentServiceInstanceId: 1, networkAddress: '127.0.0.1:12220', entryEndpoint: /finagle-6.44.x-scenario/case/finagle,
entryServiceInstanceId: 1}
- segmentId: not null
spans:
- operationName: hello
operationId: 0
parentSpanId: 0
spanId: 1
spanLayer: RPCFramework
startTime: nq 0
endTime: nq 0
componentId: 85
componentName: ''
isError: false
spanType: Exit
peer: 127.0.0.1:12220
peerId: 0
- operationName: /finagle-6.44.x-scenario/case/finagle
operationId: 0
parentSpanId: -1
spanId: 0
spanLayer: Http
startTime: nq 0
endTime: nq 0
componentId: 1
componentName: ''
isError: false
spanType: Entry
peer: ''
peerId: 0
tags:
- {key: url, value: 'http://localhost:8080/finagle-6.44.x-scenario/case/finagle'}
- {key: http.method, value: GET}

View File

@ -0,0 +1,23 @@
# 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.
type: jvm
entryService: http://localhost:8080/finagle-6.44.x-scenario/case/finagle
healthCheck: http://localhost:8080/finagle-6.44.x-scenario/case/healthCheck
startScript: ./bin/startup.sh
framework: finagle-6.44.x-scenario
environment:
dependencies:

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<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">
<groupId>org.apache.skywalking.apm.testcase</groupId>
<artifactId>finagle-6.44.x-scenario</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<compiler.version>1.8</compiler.version>
<test.framework.version>6.41.0</test.framework.version>
<spring-boot-version>2.1.6.RELEASE</spring-boot-version>
<lombok.version>1.18.10</lombok.version>
</properties>
<name>skywalking-finagle-6.44.x-scenario</name>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-core_2.11</artifactId>
<version>${test.framework.version}</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>finagle-thrift_2.11</artifactId>
<version>${test.framework.version}</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>scrooge-core_2.11</artifactId>
<version>4.20.0</version>
</dependency>
</dependencies>
<build>
<finalName>finagle-6.44.x-scenario</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${compiler.version}</source>
<target>${compiler.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
<outputDirectory>./target/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.twitter</groupId>
<artifactId>scrooge-maven-plugin</artifactId>
<version>4.20.0</version>
<configuration>
<language>java</language>
<thriftOpts>
<thriftOpt>--finagle</thriftOpt>
</thriftOpts>
<buildExtractedThrift>false</buildExtractedThrift>
</configuration>
<executions>
<execution>
<id>generate-thrift-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>thrift-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ 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.
~
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>./bin</directory>
<fileMode>0775</fileMode>
</fileSet>
</fileSets>
<files>
<file>
<source>${project.build.directory}/finagle-6.44.x-scenario.jar</source>
<outputDirectory>./libs</outputDirectory>
<fileMode>0775</fileMode>
</file>
</files>
</assembly>

View File

@ -0,0 +1,55 @@
/*
* 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.testcase.finagle;
import com.twitter.finagle.ListeningServer;
import com.twitter.finagle.Thrift;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
import org.apache.skywalking.apm.testcase.finagle.service.FinagleRpcDemoServiceImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
public class FinagleRpcApplication {
public static void main(String[] args) {
SpringApplication.run(FinagleRpcApplication.class, args);
}
@Configuration
public static class FinagleRpcConfiguration {
@Bean(destroyMethod = "close")
public ListeningServer server() {
ListeningServer server = Thrift.server()
.serveIface(":12220", new FinagleRpcDemoServiceImpl());
return server;
}
@Bean
public FinagleRpcDemoService.ServiceIface client() {
return Thrift.client()
.newIface("localhost:12220", FinagleRpcDemoService.ServiceIface.class);
}
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.testcase.finagle.controller;
import com.twitter.util.Await;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/case")
public class CaseController {
private static final String SUCCESS = "Success";
@Autowired
private FinagleRpcDemoService.ServiceIface finagleRpcDemoService;
@RequestMapping("/healthCheck")
@ResponseBody
public String healthCheck() {
return SUCCESS;
}
@RequestMapping("/finagle")
@ResponseBody
public String finagle() throws Exception {
System.out.println(Await.result(finagleRpcDemoService.hello("finagle")));
return SUCCESS;
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.testcase.finagle.service;
import com.twitter.util.Future;
import org.apache.skywalking.apm.testcase.finagle.interfaces.FinagleRpcDemoService;
public class FinagleRpcDemoServiceImpl implements FinagleRpcDemoService.ServiceIface {
public Future<String> hello(String name) {
return Future.value("hello, " + name);
}
}

View File

@ -0,0 +1,21 @@
#
# 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.
#
#
server:
port: 8080
servlet:
context-path: /finagle-6.44.x-scenario

View File

@ -0,0 +1,23 @@
/*
* 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.
*
*/
namespace java org.apache.skywalking.apm.testcase.finagle.interfaces
service FinagleRpcDemoService {
string hello(string name);
}

View File

@ -0,0 +1,20 @@
# 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
# "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.
6.44.0
6.45.0
7.0.0
7.1.0