This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new 9795080  Enhance gRPC plugin (#4177)
9795080 is described below

commit 97950807fafb503a0b083cd035f42e4f6e7c9ac5
Author: Kanro <[email protected]>
AuthorDate: Thu Jan 30 20:12:48 2020 +0800

    Enhance gRPC plugin (#4177)
    
    * Enhance gRPC plugin
    
    Co-authored-by: Kanro <[email protected]>
    Co-authored-by: kezhenxu94 <[email protected]>
    Co-authored-by: GuoDuanLZ <[email protected]>
    Co-authored-by: 吴晟 Wu Sheng <[email protected]>
---
 .../v1/AsyncUnaryRequestCallCallInterceptor.java   |  59 --
 .../grpc/v1/BlockingCallClientInterceptor.java     |  63 --
 .../apm/plugin/grpc/v1/CallServerInterceptor.java  | 150 ----
 .../skywalking/apm/plugin/grpc/v1/Constants.java   |  47 +-
 .../apm/plugin/grpc/v1/GRPCClientInterceptor.java  |  45 --
 .../plugin/grpc/v1/OperationNameFormatUtil.java    |   2 +-
 .../grpc/v1/StreamCallClientInterceptor.java       | 141 ----
 .../v1/{ => client}/AbstractStubInterceptor.java   |  20 +-
 .../v1/{ => client}/BlockingCallInterceptor.java   |  27 +-
 .../ClientInterceptor.java}                        |  18 +-
 .../plugin/grpc/v1/client/TracingClientCall.java   | 203 ++++++
 .../AbstractServerImplBuilderInstrumentation.java  |   2 +-
 .../v1/define/AbstractStubInstrumentation.java     |   2 +-
 .../grpc/v1/define/ClientCallsInstrumentation.java |  30 +-
 .../AbstractServerImplBuilderInterceptor.java      |  17 +-
 .../plugin/grpc/v1/server/ServerInterceptor.java   |  58 ++
 .../plugin/grpc/v1/server/TracingServerCall.java   | 112 +++
 .../grpc/v1/server/TracingServerCallListener.java  | 104 +++
 .../grpc-scenario/config/expectedData.yaml         | 776 +++++++++++++++------
 .../testcase/grpc/controller/CaseController.java   |  13 +-
 .../grpc/provider/ProviderConfiguration.java       |   8 +-
 .../service/GreeterBlockingErrorServiceImpl.java}  |  28 +-
 .../grpc/provider/service/GreeterServiceImpl.java  |   1 +
 .../src/main/proto/GreetService.proto              |   4 +
 24 files changed, 1139 insertions(+), 791 deletions(-)

diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AsyncUnaryRequestCallCallInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AsyncUnaryRequestCallCallInterceptor.java
deleted file mode 100644
index 9cd51d4..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AsyncUnaryRequestCallCallInterceptor.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.grpc.v1;
-
-import io.grpc.Channel;
-import io.grpc.MethodDescriptor;
-import java.lang.reflect.Method;
-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.MethodInterceptResult;
-import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
-import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
-
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil.formatOperationName;
-
-/**
- * @author zhang xin
- */
-public class AsyncUnaryRequestCallCallInterceptor implements 
StaticMethodsAroundInterceptor {
-    @Override public void beforeMethod(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
-        MethodInterceptResult result) {
-        CallClientInterceptor originClientCall = 
(CallClientInterceptor)allArguments[0];
-        Channel channel = originClientCall.getChannel();
-        MethodDescriptor methodDescriptor = 
originClientCall.getMethodDescriptor();
-
-        final AbstractSpan span = 
ContextManager.createExitSpan(formatOperationName(methodDescriptor), 
channel.authority());
-        span.setComponent(ComponentsDefine.GRPC);
-        SpanLayer.asRPCFramework(span);
-    }
-
-    @Override public Object afterMethod(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
-        Object ret) {
-        ContextManager.stopSpan();
-        return ret;
-    }
-
-    @Override
-    public void handleMethodException(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
-        Throwable t) {
-        ContextManager.activeSpan().errorOccurred().log(t);
-    }
-}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/BlockingCallClientInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/BlockingCallClientInterceptor.java
deleted file mode 100644
index 98f25de..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/BlockingCallClientInterceptor.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.grpc.v1;
-
-import io.grpc.Channel;
-import io.grpc.ClientCall;
-import io.grpc.ForwardingClientCall;
-import io.grpc.Metadata;
-import io.grpc.MethodDescriptor;
-import org.apache.skywalking.apm.agent.core.context.CarrierItem;
-import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-
-/**
- * @author zhang xin
- */
-public class BlockingCallClientInterceptor extends 
ForwardingClientCall.SimpleForwardingClientCall implements 
CallClientInterceptor {
-
-    private final MethodDescriptor methodDescriptor;
-    private final Channel channel;
-
-    public BlockingCallClientInterceptor(ClientCall delegate, MethodDescriptor 
method, Channel channel) {
-        super(delegate);
-        this.methodDescriptor = method;
-        this.channel = channel;
-    }
-
-    @Override public void start(Listener responseListener, Metadata headers) {
-        final ContextCarrier contextCarrier = new ContextCarrier();
-        ContextManager.inject(contextCarrier);
-        CarrierItem contextItem = contextCarrier.items();
-        while (contextItem.hasNext()) {
-            contextItem = contextItem.next();
-            Metadata.Key<String> headerKey = 
Metadata.Key.of(contextItem.getHeadKey(), Metadata.ASCII_STRING_MARSHALLER);
-            headers.put(headerKey, contextItem.getHeadValue());
-        }
-        delegate().start(responseListener, headers);
-    }
-
-    public MethodDescriptor getMethodDescriptor() {
-        return methodDescriptor;
-    }
-
-    public Channel getChannel() {
-        return channel;
-    }
-}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/CallServerInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/CallServerInterceptor.java
deleted file mode 100644
index f8045c4..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/CallServerInterceptor.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.grpc.v1;
-
-import io.grpc.ForwardingServerCall;
-import io.grpc.ForwardingServerCallListener;
-import io.grpc.Metadata;
-import io.grpc.MethodDescriptor;
-import io.grpc.ServerCall;
-import io.grpc.ServerCallHandler;
-import io.grpc.ServerInterceptor;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.skywalking.apm.agent.core.context.CarrierItem;
-import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
-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.network.trace.component.ComponentsDefine;
-import org.apache.skywalking.apm.util.StringUtil;
-
-import static org.apache.skywalking.apm.plugin.grpc.v1.Constants.SERVER;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.STREAM_REQUEST_OBSERVER_ON_COMPLETE_OPERATION_NAME;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.STREAM_REQUEST_OBSERVER_ON_ERROR_OPERATION_NAME;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.STREAM_REQUEST_OBSERVER_ON_NEXT_OPERATION_NAME;
-
-/**
- * @author zhang xin
- */
-public class CallServerInterceptor implements ServerInterceptor {
-    @Override
-    public ServerCall.Listener interceptCall(ServerCall call, Metadata 
headers, ServerCallHandler handler) {
-        Map<String, String> headerMap = new HashMap<String, String>();
-        for (String key : headers.keys()) {
-            if (!key.endsWith(Metadata.BINARY_HEADER_SUFFIX)) {
-                String value = headers.get(Metadata.Key.of(key, 
Metadata.ASCII_STRING_MARSHALLER));
-                headerMap.put(key, value);
-            }
-        }
-
-        ContextCarrier contextCarrier = new ContextCarrier();
-        CarrierItem next = contextCarrier.items();
-        while (next.hasNext()) {
-            next = next.next();
-            String contextValue = headerMap.get(next.getHeadKey());
-            if (!StringUtil.isEmpty(contextValue)) {
-                next.setHeadValue(contextValue);
-            }
-        }
-
-        final AbstractSpan span = 
ContextManager.createEntrySpan(OperationNameFormatUtil.formatOperationName(call.getMethodDescriptor()),
 contextCarrier);
-        span.setComponent(ComponentsDefine.GRPC);
-        SpanLayer.asRPCFramework(span);
-        try {
-            return new ServerCallListener(handler.startCall(new 
ForwardingServerCall.SimpleForwardingServerCall(call) {
-                @Override
-                public void sendHeaders(Metadata responseHeaders) {
-                    delegate().sendHeaders(responseHeaders);
-                }
-            }, headers), call.getMethodDescriptor(), ContextManager.capture());
-        } finally {
-            ContextManager.stopSpan();
-        }
-    }
-
-    public class ServerCallListener extends 
ForwardingServerCallListener.SimpleForwardingServerCallListener {
-
-        private final ContextSnapshot contextSnapshot;
-        private final MethodDescriptor.MethodType methodType;
-        private final String operationPrefix;
-
-        protected ServerCallListener(ServerCall.Listener delegate, 
MethodDescriptor descriptor,
-            ContextSnapshot contextSnapshot) {
-            super(delegate);
-            this.contextSnapshot = contextSnapshot;
-            this.methodType = descriptor.getType();
-            this.operationPrefix = 
OperationNameFormatUtil.formatOperationName(descriptor) + SERVER;
-        }
-
-        @Override public void onReady() {
-            delegate().onReady();
-        }
-
-        @Override public void onMessage(Object message) {
-            try {
-                ContextManager.createLocalSpan(operationPrefix + 
STREAM_REQUEST_OBSERVER_ON_NEXT_OPERATION_NAME);
-                ContextManager.continued(contextSnapshot);
-                delegate().onMessage(message);
-            } catch (Throwable t) {
-                ContextManager.activeSpan().errorOccurred().log(t);
-            } finally {
-                ContextManager.stopSpan();
-            }
-        }
-
-        @Override public void onComplete() {
-            if (methodType != MethodDescriptor.MethodType.UNARY) {
-                try {
-                    ContextManager.createLocalSpan(operationPrefix + 
STREAM_REQUEST_OBSERVER_ON_COMPLETE_OPERATION_NAME);
-                    ContextManager.continued(contextSnapshot);
-                    delegate().onComplete();
-                } catch (Throwable t) {
-                    ContextManager.activeSpan().errorOccurred().log(t);
-                } finally {
-                    ContextManager.stopSpan();
-                }
-            } else {
-                delegate().onComplete();
-            }
-        }
-
-        @Override public void onCancel() {
-            if (methodType != MethodDescriptor.MethodType.UNARY) {
-                try {
-                    ContextManager.createLocalSpan(operationPrefix + 
STREAM_REQUEST_OBSERVER_ON_ERROR_OPERATION_NAME);
-                    ContextManager.continued(contextSnapshot);
-                    delegate().onCancel();
-                } catch (Throwable t) {
-                    ContextManager.activeSpan().errorOccurred().log(t);
-                } finally {
-                    ContextManager.stopSpan();
-                }
-            } else {
-                delegate().onCancel();
-            }
-        }
-
-        @Override public void onHalfClose() {
-            delegate().onHalfClose();
-        }
-    }
-
-}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/Constants.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/Constants.java
index a034590..f46ce28 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/Constants.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/Constants.java
@@ -21,23 +21,52 @@ package org.apache.skywalking.apm.plugin.grpc.v1;
 /**
  * Constant variables
  *
- * @author zhang xin
+ * @author zhang xin, wang zheng, kanro
  */
 public class Constants {
+
+    /**
+     * Mark the current application is the gRPC client in current tracing span.
+     */
     public static final String CLIENT = "/client";
 
+    /**
+     * Mark the current application is the gRPC server in current tracing span.
+     */
     public static final String SERVER = "/server";
 
-    public static final String STREAM_REQUEST_OBSERVER_ON_NEXT_OPERATION_NAME 
= "/RequestObserver/onNext";
-
-    public static final String STREAM_REQUEST_OBSERVER_ON_ERROR_OPERATION_NAME 
= "/RequestObserver/onError";
+    /**
+     * Operation name for request message received on server or sent on client.
+     *
+     * Spans of this operations just be create with request stream calls.
+     */
+    public static final String REQUEST_ON_MESSAGE_OPERATION_NAME = 
"/Request/onMessage";
 
-    public static final String 
STREAM_REQUEST_OBSERVER_ON_COMPLETE_OPERATION_NAME = 
"/RequestObserver/onComplete";
+    /**
+     * Operation name for client has completed request sending, there are no 
more incoming request.
+     *
+     * It should happen with half close state usually.
+     */
+    public static final String REQUEST_ON_COMPLETE_OPERATION_NAME = 
"/Request/onComplete";
 
-    public static final String STREAM_RESPONSE_OBSERVER_ON_NEXT_OPERATION_NAME 
= "/ResponseObserver/onNext";
+    /**
+     * Operation name for client has cancelled the call.
+     */
+    public static final String REQUEST_ON_CANCEL_OPERATION_NAME = 
"/Request/onCancel";
 
-    public static final String 
STREAM_RESPONSE_OBSERVER_ON_ERROR_OPERATION_NAME = "/ResponseObserver/onError";
+    /**
+     * Operation name for response message received on client or sent on 
server.
+     *
+     * Spans of this operations just be create with response stream calls.
+     */
+    public static final String RESPONSE_ON_MESSAGE_OPERATION_NAME = 
"/Response/onMessage";
 
-    public static final String 
STREAM_RESPONSE_OBSERVER_ON_COMPLETE_OPERATION_NAME = 
"/ResponseObserver/onComplete";
+    /**
+     * Operation name for call closed with status and trailers.
+     *
+     * Exceptions will be logs here.
+     */
+    public static final String RESPONSE_ON_CLOSE_OPERATION_NAME = 
"/Response/onClose";
 
-}
+    public static final String BLOCKING_CALL_EXIT_SPAN = 
"SW_GRPC_BLOCKING_CALL_EXIT_SPAN";
+}
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/GRPCClientInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/GRPCClientInterceptor.java
deleted file mode 100644
index 29e0f04..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/GRPCClientInterceptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.grpc.v1;
-
-import io.grpc.CallOptions;
-import io.grpc.Channel;
-import io.grpc.ClientCall;
-import io.grpc.ClientInterceptor;
-import io.grpc.MethodDescriptor;
-
-/**
- * {@link GRPCClientInterceptor} determines the returned Interceptor based on 
the method type. If the method type is
- * UNARY, {@link GRPCClientInterceptor} returns BlockingCallClientInterceptor, 
or it returns
- * StreamCallClientInterceptor.
- *
- * @author zhang xin
- */
-public class GRPCClientInterceptor implements ClientInterceptor {
-
-    @Override
-    public ClientCall interceptCall(MethodDescriptor method,
-        CallOptions callOptions, Channel channel) {
-        if (method.getType() != MethodDescriptor.MethodType.UNARY) {
-            return new StreamCallClientInterceptor(channel.newCall(method, 
callOptions), method, channel);
-        }
-        return new BlockingCallClientInterceptor(channel.newCall(method, 
callOptions), method, channel);
-    }
-
-}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/OperationNameFormatUtil.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/OperationNameFormatUtil.java
index e5fa97e..245d6b3 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/OperationNameFormatUtil.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/OperationNameFormatUtil.java
@@ -27,7 +27,7 @@ import io.grpc.MethodDescriptor;
  */
 public class OperationNameFormatUtil {
 
-    public static String formatOperationName(MethodDescriptor 
methodDescriptor) {
+    public static String formatOperationName(MethodDescriptor<?, ?> 
methodDescriptor) {
         String fullMethodName = methodDescriptor.getFullMethodName();
         return formatServiceName(fullMethodName) + "." + 
formatMethodName(fullMethodName);
     }
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/StreamCallClientInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/StreamCallClientInterceptor.java
deleted file mode 100644
index 57cdadb..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/StreamCallClientInterceptor.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.grpc.v1;
-
-import io.grpc.Channel;
-import io.grpc.ClientCall;
-import io.grpc.ForwardingClientCall;
-import io.grpc.ForwardingClientCallListener;
-import io.grpc.Metadata;
-import io.grpc.MethodDescriptor;
-import io.grpc.Status;
-import org.apache.skywalking.apm.agent.core.context.CarrierItem;
-import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
-import org.apache.skywalking.apm.agent.core.context.tag.Tags;
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
-import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
-import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
-
-import static org.apache.skywalking.apm.plugin.grpc.v1.Constants.CLIENT;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.STREAM_RESPONSE_OBSERVER_ON_COMPLETE_OPERATION_NAME;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.STREAM_RESPONSE_OBSERVER_ON_ERROR_OPERATION_NAME;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.STREAM_RESPONSE_OBSERVER_ON_NEXT_OPERATION_NAME;
-import static 
org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil.formatOperationName;
-
-/**
- * @author zhangxin
- */
-public class StreamCallClientInterceptor extends 
ForwardingClientCall.SimpleForwardingClientCall implements 
CallClientInterceptor {
-
-    private final String serviceName;
-    private final String remotePeer;
-    private final String operationPrefix;
-    private final Channel channel;
-    private final MethodDescriptor methodDescriptor;
-
-    protected StreamCallClientInterceptor(ClientCall delegate, 
MethodDescriptor method, Channel channel) {
-        super(delegate);
-        this.channel = channel;
-        this.methodDescriptor = method;
-        this.serviceName = formatOperationName(method);
-        this.remotePeer = channel.authority();
-        this.operationPrefix = 
OperationNameFormatUtil.formatOperationName(method) + CLIENT;
-    }
-
-    @Override
-    public void start(Listener responseListener, Metadata headers) {
-        final ContextCarrier contextCarrier = new ContextCarrier();
-        final AbstractSpan span = ContextManager.createExitSpan(serviceName, 
contextCarrier, remotePeer);
-        span.setComponent(ComponentsDefine.GRPC);
-        SpanLayer.asRPCFramework(span);
-        CarrierItem contextItem = contextCarrier.items();
-        while (contextItem.hasNext()) {
-            contextItem = contextItem.next();
-            Metadata.Key<String> headerKey = 
Metadata.Key.of(contextItem.getHeadKey(), Metadata.ASCII_STRING_MARSHALLER);
-            headers.put(headerKey, contextItem.getHeadValue());
-        }
-        delegate().start(new CallListener(responseListener, 
ContextManager.capture()), headers);
-        ContextManager.stopSpan();
-    }
-
-    @Override
-    public Channel getChannel() {
-        return channel;
-    }
-
-    @Override
-    public MethodDescriptor getMethodDescriptor() {
-        return methodDescriptor;
-    }
-
-    private class CallListener extends 
ForwardingClientCallListener.SimpleForwardingClientCallListener {
-
-        private final ContextSnapshot contextSnapshot;
-
-        protected CallListener(Listener delegate, ContextSnapshot 
contextSnapshot) {
-            super(delegate);
-            this.contextSnapshot = contextSnapshot;
-        }
-
-        @Override
-        public void onReady() {
-            delegate().onReady();
-        }
-
-        @Override
-        public void onHeaders(Metadata headers) {
-            delegate().onHeaders(headers);
-        }
-
-        @Override
-        public void onMessage(Object message) {
-            try {
-                ContextManager.createLocalSpan(operationPrefix + 
STREAM_RESPONSE_OBSERVER_ON_NEXT_OPERATION_NAME);
-                ContextManager.continued(contextSnapshot);
-                delegate().onMessage(message);
-            } catch (Throwable t) {
-                ContextManager.activeSpan().errorOccurred().log(t);
-            } finally {
-                ContextManager.stopSpan();
-            }
-        }
-
-        @Override
-        public void onClose(Status status, Metadata trailers) {
-            try {
-                if (!status.isOk()) {
-                    AbstractSpan abstractSpan = 
ContextManager.createLocalSpan(operationPrefix + 
STREAM_RESPONSE_OBSERVER_ON_ERROR_OPERATION_NAME);
-                    
abstractSpan.errorOccurred().log(status.asRuntimeException());
-                    Tags.STATUS_CODE.set(abstractSpan, 
status.getCode().name());
-                } else {
-                    AbstractSpan abstractSpan = 
ContextManager.createLocalSpan(operationPrefix + 
STREAM_RESPONSE_OBSERVER_ON_COMPLETE_OPERATION_NAME);
-                }
-                delegate().onClose(status, trailers);
-                ContextManager.continued(contextSnapshot);
-            } catch (Throwable t) {
-                ContextManager.activeSpan().errorOccurred().log(t);
-            } finally {
-                ContextManager.stopSpan();
-            }
-        }
-    }
-
-}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AbstractStubInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/AbstractStubInterceptor.java
similarity index 79%
rename from 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AbstractStubInterceptor.java
rename to 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/AbstractStubInterceptor.java
index fb6edd9..ebc2df0 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AbstractStubInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/AbstractStubInterceptor.java
@@ -16,40 +16,42 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.grpc.v1;
+package org.apache.skywalking.apm.plugin.grpc.v1.client;
 
 import io.grpc.Channel;
 import io.grpc.ClientInterceptors;
-import java.lang.reflect.Method;
 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;
+
 /**
  * {@link AbstractStubInterceptor} add the interceptor for every ClientCall.
  *
- * @author zhang xin
+ * @author zhang xin, kanro
  */
 public class AbstractStubInterceptor implements 
InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
     @Override
     public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
-        Channel channel = (Channel)allArguments[0];
-        
objInst.setSkyWalkingDynamicField(ClientInterceptors.intercept(channel, new 
GRPCClientInterceptor()));
+        Channel channel = (Channel) allArguments[0];
+        
objInst.setSkyWalkingDynamicField(ClientInterceptors.intercept(channel, new 
ClientInterceptor()));
     }
 
     @Override
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
-        MethodInterceptResult result) throws Throwable {
+                             MethodInterceptResult result) throws Throwable {
     }
 
     @Override
     public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes,
-        Object ret) throws Throwable {
+                              Object ret) throws Throwable {
         return objInst.getSkyWalkingDynamicField();
     }
 
-    @Override public void handleMethodException(EnhancedInstance objInst, 
Method method, Object[] allArguments,
-        Class<?>[] argumentsTypes, Throwable t) {
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments,
+                                      Class<?>[] argumentsTypes, Throwable t) {
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/BlockingCallInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/BlockingCallInterceptor.java
similarity index 70%
rename from 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/BlockingCallInterceptor.java
rename to 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/BlockingCallInterceptor.java
index abf5d98..890389f 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/BlockingCallInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/BlockingCallInterceptor.java
@@ -16,11 +16,10 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.grpc.v1;
+package org.apache.skywalking.apm.plugin.grpc.v1.client;
 
 import io.grpc.Channel;
 import io.grpc.MethodDescriptor;
-import java.lang.reflect.Method;
 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;
@@ -28,31 +27,37 @@ import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
 import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
 
+import java.lang.reflect.Method;
+
+import static 
org.apache.skywalking.apm.plugin.grpc.v1.Constants.BLOCKING_CALL_EXIT_SPAN;
 import static 
org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil.formatOperationName;
 
 /**
- * @author zhang xin
+ * @author zhang xin, kanro
  */
 public class BlockingCallInterceptor implements StaticMethodsAroundInterceptor 
{
 
-    @Override public void beforeMethod(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
-        MethodInterceptResult result) {
-        Channel channel = (Channel)allArguments[0];
-        MethodDescriptor methodDescriptor = (MethodDescriptor)allArguments[1];
+    @Override
+    public void beforeMethod(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
+                             MethodInterceptResult result) {
+        Channel channel = (Channel) allArguments[0];
+        MethodDescriptor<?, ?> methodDescriptor = (MethodDescriptor<?, ?>) 
allArguments[1];
         final AbstractSpan span = 
ContextManager.createExitSpan(formatOperationName(methodDescriptor), 
channel.authority());
         span.setComponent(ComponentsDefine.GRPC);
-        SpanLayer.asRPCFramework(span);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.getRuntimeContext().put(BLOCKING_CALL_EXIT_SPAN, span);
     }
 
-    @Override public Object afterMethod(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
-        Object ret) {
+    @Override
+    public Object afterMethod(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
+                              Object ret) {
         ContextManager.stopSpan();
         return ret;
     }
 
     @Override
     public void handleMethodException(Class clazz, Method method, Object[] 
allArguments, Class<?>[] parameterTypes,
-        Throwable t) {
+                                      Throwable t) {
         ContextManager.activeSpan().errorOccurred().log(t);
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/CallClientInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/ClientInterceptor.java
similarity index 60%
rename from 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/CallClientInterceptor.java
rename to 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/ClientInterceptor.java
index 2910817..21f31d7 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/CallClientInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/ClientInterceptor.java
@@ -16,19 +16,21 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.grpc.v1;
+package org.apache.skywalking.apm.plugin.grpc.v1.client;
 
+import io.grpc.CallOptions;
 import io.grpc.Channel;
+import io.grpc.ClientCall;
 import io.grpc.MethodDescriptor;
 
 /**
- * @author AI
- * 2019-07-22
+ * @author zhang xin, kanro
  */
-public interface CallClientInterceptor {
-
-    public Channel getChannel();
-
-    public MethodDescriptor getMethodDescriptor();
+public class ClientInterceptor implements io.grpc.ClientInterceptor {
 
+    @Override
+    public <REQUEST, RESPONSE> ClientCall<REQUEST, RESPONSE> 
interceptCall(MethodDescriptor<REQUEST, RESPONSE> method,
+                                                                           
CallOptions callOptions, Channel channel) {
+        return new TracingClientCall<>(channel.newCall(method, callOptions), 
method, channel);
+    }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/TracingClientCall.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/TracingClientCall.java
new file mode 100644
index 0000000..dde2198
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/client/TracingClientCall.java
@@ -0,0 +1,203 @@
+/*
+ * 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.grpc.v1.client;
+
+import io.grpc.*;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil;
+
+import javax.annotation.Nullable;
+
+import static org.apache.skywalking.apm.plugin.grpc.v1.Constants.*;
+import static 
org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil.formatOperationName;
+
+/**
+ * Fully client tracing for gRPC servers.
+ *
+ * @author zhang xin, kanro
+ */
+class TracingClientCall<REQUEST, RESPONSE> extends 
ForwardingClientCall.SimpleForwardingClientCall<REQUEST, RESPONSE> {
+
+    private final String serviceName;
+    private final String remotePeer;
+    private final String operationPrefix;
+    private final MethodDescriptor<REQUEST, RESPONSE> methodDescriptor;
+    private ContextSnapshot snapshot;
+
+    TracingClientCall(ClientCall<REQUEST, RESPONSE> delegate, 
MethodDescriptor<REQUEST, RESPONSE> method, Channel channel) {
+        super(delegate);
+
+        this.methodDescriptor = method;
+        this.serviceName = formatOperationName(method);
+        this.remotePeer = channel.authority();
+        this.operationPrefix = 
OperationNameFormatUtil.formatOperationName(method) + CLIENT;
+    }
+
+    @Override
+    public void start(Listener<RESPONSE> responseListener, Metadata headers) {
+        final AbstractSpan blockingSpan = (AbstractSpan) 
ContextManager.getRuntimeContext().get(BLOCKING_CALL_EXIT_SPAN);
+        final ContextCarrier contextCarrier = new ContextCarrier();
+
+        // Avoid create ExitSpan repeatedly, ExitSpan of blocking calls will 
create by BlockingCallInterceptor.
+        if (blockingSpan == null) {
+            final AbstractSpan span = 
ContextManager.createExitSpan(serviceName, remotePeer);
+            span.setComponent(ComponentsDefine.GRPC);
+            span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        } else {
+            ContextManager.getRuntimeContext().remove(BLOCKING_CALL_EXIT_SPAN);
+        }
+
+        ContextManager.inject(contextCarrier);
+        CarrierItem contextItem = contextCarrier.items();
+        while (contextItem.hasNext()) {
+            contextItem = contextItem.next();
+            Metadata.Key<String> headerKey = 
Metadata.Key.of(contextItem.getHeadKey(), Metadata.ASCII_STRING_MARSHALLER);
+            headers.put(headerKey, contextItem.getHeadValue());
+        }
+
+        snapshot = ContextManager.capture();
+        try {
+            delegate().start(new TracingClientCallListener(responseListener, 
snapshot), headers);
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            if (blockingSpan == null) {
+                ContextManager.stopSpan();
+            }
+        }
+    }
+
+    @Override
+    public void sendMessage(REQUEST message) {
+        if (methodDescriptor.getType().clientSendsOneMessage()) {
+            super.sendMessage(message);
+            return;
+        }
+
+        final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
REQUEST_ON_MESSAGE_OPERATION_NAME);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.continued(snapshot);
+
+        try {
+            super.sendMessage(message);
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+
+    @Override
+    public void halfClose() {
+        final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
REQUEST_ON_COMPLETE_OPERATION_NAME);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.continued(snapshot);
+
+        try {
+            super.halfClose();
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+
+    @Override
+    public void cancel(@Nullable String message, @Nullable Throwable cause) {
+        final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
REQUEST_ON_CANCEL_OPERATION_NAME);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.continued(snapshot);
+
+        if (cause != null) {
+            span.log(cause);
+        }
+
+        try {
+            super.cancel(message, cause);
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+
+    class TracingClientCallListener extends 
ForwardingClientCallListener.SimpleForwardingClientCallListener<RESPONSE> {
+        private final ContextSnapshot contextSnapshot;
+
+        TracingClientCallListener(Listener<RESPONSE> delegate, ContextSnapshot 
contextSnapshot) {
+            super(delegate);
+            this.contextSnapshot = contextSnapshot;
+        }
+
+        @Override
+        public void onMessage(RESPONSE message) {
+            if (methodDescriptor.getType().serverSendsOneMessage()) {
+                super.onMessage(message);
+                return;
+            }
+
+            final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
RESPONSE_ON_MESSAGE_OPERATION_NAME);
+            span.setComponent(ComponentsDefine.GRPC);
+            span.setLayer(SpanLayer.RPC_FRAMEWORK);
+            ContextManager.continued(contextSnapshot);
+
+            try {
+                delegate().onMessage(message);
+            } catch (Throwable t) {
+                ContextManager.activeSpan().errorOccurred().log(t);
+            } finally {
+                ContextManager.stopSpan();
+            }
+        }
+
+        @Override
+        public void onClose(Status status, Metadata trailers) {
+            final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
RESPONSE_ON_CLOSE_OPERATION_NAME);
+            span.setComponent(ComponentsDefine.GRPC);
+            span.setLayer(SpanLayer.RPC_FRAMEWORK);
+            ContextManager.continued(contextSnapshot);
+            if (!status.isOk()) {
+                span.errorOccurred().log(status.asRuntimeException());
+                Tags.STATUS_CODE.set(span, status.getCode().name());
+            }
+
+            try {
+                delegate().onClose(status, trailers);
+            } catch (Throwable t) {
+                ContextManager.activeSpan().errorOccurred().log(t);
+            } finally {
+                ContextManager.stopSpan();
+            }
+        }
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractServerImplBuilderInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractServerImplBuilderInstrumentation.java
index fe75cc8..d57b09b 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractServerImplBuilderInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractServerImplBuilderInstrumentation.java
@@ -33,7 +33,7 @@ public class AbstractServerImplBuilderInstrumentation extends 
ClassInstanceMetho
 
     public static final String ENHANCE_CLASS = 
"io.grpc.internal.AbstractServerImplBuilder";
     public static final String ENHANCE_METHOD = "addService";
-    public static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.AbstractServerImplBuilderInterceptor";
+    public static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.server.AbstractServerImplBuilderInterceptor";
     public static final String ARGUMENT_TYPE = 
"io.grpc.ServerServiceDefinition";
 
     @Override public ConstructorInterceptPoint[] 
getConstructorsInterceptPoints() {
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractStubInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractStubInstrumentation.java
index 54bab22..db34681 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractStubInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/AbstractStubInstrumentation.java
@@ -31,7 +31,7 @@ import static 
org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName
 
 public class AbstractStubInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
 
-    public static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.AbstractStubInterceptor";
+    public static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.client.AbstractStubInterceptor";
     public static final String ENHANCE_METHOD = "getChannel";
     public static final String ENHANCE_CLASS = "io.grpc.stub.AbstractStub";
 
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/ClientCallsInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/ClientCallsInstrumentation.java
index 07f9814..99beb9c 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/ClientCallsInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/define/ClientCallsInstrumentation.java
@@ -32,10 +32,8 @@ import static 
org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName
  * @author zhang xin
  */
 public class ClientCallsInstrumentation extends 
ClassStaticMethodsEnhancePluginDefine {
-
     private static final String ENHANCE_CLASS = "io.grpc.stub.ClientCalls";
-    private static final String INTERCEPTOR_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.BlockingCallInterceptor";
-    private static final String FUTURE_INTERCEPTOR_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.AsyncUnaryRequestCallCallInterceptor";
+    private static final String INTERCEPTOR_CLASS = 
"org.apache.skywalking.apm.plugin.grpc.v1.client.BlockingCallInterceptor";
 
     @Override public StaticMethodsInterceptPoint[] 
getStaticMethodsInterceptPoints() {
         return new StaticMethodsInterceptPoint[] {
@@ -51,32 +49,6 @@ public class ClientCallsInstrumentation extends 
ClassStaticMethodsEnhancePluginD
                 @Override public boolean isOverrideArgs() {
                     return false;
                 }
-            },
-//            new StaticMethodsInterceptPoint() {
-//                @Override public ElementMatcher<MethodDescription> 
getMethodsMatcher() {
-//                    return 
named("blockingServerStreamingCall").and(takesArgumentWithType(1, 
"io.grpc.MethodDescriptor"));
-//                }
-//
-//                @Override public String getMethodsInterceptor() {
-//                    return INTERCEPTOR_CLASS;
-//                }
-//
-//                @Override public boolean isOverrideArgs() {
-//                    return false;
-//                }
-//            },
-            new StaticMethodsInterceptPoint() {
-                @Override public ElementMatcher<MethodDescription> 
getMethodsMatcher() {
-                    return 
named("asyncUnaryRequestCall").and(takesArgumentWithType(2, 
"io.grpc.ClientCall$Listener"));
-                }
-
-                @Override public String getMethodsInterceptor() {
-                    return FUTURE_INTERCEPTOR_CLASS;
-                }
-
-                @Override public boolean isOverrideArgs() {
-                    return true;
-                }
             }
         };
     }
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AbstractServerImplBuilderInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/AbstractServerImplBuilderInterceptor.java
similarity index 76%
rename from 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AbstractServerImplBuilderInterceptor.java
rename to 
apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/AbstractServerImplBuilderInterceptor.java
index 6d5b00e..251217c 100644
--- 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/AbstractServerImplBuilderInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/AbstractServerImplBuilderInterceptor.java
@@ -16,17 +16,19 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.grpc.v1;
+package org.apache.skywalking.apm.plugin.grpc.v1.server;
 
 import io.grpc.ServerInterceptors;
 import io.grpc.ServerServiceDefinition;
+
 import java.lang.reflect.Method;
+
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
 
 /**
- * {@link AbstractServerImplBuilderInterceptor} add the {@link 
CallServerInterceptor} interceptor for every
+ * {@link AbstractServerImplBuilderInterceptor} add the {@link 
ServerInterceptor} interceptor for every
  * ServerService.
  *
  * @author zhang xin
@@ -34,18 +36,19 @@ import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
 public class AbstractServerImplBuilderInterceptor implements 
InstanceMethodsAroundInterceptor {
     @Override
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
-        MethodInterceptResult result) throws Throwable {
-        allArguments[0] = 
ServerInterceptors.intercept((ServerServiceDefinition)allArguments[0], new 
CallServerInterceptor());
+                             MethodInterceptResult result) {
+        allArguments[0] = 
ServerInterceptors.intercept((ServerServiceDefinition) allArguments[0], new 
ServerInterceptor());
     }
 
     @Override
     public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes,
-        Object ret) throws Throwable {
+                              Object ret) {
         return ret;
     }
 
-    @Override public void handleMethodException(EnhancedInstance objInst, 
Method method, Object[] allArguments,
-        Class<?>[] argumentsTypes, Throwable t) {
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments,
+                                      Class<?>[] argumentsTypes, Throwable t) {
 
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/ServerInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/ServerInterceptor.java
new file mode 100644
index 0000000..3113fca
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/ServerInterceptor.java
@@ -0,0 +1,58 @@
+/*
+ * 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.grpc.v1.server;
+
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil;
+import org.apache.skywalking.apm.util.StringUtil;
+
+/**
+ * @author zhang xin, wang zheng, kanro
+ */
+public class ServerInterceptor implements io.grpc.ServerInterceptor {
+    @Override
+    public <REQUEST, RESPONSE> ServerCall.Listener<REQUEST> 
interceptCall(ServerCall<REQUEST, RESPONSE> call, Metadata headers, 
ServerCallHandler<REQUEST, RESPONSE> handler) {
+        final ContextCarrier contextCarrier = new ContextCarrier();
+        CarrierItem next = contextCarrier.items();
+        while (next.hasNext()) {
+            next = next.next();
+            String contextValue = 
headers.get(Metadata.Key.of(next.getHeadKey(), 
Metadata.ASCII_STRING_MARSHALLER));
+            if (!StringUtil.isEmpty(contextValue)) {
+                next.setHeadValue(contextValue);
+            }
+        }
+
+        final AbstractSpan span = 
ContextManager.createEntrySpan(OperationNameFormatUtil.formatOperationName(call.getMethodDescriptor()),
 contextCarrier);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        try {
+            return new TracingServerCallListener<>(handler.startCall(new 
TracingServerCall<>(call, ContextManager.capture()), headers), 
call.getMethodDescriptor(), ContextManager.capture());
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/TracingServerCall.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/TracingServerCall.java
new file mode 100644
index 0000000..48572bf
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/TracingServerCall.java
@@ -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.grpc.v1.server;
+
+import io.grpc.ForwardingServerCall;
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.Status;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil;
+
+import static org.apache.skywalking.apm.plugin.grpc.v1.Constants.*;
+
+/**
+ * @author wang zheng, kanro
+ */
+public class TracingServerCall<REQUEST, RESPONSE> extends 
ForwardingServerCall.SimpleForwardingServerCall<REQUEST, RESPONSE> {
+
+    private final String operationPrefix;
+    private final ContextSnapshot contextSnapshot;
+
+    protected TracingServerCall(ServerCall<REQUEST, RESPONSE> delegate, 
ContextSnapshot contextSnapshot) {
+        super(delegate);
+        this.operationPrefix = 
OperationNameFormatUtil.formatOperationName(delegate.getMethodDescriptor()) + 
SERVER;
+        this.contextSnapshot = contextSnapshot;
+    }
+
+    @Override
+    public void sendMessage(RESPONSE message) {
+        // We just create the request on message span for server stream calls.
+        if (!getMethodDescriptor().getType().serverSendsOneMessage()) {
+            final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
RESPONSE_ON_MESSAGE_OPERATION_NAME);
+            span.setComponent(ComponentsDefine.GRPC);
+            span.setLayer(SpanLayer.RPC_FRAMEWORK);
+            ContextManager.continued(contextSnapshot);
+
+            try {
+                super.sendMessage(message);
+            } catch (Throwable t) {
+                ContextManager.activeSpan().errorOccurred().log(t);
+                throw t;
+            } finally {
+                ContextManager.stopSpan();
+            }
+        } else {
+            super.sendMessage(message);
+        }
+    }
+
+    @Override
+    public void close(Status status, Metadata trailers) {
+        final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
RESPONSE_ON_CLOSE_OPERATION_NAME);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.continued(contextSnapshot);
+        switch (status.getCode()) {
+            case OK:
+                break;
+            // UNKNOWN/INTERNAL status code will case error in this span.
+            // Those status code means some unexpected error occurred in 
server.
+            // Similar to 5XX in HTTP status.
+            case UNKNOWN:
+            case INTERNAL:
+                if (status.getCause() == null) {
+                    span.errorOccurred().log(status.asRuntimeException());
+                } else {
+                    span.errorOccurred().log(status.getCause());
+                }
+                break;
+            // Other status code means some predictable error occurred in 
server.
+            // Like PERMISSION_DENIED or UNAUTHENTICATED somethings.
+            // Similar to 4XX in HTTP status.
+            default:
+                // But if the status still has cause exception, we will log it 
too.
+                if (status.getCause() != null) {
+                    span.errorOccurred().log(status.getCause());
+                }
+                break;
+        }
+        Tags.STATUS_CODE.set(span, status.getCode().name());
+
+        try {
+            super.close(status, trailers);
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/TracingServerCallListener.java
 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/TracingServerCallListener.java
new file mode 100644
index 0000000..eaec551
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/grpc-1.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/grpc/v1/server/TracingServerCallListener.java
@@ -0,0 +1,104 @@
+/*
+ * 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.grpc.v1.server;
+
+import io.grpc.ForwardingServerCallListener;
+import io.grpc.MethodDescriptor;
+import io.grpc.ServerCall;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.grpc.v1.OperationNameFormatUtil;
+
+import static org.apache.skywalking.apm.plugin.grpc.v1.Constants.*;
+
+/**
+ * @author wang zheng, kanro
+ */
+public class TracingServerCallListener<REQUEST> extends 
ForwardingServerCallListener.SimpleForwardingServerCallListener<REQUEST> {
+
+    private final ContextSnapshot contextSnapshot;
+    private final MethodDescriptor.MethodType methodType;
+    private final String operationPrefix;
+
+    protected TracingServerCallListener(ServerCall.Listener<REQUEST> delegate, 
MethodDescriptor<REQUEST, ?> descriptor,
+                                        ContextSnapshot contextSnapshot) {
+        super(delegate);
+        this.contextSnapshot = contextSnapshot;
+        this.methodType = descriptor.getType();
+        this.operationPrefix = 
OperationNameFormatUtil.formatOperationName(descriptor) + SERVER;
+    }
+
+    @Override
+    public void onMessage(REQUEST message) {
+        // We just create the request on message span for client stream calls.
+        if (!methodType.clientSendsOneMessage()) {
+            final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
REQUEST_ON_MESSAGE_OPERATION_NAME);
+            span.setComponent(ComponentsDefine.GRPC);
+            span.setLayer(SpanLayer.RPC_FRAMEWORK);
+            ContextManager.continued(contextSnapshot);
+            try {
+                super.onMessage(message);
+            } catch (Throwable t) {
+                ContextManager.activeSpan().errorOccurred().log(t);
+                throw t;
+            } finally {
+                ContextManager.stopSpan();
+            }
+        } else {
+            super.onMessage(message);
+        }
+    }
+
+    @Override
+    public void onCancel() {
+        final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
REQUEST_ON_CANCEL_OPERATION_NAME);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.continued(contextSnapshot);
+
+        try {
+            super.onCancel();
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+
+    @Override
+    public void onHalfClose() {
+        final AbstractSpan span = 
ContextManager.createLocalSpan(operationPrefix + 
REQUEST_ON_COMPLETE_OPERATION_NAME);
+        span.setComponent(ComponentsDefine.GRPC);
+        span.setLayer(SpanLayer.RPC_FRAMEWORK);
+        ContextManager.continued(contextSnapshot);
+
+        try {
+            super.onHalfClose();
+        } catch (Throwable t) {
+            ContextManager.activeSpan().errorOccurred().log(t);
+            throw t;
+        } finally {
+            ContextManager.stopSpan();
+        }
+    }
+}
diff --git a/test/plugin/scenarios/grpc-scenario/config/expectedData.yaml 
b/test/plugin/scenarios/grpc-scenario/config/expectedData.yaml
index 51a02e1..b0a870c 100644
--- a/test/plugin/scenarios/grpc-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/grpc-scenario/config/expectedData.yaml
@@ -15,239 +15,551 @@
 # limitations under the License.
 registryItems:
   applications:
-    - {grpc-scenario: 2}
+  - { grpc-scenario: 2 }
   instances:
-    - {grpc-scenario: 1}
+  - { grpc-scenario: 1 }
   operationNames:
-    - grpc-scenario: [Greeter.sayHello, GreeterBlocking.sayHello,
-                      /grpc-scenario/case/grpc-scenario]
+  - grpc-scenario: [Greeter.sayHello, GreeterBlocking.sayHello, 
GreeterBlockingError.sayHello, /grpc-scenario/case/grpc-scenario]
   heartbeat: []
 segmentItems:
-  - applicationCode: grpc-scenario
-    segmentSize: gt 10
-    segments:
-      - segmentId: not null
-        spans:
-          - operationName: GreeterBlocking.sayHello
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: RPCFramework
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 23
-            componentName: ''
-            isError: false
-            spanType: Entry
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossProcess, parentSpanId: 2, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: 
'127.0.0.1:18080', entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: RPCFramework
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 23
-            componentName: ''
-            isError: false
-            spanType: Entry
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: 
'127.0.0.1:18080', entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: 
GreeterBlocking.sayHello/server/RequestObserver/onNext
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: 
GreeterBlocking.sayHello, networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello/server/RequestObserver/onNext
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello/client/ResponseObserver/onNext
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello/client/ResponseObserver/onComplete
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello/server/RequestObserver/onNext
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello/server/RequestObserver/onComplete
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello
-            operationId: 0
-            parentSpanId: 0
-            spanId: 1
-            spanLayer: RPCFramework
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 23
-            componentName: ''
-            isError: false
-            spanType: Exit
-            peer: '127.0.0.1:18080'
-            peerId: 0
-          - operationName: GreeterBlocking.sayHello
-            operationId: 0
-            parentSpanId: 0
-            spanId: 2
-            spanLayer: RPCFramework
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 23
-            componentName: ''
-            isError: false
-            spanType: Exit
-            peer: '127.0.0.1:18080'
-            peerId: 0
-          - operationName: /grpc-scenario/case/grpc-scenario
-            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/grpc-scenario/case/grpc-scenario'}
-              - {key: http.method, value: GET}
-      - segmentId: not null
-        spans:
-          - operationName: Greeter.sayHello/client/ResponseObserver/onNext
-            operationId: 0
-            parentSpanId: -1
-            spanId: 0
-            spanLayer: Unknown
-            startTime: nq 0
-            endTime: nq 0
-            componentId: 0
-            componentName: ''
-            isError: false
-            spanType: Local
-            peer: ''
-            peerId: 0
-            refs:
-              - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
-                 entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
-                 parentServiceInstanceId: 1, networkAddress: '', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
-                 entryServiceInstanceId: 1}
-
+- applicationCode: grpc-scenario
+  segmentSize: gt 10
+  segments:
+  - segmentId: not null
+    spans:
+    - operationName: GreeterBlocking.sayHello
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Entry
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossProcess, parentSpanId: 2, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '127.0.0.1:18080', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/client/Request/onMessage
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/client/Request/onMessage
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/client/Request/onComplete
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Entry
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossProcess, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '127.0.0.1:18080', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/server/Response/onMessage
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+    - operationName: Greeter.sayHello/server/Request/onMessage
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/client/Response/onMessage
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: GreeterBlocking.sayHello/server/Response/onClose
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      tags:
+      - { key: status_code, value: OK }
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: GreeterBlocking.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+    - operationName: GreeterBlocking.sayHello/server/Request/onComplete
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: GreeterBlocking.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/server/Response/onMessage
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+    - operationName: Greeter.sayHello/server/Request/onMessage
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/server/Response/onClose
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      tags:
+      - {key: status_code, value: OK}
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+    - operationName: Greeter.sayHello/server/Request/onComplete
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: Greeter.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/client/Response/onMessage
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello/client/Response/onClose
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 1, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: GreeterBlockingError.sayHello
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Entry
+      peer: ''
+      peerId: 0
+      refs:
+        - {parentEndpointId: 0, parentEndpoint: 
/grpc-scenario/case/grpc-scenario, networkAddressId: 0,
+           entryEndpointId: 0, refType: CrossProcess, parentSpanId: 5, 
parentTraceSegmentId: not null,
+           parentServiceInstanceId: 1, networkAddress: '127.0.0.1:18080', 
entryEndpoint: /grpc-scenario/case/grpc-scenario,
+           entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: GreeterBlockingError.sayHello/server/Response/onClose
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: true
+      spanType: Local
+      peer: ''
+      peerId: 0
+      tags:
+      - { key: status_code, value: UNKNOWN }
+      logs:
+      - logEvent:
+        - { key: event, value: error }
+        - { key: error.kind, value: java.lang.Exception }
+        - { key: message, value: '' }
+        - key: stack
+          value: not null
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: GreeterBlockingError.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+    - operationName: GreeterBlockingError.sayHello/server/Request/onComplete
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      refs:
+      - {parentEndpointId: 0, parentEndpoint: GreeterBlockingError.sayHello, 
networkAddressId: 0,
+         entryEndpointId: 0, refType: CrossThread, parentSpanId: 0, 
parentTraceSegmentId: not null,
+         parentServiceInstanceId: 1, networkAddress: '', entryEndpoint: 
/grpc-scenario/case/grpc-scenario,
+         entryServiceInstanceId: 1}
+  - segmentId: not null
+    spans:
+    - operationName: Greeter.sayHello
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Exit
+      peer: '127.0.0.1:18080'
+      peerId: 0
+    - operationName: GreeterBlocking.sayHello/client/Request/onComplete
+      operationId: 0
+      parentSpanId: 2
+      spanId: 3
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+    - operationName: GreeterBlocking.sayHello/client/Response/onClose
+      operationId: 0
+      parentSpanId: 2
+      spanId: 4
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+    - operationName: GreeterBlocking.sayHello
+      operationId: 0
+      parentSpanId: 0
+      spanId: 2
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Exit
+      peer: '127.0.0.1:18080'
+      peerId: 0
+    - operationName: GreeterBlockingError.sayHello/client/Request/onComplete
+      operationId: 0
+      parentSpanId: 5
+      spanId: 6
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+    - operationName: GreeterBlockingError.sayHello/client/Response/onClose
+      operationId: 0
+      parentSpanId: 5
+      spanId: 7
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: true
+      spanType: Local
+      peer: ''
+      peerId: 0
+      tags:
+      - {key: status_code, value: UNKNOWN}
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: io.grpc.StatusRuntimeException}
+        - {key: message, value: UNKNOWN}
+        - key: stack
+          value: not null
+    - operationName: GreeterBlockingError.sayHello/client/Request/onCancel
+      operationId: 0
+      parentSpanId: 5
+      spanId: 8
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: false
+      spanType: Local
+      peer: ''
+      peerId: 0
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: io.grpc.StatusRuntimeException}
+        - {key: message, value: UNKNOWN}
+        - key: stack
+          value: not null
+    - operationName: GreeterBlockingError.sayHello
+      operationId: 0
+      parentSpanId: 0
+      spanId: 5
+      spanLayer: RPCFramework
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 23
+      componentName: ''
+      isError: true
+      spanType: Exit
+      peer: 127.0.0.1:18080
+      peerId: 0
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: io.grpc.StatusRuntimeException}
+        - {key: message, value: UNKNOWN}
+        - key: stack
+          value: not null
+    - operationName: /grpc-scenario/case/grpc-scenario
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: Http
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 1
+      componentName: ''
+      isError: true
+      spanType: Entry
+      peer: ''
+      peerId: 0
+      tags:
+      - {key: url, value: 
'http://localhost:8080/grpc-scenario/case/grpc-scenario'}
+      - {key: http.method, value: GET}
+      - {key: status_code, value: '500'}
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: 
org.springframework.web.util.NestedServletException}
+        - {key: message, value: 'Request processing failed; nested exception 
is io.grpc.StatusRuntimeException: UNKNOWN'}
+        - key: stack
+          value: not null
+      - logEvent:
+        - {key: forward-url, value: /grpc-scenario/error}
diff --git 
a/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/controller/CaseController.java
 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/controller/CaseController.java
index 7579582..708770a 100644
--- 
a/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/controller/CaseController.java
+++ 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/controller/CaseController.java
@@ -26,10 +26,7 @@ import io.grpc.stub.ClientResponseObserver;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.skywalking.apm.testcase.grpc.consumr.ConsumerInterceptor;
-import org.apache.skywalking.apm.testcase.grpc.proto.GreeterBlockingGrpc;
-import org.apache.skywalking.apm.testcase.grpc.proto.GreeterGrpc;
-import org.apache.skywalking.apm.testcase.grpc.proto.HelloReply;
-import org.apache.skywalking.apm.testcase.grpc.proto.HelloRequest;
+import org.apache.skywalking.apm.testcase.grpc.proto.*;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
@@ -52,12 +49,14 @@ public class CaseController {
     private ManagedChannel channel;
     private GreeterGrpc.GreeterStub greeterStub;
     private GreeterBlockingGrpc.GreeterBlockingBlockingStub 
greeterBlockingStub;
+    private GreeterBlockingErrorGrpc.GreeterBlockingErrorBlockingStub 
greeterBlockingErrorStub;
 
     @PostConstruct
     public void up() {
         channel = ManagedChannelBuilder.forAddress(gprcProviderHost, 
grpcProviderPort).usePlaintext(true).build();
         greeterStub = 
GreeterGrpc.newStub(ClientInterceptors.intercept(channel, new 
ConsumerInterceptor()));
         greeterBlockingStub = 
GreeterBlockingGrpc.newBlockingStub(ClientInterceptors.intercept(channel, new 
ConsumerInterceptor()));
+        greeterBlockingErrorStub = 
GreeterBlockingErrorGrpc.newBlockingStub(ClientInterceptors.intercept(channel, 
new ConsumerInterceptor()));
     }
 
     @RequestMapping("/grpc-scenario")
@@ -65,6 +64,7 @@ public class CaseController {
     public String testcase() {
         greetService();
         greetBlockingService();
+        greetBlockingErrorService();
         return SUCCESS;
     }
 
@@ -129,4 +129,9 @@ public class CaseController {
         HelloRequest request = 
HelloRequest.newBuilder().setName("Sophia").build();
         greeterBlockingStub.sayHello(request);
     }
+
+    private void greetBlockingErrorService() {
+        HelloRequest request = 
HelloRequest.newBuilder().setName("Tony").build();
+        greeterBlockingErrorStub.sayHello(request);
+    }
 }
diff --git 
a/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/ProviderConfiguration.java
 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/ProviderConfiguration.java
index 2058f58..672876f 100644
--- 
a/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/ProviderConfiguration.java
+++ 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/ProviderConfiguration.java
@@ -22,6 +22,7 @@ import io.grpc.Server;
 import io.grpc.ServerBuilder;
 import io.grpc.ServerInterceptors;
 import 
org.apache.skywalking.apm.testcase.grpc.provider.interceptor.ProviderInterceptor;
+import 
org.apache.skywalking.apm.testcase.grpc.provider.service.GreeterBlockingErrorServiceImpl;
 import 
org.apache.skywalking.apm.testcase.grpc.provider.service.GreeterBlockingServiceImpl;
 import 
org.apache.skywalking.apm.testcase.grpc.provider.service.GreeterServiceImpl;
 import org.springframework.beans.factory.annotation.Configurable;
@@ -38,8 +39,9 @@ public class ProviderConfiguration {
     @Bean(initMethod = "start", destroyMethod = "shutdown")
     public Server server() {
         return ServerBuilder.forPort(18080)
-            .addService(ServerInterceptors.intercept(new GreeterServiceImpl(), 
new ProviderInterceptor()))
-            .addService(ServerInterceptors.intercept(new 
GreeterBlockingServiceImpl(), new ProviderInterceptor()))
-            .build();
+                .addService(ServerInterceptors.intercept(new 
GreeterServiceImpl(), new ProviderInterceptor()))
+                .addService(ServerInterceptors.intercept(new 
GreeterBlockingServiceImpl(), new ProviderInterceptor()))
+                .addService(ServerInterceptors.intercept(new 
GreeterBlockingErrorServiceImpl(), new ProviderInterceptor()))
+                .build();
     }
 }
diff --git 
a/test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterBlockingErrorServiceImpl.java
similarity index 55%
copy from test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto
copy to 
test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterBlockingErrorServiceImpl.java
index f6c28f7..7b1af58 100644
--- a/test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto
+++ 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterBlockingErrorServiceImpl.java
@@ -15,25 +15,17 @@
  * limitations under the License.
  *
  */
-syntax = "proto3";
+package org.apache.skywalking.apm.testcase.grpc.provider.service;
 
-option java_multiple_files = true;
-option java_package = "org.apache.skywalking.apm.testcase.grpc.proto";
+import io.grpc.stub.StreamObserver;
+import org.apache.skywalking.apm.testcase.grpc.proto.GreeterBlockingErrorGrpc;
+import org.apache.skywalking.apm.testcase.grpc.proto.GreeterBlockingGrpc;
+import org.apache.skywalking.apm.testcase.grpc.proto.HelloReply;
+import org.apache.skywalking.apm.testcase.grpc.proto.HelloRequest;
 
-service Greeter {
-    rpc SayHello (stream HelloRequest) returns (stream HelloReply) {
+public class GreeterBlockingErrorServiceImpl extends 
GreeterBlockingErrorGrpc.GreeterBlockingErrorImplBase {
+    @Override
+    public void sayHello(HelloRequest request, StreamObserver<HelloReply> 
responseObserver) {
+        responseObserver.onError(new Exception());
     }
 }
-
-service GreeterBlocking {
-    rpc SayHello (HelloRequest) returns (HelloReply) {
-    }
-}
-
-message HelloRequest {
-    string name = 1;
-}
-
-message HelloReply {
-    string message = 1;
-}
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterServiceImpl.java
 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterServiceImpl.java
index 00a77f8..1116c47 100644
--- 
a/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterServiceImpl.java
+++ 
b/test/plugin/scenarios/grpc-scenario/src/main/java/org/apache/skywalking/apm/testcase/grpc/provider/service/GreeterServiceImpl.java
@@ -33,6 +33,7 @@ public class GreeterServiceImpl extends 
GreeterGrpc.GreeterImplBase {
     @Override
     public StreamObserver<HelloRequest> sayHello(final 
StreamObserver<HelloReply> responseObserver) {
         StreamObserver<HelloRequest> requestStreamObserver = new 
StreamObserver<HelloRequest>() {
+
             public void onNext(HelloRequest request) {
                 logger.info("Receive an message from client. Message: {}", 
request.getName());
                 
responseObserver.onNext(HelloReply.newBuilder().setMessage("Hi," + 
request.getName()).build());
diff --git 
a/test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto 
b/test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto
index f6c28f7..fd5ba4a 100644
--- a/test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto
+++ b/test/plugin/scenarios/grpc-scenario/src/main/proto/GreetService.proto
@@ -29,6 +29,10 @@ service GreeterBlocking {
     rpc SayHello (HelloRequest) returns (HelloReply) {
     }
 }
+service GreeterBlockingError {
+    rpc SayHello (HelloRequest) returns (HelloReply) {
+    }
+}
 
 message HelloRequest {
     string name = 1;

Reply via email to