You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/03/06 13:07:52 UTC
[skywalking] branch master updated: support http api for upstream
trace. (#4399)
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 aa21765 support http api for upstream trace. (#4399)
aa21765 is described below
commit aa2176562842aba0966524fbc6c2b444e69c285d
Author: Jared Tan <ji...@daocloud.io>
AuthorDate: Fri Mar 6 21:07:39 2020 +0800
support http api for upstream trace. (#4399)
* support http api.
* e2e
Co-authored-by: 吴晟 Wu Sheng <wu...@foxmail.com>
Co-authored-by: kezhenxu94 <ke...@apache.org>
---
.github/workflows/e2e.yaml | 2 +
.gitignore | 1 +
docs/en/protocols/HTTP-API-Protocol.md | 200 +++++++++++
docs/en/protocols/Trace-Data-Protocol-v2.md | 3 +
oap-server/pom.xml | 8 +
.../library/server/jetty/JettyJsonHandler.java | 19 +-
oap-server/server-library/library-util/pom.xml | 12 +
.../oap/server/library/util/ProtoBufJsonUtils.java | 46 +++
.../register/provider/RegisterModuleProvider.java | 11 +
.../v6/rest/ServiceInstancePingServletHandler.java | 111 ++++++
.../ServiceInstanceRegisterServletHandler.java | 152 ++++++++
.../v6/rest/ServiceRegisterServletHandler.java | 92 +++++
.../trace/provider/TraceModuleProvider.java | 25 +-
.../v6/rest/TraceSegmentCollectServletHandler.java | 76 ++++
.../handler/v6/rest/reader/SegmentJsonReader.java | 33 ++
.../handler/v6/rest/reader/StreamJsonReader.java | 25 ++
.../v6/rest/reader/UpstreamSegmentJsonReader.java | 41 +++
.../listener/segment/ProtoBufJsonUtilsTest.java | 139 ++++++++
test/e2e/e2e-http-api-with-nginx-lua/pom.xml | 195 +++++++++++
.../src/docker/rc.d/rc0-prepare.sh | 95 +++++
.../src/docker/rc.d/rc1-startup.sh | 48 +++
.../e2e/sample/client/SampleClientApplication.java | 29 ++
.../e2e/sample/client/TestController.java | 32 ++
.../src/main/resources/application.yml | 22 ++
.../skywalking/e2e/SampleVerificationITCase.java | 386 +++++++++++++++++++++
...king.e2e.SampleVerificationITCase.endpoints.yml | 28 ++
...king.e2e.SampleVerificationITCase.instances.yml | 34 ++
...ampleVerificationITCase.serviceInstanceTopo.yml | 41 +++
...lking.e2e.SampleVerificationITCase.services.yml | 27 ++
...kywalking.e2e.SampleVerificationITCase.topo.yml | 47 +++
...walking.e2e.SampleVerificationITCase.traces.yml | 40 +++
test/e2e/pom.xml | 1 +
.../known-oap-backend-dependencies-es7.txt | 3 +-
.../known-oap-backend-dependencies.txt | 3 +-
34 files changed, 2014 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml
index e19c1de..513f9e8 100644
--- a/.github/workflows/e2e.yaml
+++ b/.github/workflows/e2e.yaml
@@ -116,6 +116,8 @@ jobs:
./mvnw --batch-mode -f test/e2e/pom.xml -pl e2e-base clean install
- name: 6.x Agents & 7.x Backend
run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-6.x-agent-7.x-oap-compatibility
+ - name: Http API with Nginx Lua Tests In Single Node Mode(JDK8)
+ run: export E2E_VERSION=jdk8-1.5 && bash -x test/e2e/run.sh e2e-http-api-with-nginx-lua
Profile:
runs-on: ubuntu-latest
diff --git a/.gitignore b/.gitignore
index c8c8488..a5bd42a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,4 @@ OALLexer.tokens
.externalToolBuilders
/test/plugin/dist
/test/plugin/workspace
+e2e-*
diff --git a/docs/en/protocols/HTTP-API-Protocol.md b/docs/en/protocols/HTTP-API-Protocol.md
new file mode 100644
index 0000000..3b42a42
--- /dev/null
+++ b/docs/en/protocols/HTTP-API-Protocol.md
@@ -0,0 +1,200 @@
+# HTTP API Protocol
+
+HTTP API Protocol defines the API data format, including api request and response data format.
+
+### Do register
+
+Detail information about data format can be found in [Register service](https://github.com/apache/skywalking-data-collect-protocol/tree/master/register/Register.proto).
+And register steps followings [SkyWalking Trace Data Protocol v2](Trace-Data-Protocol-v2.md).
+
+- Service Register
+
+> POST http://localhost:12800/v2/service/register
+
+Input:
+
+```json
+{
+ "services": [
+ {
+ "type": "normal",
+ "serviceName": "Service Name"
+ }
+ ]
+}
+```
+
+Output JSON Array:
+
+```json
+[
+ {
+ "key": "Service Name",
+ "value": 2
+ }
+]
+```
+
+- Service instance Register
+
+> POST http://localhost:12800/v2/instance/register
+
+Input:
+
+```json
+{
+ "instances": [
+ {
+ "time": 1582428603392,
+ "instanceUUID": "NAME:Service Instance Name",
+ "properties": [
+ {
+ "key": "language",
+ "value": "Lua"
+ }
+ ],
+ "serviceId": 2
+ }
+ ]
+}
+```
+
+OutPut:
+
+```json
+[
+ {
+ "key": "NAME:Service Instance Name",
+ "value": 0
+ }
+]
+```
+
+- Service instance heartbeat
+
+> POST http://localhost:12800/v2/instance/heartbeat
+
+Input:
+
+```json
+{
+ "serviceInstanceId":20,
+ "time": 1582428603392,
+ "serviceInstanceUUID":"NAME:Service Instance Name"
+}
+```
+
+OutPut:
+
+```json
+{}
+```
+If your instance does not exist, you need to clean your local service instance metadata in your application and re-do register:
+
+```json
+{
+ "commands": [
+ {
+ "command": "ServiceMetadataReset",
+ "args": [
+ {
+ "key": "SerialNumber",
+ "value": "44bd2664-03c7-46bc-8652-52fcde0e7699"
+ }
+ ]
+ }
+ ]
+}
+```
+
+## Trace Report
+
+### POST http://localhost:12800/v2/segments
+
+Input:
+
+```json
+{
+ "spans": [
+ {
+ "operationName": "/tier2/lb",
+ "startTime": 1582461179910,
+ "tags": [],
+ "endTime": 1582461179922,
+ "spanType": "Exit",
+ "logs":[],
+ "spanId": 1,
+ "isError": false,
+ "parentSpanId": 0,
+ "componentId": 6000,
+ "peer": "User Service Name-nginx:upstream_ip:port",
+ "spanLayer": "HTTP"
+ },
+ {
+ "operationName": "/tier2/lb",
+ "startTime": 1582461179910,
+ "tags": [
+ {
+ "key": "http.method",
+ "value": "GET"
+ },
+ {
+ "key": "http.params",
+ "value": "http://127.0.0.1/tier2/lb"
+ }
+ ],
+ "endTime": 1582461179922,
+ "spanType": "Entry",
+ "logs": [],
+ "spanId": 0,
+ "isError": false,
+ "parentSpanId": -1,
+ "componentId": 6000,
+ "refs": [
+ {
+ "parentTraceSegmentId": {
+ "idParts": [
+ 1582461179038,
+ 794206293,
+ 69887
+ ]
+ },
+ "parentEndpointId": 0,
+ "entryEndpointId": 0,
+ "parentServiceInstanceId": 1,
+ "parentEndpoint": "/ingress",
+ "networkAddress": "#User Service Name-nginx:upstream_ip:port",
+ "parentSpanId": 1,
+ "entryServiceInstanceId": 1,
+ "networkAddressId": 0,
+ "entryEndpoint": "/ingress"
+ }
+ ],
+ "spanLayer": "HTTP"
+ }
+ ],
+ "serviceInstanceId": 1,
+ "serviceId": 1,
+ "traceSegmentId": {
+ "idParts": [
+ 1582461179044,
+ 794206293,
+ 69887
+ ]
+ },
+ "globalTraceIds": [
+ {
+ "idParts": [
+ 1582461179038,
+ 794206293,
+ 69887
+ ]
+ }
+ ]
+}
+```
+ OutPut:
+
+ ```json
+
+```
\ No newline at end of file
diff --git a/docs/en/protocols/Trace-Data-Protocol-v2.md b/docs/en/protocols/Trace-Data-Protocol-v2.md
index a80a840..26079bc 100644
--- a/docs/en/protocols/Trace-Data-Protocol-v2.md
+++ b/docs/en/protocols/Trace-Data-Protocol-v2.md
@@ -7,6 +7,9 @@ Trace data protocol is defined and provided in [gRPC format](https://github.com/
For each agent/SDK, it needs to register service id and service instance id before reporting any kind of trace
or metrics data.
+Since SkyWalking v7.x, SkyWalking provided register and uplink trace data through HTTP API way.
+[HTTP API Protocol](HTTP-API-Protocol.md) defined the API data format.
+
### Step 1. Do register
[Register service](https://github.com/apache/skywalking-data-collect-protocol/tree/master/register/Register.proto) takes charge of
all register methods. At step 1, we need `doServiceRegister`, then `doServiceInstanceRegister`.
diff --git a/oap-server/pom.xml b/oap-server/pom.xml
index a90031f..88562cb 100755
--- a/oap-server/pom.xml
+++ b/oap-server/pom.xml
@@ -90,6 +90,7 @@
<javaassist.version>3.25.0-GA</javaassist.version>
<zookeeper.image.version>3.5</zookeeper.image.version>
+ <protobuf-java-util.version>3.11.4</protobuf-java-util.version>
</properties>
@@ -263,6 +264,13 @@
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java-util</artifactId>
+ <version>${protobuf-java-util.version}</version>
+ </dependency>
+
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
diff --git a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java
index f2bbded..b48a324 100644
--- a/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java
+++ b/oap-server/server-library/library-server/src/main/java/org/apache/skywalking/oap/server/library/server/jetty/JettyJsonHandler.java
@@ -19,6 +19,7 @@
package org.apache.skywalking.oap.server.library.server.jetty;
import com.google.gson.JsonElement;
+import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
@@ -84,25 +85,25 @@ public abstract class JettyJsonHandler extends JettyHandler {
@Override
protected final void doDelete(HttpServletRequest req,
- HttpServletResponse resp) throws ServletException, IOException {
+ HttpServletResponse resp) throws ServletException, IOException {
super.doDelete(req, resp);
}
@Override
protected final void doOptions(HttpServletRequest req,
- HttpServletResponse resp) throws ServletException, IOException {
+ HttpServletResponse resp) throws ServletException, IOException {
super.doOptions(req, resp);
}
@Override
protected final void doTrace(HttpServletRequest req,
- HttpServletResponse resp) throws ServletException, IOException {
+ HttpServletResponse resp) throws ServletException, IOException {
super.doTrace(req, resp);
}
@Override
protected final void service(HttpServletRequest req,
- HttpServletResponse resp) throws ServletException, IOException {
+ HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
@@ -189,4 +190,14 @@ public abstract class JettyJsonHandler extends JettyHandler {
out.flush();
out.close();
}
+
+ public String getJsonBody(HttpServletRequest req) throws IOException {
+ StringBuffer stringBuffer = new StringBuffer();
+ String line = null;
+ BufferedReader reader = req.getReader();
+ while ((line = reader.readLine()) != null) {
+ stringBuffer.append(line);
+ }
+ return stringBuffer.toString();
+ }
}
diff --git a/oap-server/server-library/library-util/pom.xml b/oap-server/server-library/library-util/pom.xml
index 93b2fa7..6f5b29a 100644
--- a/oap-server/server-library/library-util/pom.xml
+++ b/oap-server/server-library/library-util/pom.xml
@@ -31,6 +31,7 @@
<properties>
<ststem-rules.version>1.18.0</ststem-rules.version>
+ <protobuf-java.version>3.11.4</protobuf-java.version>
</properties>
<dependencies>
@@ -53,5 +54,16 @@
<version>${ststem-rules.version}</version>
<scope>test</scope>
</dependency>
+
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>${protobuf-java.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java-util</artifactId>
+ </dependency>
</dependencies>
</project>
diff --git a/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/ProtoBufJsonUtils.java b/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/ProtoBufJsonUtils.java
new file mode 100644
index 0000000..09aba12
--- /dev/null
+++ b/oap-server/server-library/library-util/src/main/java/org/apache/skywalking/oap/server/library/util/ProtoBufJsonUtils.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 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.oap.server.library.util;
+
+import com.google.protobuf.Message;
+import com.google.protobuf.util.JsonFormat;
+import java.io.IOException;
+
+public class ProtoBufJsonUtils {
+
+ public static String toJSON(Message sourceMessage) throws IOException {
+ return JsonFormat.printer().print(sourceMessage);
+ }
+
+ /**
+ * Extract data from a JSON String and use them to construct a Protocol Buffers Message.
+ *
+ * @param json A JSON data string to parse
+ * @param targetBuilder A Message builder to use to construct the resulting Message
+ * @throws com.google.protobuf.InvalidProtocolBufferException Thrown in case of invalid Message data
+ */
+ public static void fromJSON(String json, Message.Builder targetBuilder) throws IOException {
+ JsonFormat.parser()
+ .usingTypeRegistry(JsonFormat.TypeRegistry.newBuilder()
+ .add(targetBuilder.getDescriptorForType())
+ .build())
+ .ignoringUnknownFields()
+ .merge(json, targetBuilder);
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java
index 798dea3..f7b3dc0 100644
--- a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/RegisterModuleProvider.java
@@ -20,12 +20,16 @@ package org.apache.skywalking.oap.server.receiver.register.provider;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
import org.apache.skywalking.oap.server.library.module.ModuleConfig;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
import org.apache.skywalking.oap.server.library.module.ModuleProvider;
import org.apache.skywalking.oap.server.receiver.register.module.RegisterModule;
import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.grpc.RegisterServiceHandler;
import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.grpc.ServiceInstancePingServiceHandler;
+import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest.ServiceInstancePingServletHandler;
+import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest.ServiceInstanceRegisterServletHandler;
+import org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest.ServiceRegisterServletHandler;
import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
public class RegisterModuleProvider extends ModuleProvider {
@@ -56,6 +60,13 @@ public class RegisterModuleProvider extends ModuleProvider {
.getService(GRPCHandlerRegister.class);
grpcHandlerRegister.addHandler(new RegisterServiceHandler(getManager()));
grpcHandlerRegister.addHandler(new ServiceInstancePingServiceHandler(getManager()));
+
+ JettyHandlerRegister jettyHandlerRegister = getManager().find(SharingServerModule.NAME)
+ .provider()
+ .getService(JettyHandlerRegister.class);
+ jettyHandlerRegister.addHandler(new ServiceRegisterServletHandler(getManager()));
+ jettyHandlerRegister.addHandler(new ServiceInstanceRegisterServletHandler(getManager()));
+ jettyHandlerRegister.addHandler(new ServiceInstancePingServletHandler(getManager()));
}
@Override
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstancePingServletHandler.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstancePingServletHandler.java
new file mode 100644
index 0000000..738f661
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstancePingServletHandler.java
@@ -0,0 +1,111 @@
+/*
+ * 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.oap.server.receiver.register.provider.handler.v6.rest;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.Objects;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.common.Command;
+import org.apache.skywalking.apm.network.common.Commands;
+import org.apache.skywalking.apm.network.register.v2.ServiceInstancePingPkg;
+import org.apache.skywalking.apm.network.trace.component.command.ServiceResetCommand;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.cache.ServiceInstanceInventoryCache;
+import org.apache.skywalking.oap.server.core.command.CommandService;
+import org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInstanceInventoryRegister;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInventoryRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServiceInstancePingServletHandler extends JettyJsonHandler {
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceInstancePingServletHandler.class);
+
+ private final IServiceInstanceInventoryRegister serviceInstanceInventoryRegister;
+ private final ServiceInstanceInventoryCache serviceInstanceInventoryCache;
+ private final IServiceInventoryRegister serviceInventoryRegister;
+ private final CommandService commandService;
+ private final Gson gson = new Gson();
+
+ public ServiceInstancePingServletHandler(ModuleManager moduleManager) {
+ this.serviceInstanceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(
+ IServiceInstanceInventoryRegister.class);
+ this.serviceInstanceInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(
+ ServiceInstanceInventoryCache.class);
+ this.serviceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(
+ IServiceInventoryRegister.class);
+ this.commandService = moduleManager.find(CoreModule.NAME).provider().getService(CommandService.class);
+ }
+
+ @Override
+ public String pathSpec() {
+ return "/v2/instance/heartbeat";
+ }
+
+ @Override
+ protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException, IOException {
+ JsonObject responseJson = new JsonObject();
+
+ try {
+ ServiceInstancePingPkg.Builder builder = ServiceInstancePingPkg.newBuilder();
+ ProtoBufJsonUtils.fromJSON(getJsonBody(req), builder);
+ ServiceInstancePingPkg instancePingPkg = builder.build();
+
+ int serviceInstanceId = instancePingPkg.getServiceInstanceId();
+ long heartBeatTime = instancePingPkg.getTime();
+ String serviceInstanceUUID = instancePingPkg.getServiceInstanceUUID();
+ serviceInstanceInventoryRegister.heartbeat(serviceInstanceId, heartBeatTime);
+
+ ServiceInstanceInventory serviceInstanceInventory = serviceInstanceInventoryCache.get(serviceInstanceId);
+ if (Objects.nonNull(serviceInstanceInventory)) {
+ serviceInventoryRegister.heartbeat(serviceInstanceInventory.getServiceId(), heartBeatTime);
+ } else {
+ logger.warn(
+ "Can't found service by service instance id from cache, service instance id is: {}",
+ serviceInstanceId
+ );
+
+ final ServiceResetCommand resetCommand = commandService.newResetCommand(
+ serviceInstanceId, heartBeatTime, serviceInstanceUUID);
+ final Command command = resetCommand.serialize().build();
+ final Commands nextCommands = Commands.newBuilder().addCommands(command).build();
+ return gson.fromJson(ProtoBufJsonUtils.toJSON(nextCommands), JsonElement.class);
+ }
+
+ } catch (IOException e) {
+ responseJson.addProperty("error", e.getMessage());
+ logger.error(e.getMessage(), e);
+ }
+
+ return responseJson;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstanceRegisterServletHandler.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstanceRegisterServletHandler.java
new file mode 100644
index 0000000..f930fc3
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceInstanceRegisterServletHandler.java
@@ -0,0 +1,152 @@
+/*
+ * 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.oap.server.receiver.register.provider.handler.v6.rest;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.common.KeyStringValuePair;
+import org.apache.skywalking.apm.network.register.v2.ServiceInstance;
+import org.apache.skywalking.apm.network.register.v2.ServiceInstances;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.cache.ServiceInventoryCache;
+import org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory;
+import org.apache.skywalking.oap.server.core.register.ServiceInventory;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInstanceInventoryRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.HOST_NAME;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.IPV4S;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.LANGUAGE;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.OS_NAME;
+import static org.apache.skywalking.oap.server.core.register.ServiceInstanceInventory.PropertyUtil.PROCESS_NO;
+
+public class ServiceInstanceRegisterServletHandler extends JettyJsonHandler {
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceInstanceRegisterServletHandler.class);
+ private static final String INSTANCE_CUSTOMIZED_NAME_PREFIX = "NAME:";
+
+ private final IServiceInstanceInventoryRegister serviceInstanceInventoryRegister;
+ private final ServiceInventoryCache serviceInventoryCache;
+
+ private static final String KEY = "key";
+ private static final String VALUE = "value";
+
+ public ServiceInstanceRegisterServletHandler(ModuleManager moduleManager) {
+ this.serviceInventoryCache = moduleManager.find(CoreModule.NAME)
+ .provider()
+ .getService(ServiceInventoryCache.class);
+ this.serviceInstanceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(
+ IServiceInstanceInventoryRegister.class);
+ }
+
+ @Override
+ public String pathSpec() {
+ return "/v2/instance/register";
+ }
+
+ @Override
+ protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException {
+
+ JsonObject responseJson = new JsonObject();
+ JsonArray jsonArray = new JsonArray();
+
+ try {
+ ServiceInstances.Builder builder = ServiceInstances.newBuilder();
+ ProtoBufJsonUtils.fromJSON(getJsonBody(req), builder);
+ List<ServiceInstance> serviceInstances = builder.build().getInstancesList();
+
+ serviceInstances.forEach(instance -> {
+ long time = instance.getTime();
+ int serviceId = instance.getServiceId();
+ String instanceUUID = instance.getInstanceUUID();
+
+ JsonObject instanceProperties = new JsonObject();
+ List<String> ipv4s = new ArrayList<>();
+
+ for (KeyStringValuePair property : instance.getPropertiesList()) {
+ String key = property.getKey();
+ switch (key) {
+ case HOST_NAME:
+ instanceProperties.addProperty(HOST_NAME, property.getValue());
+ break;
+ case OS_NAME:
+ instanceProperties.addProperty(OS_NAME, property.getValue());
+ break;
+ case LANGUAGE:
+ instanceProperties.addProperty(LANGUAGE, property.getValue());
+ break;
+ case "ipv4":
+ ipv4s.add(property.getValue());
+ break;
+ case PROCESS_NO:
+ instanceProperties.addProperty(PROCESS_NO, property.getValue());
+ break;
+ default:
+ instanceProperties.addProperty(key, property.getValue());
+ }
+ }
+ instanceProperties.addProperty(IPV4S, ServiceInstanceInventory.PropertyUtil.ipv4sSerialize(ipv4s));
+
+ String instanceName = null;
+ if (instanceUUID.startsWith(INSTANCE_CUSTOMIZED_NAME_PREFIX)) {
+ instanceName = instanceUUID.substring(INSTANCE_CUSTOMIZED_NAME_PREFIX.length());
+ }
+
+ ServiceInventory serviceInventory = serviceInventoryCache.get(serviceId);
+
+ if (instanceName == null) {
+ instanceName = serviceInventory.getName();
+ if (instanceProperties.has(PROCESS_NO)) {
+ instanceName += "-pid:" + instanceProperties.get(PROCESS_NO).getAsString();
+ }
+ if (instanceProperties.has(HOST_NAME)) {
+ instanceName += "@" + instanceProperties.get(HOST_NAME).getAsString();
+ }
+ }
+ int instanceId = serviceInstanceInventoryRegister.getOrCreate(
+ serviceId, instanceName, instanceUUID, time, instanceProperties);
+
+ responseJson.addProperty(KEY, instanceUUID);
+ responseJson.addProperty(VALUE, instanceId);
+ jsonArray.add(responseJson);
+ });
+
+ return jsonArray;
+ } catch (IOException e) {
+ responseJson.addProperty("error", e.getMessage());
+ logger.error(e.getMessage(), e);
+ }
+ return responseJson;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceRegisterServletHandler.java b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceRegisterServletHandler.java
new file mode 100644
index 0000000..10242bc
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-register-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/register/provider/handler/v6/rest/ServiceRegisterServletHandler.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.receiver.register.provider.handler.v6.rest;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.io.IOException;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.register.v2.Service;
+import org.apache.skywalking.apm.network.register.v2.Services;
+import org.apache.skywalking.oap.server.core.CoreModule;
+import org.apache.skywalking.oap.server.core.register.NodeType;
+import org.apache.skywalking.oap.server.core.register.service.IServiceInventoryRegister;
+import org.apache.skywalking.oap.server.library.module.ModuleManager;
+import org.apache.skywalking.oap.server.library.server.jetty.ArgumentsParseException;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServiceRegisterServletHandler extends JettyJsonHandler {
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceRegisterServletHandler.class);
+
+ private final IServiceInventoryRegister serviceInventoryRegister;
+
+ private static final String KEY = "key";
+ private static final String VALUE = "value";
+
+ public ServiceRegisterServletHandler(ModuleManager moduleManager) {
+ serviceInventoryRegister = moduleManager.find(CoreModule.NAME)
+ .provider()
+ .getService(IServiceInventoryRegister.class);
+ }
+
+ @Override
+ public String pathSpec() {
+ return "/v2/service/register";
+ }
+
+ @Override
+ protected JsonElement doGet(HttpServletRequest req) throws ArgumentsParseException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected JsonElement doPost(HttpServletRequest req) throws ArgumentsParseException {
+ JsonArray responseArray = new JsonArray();
+
+ try {
+ Services.Builder builder = Services.newBuilder();
+ ProtoBufJsonUtils.fromJSON(getJsonBody(req), builder);
+ List<Service> serviceList = builder.build().getServicesList();
+
+ serviceList.forEach(service -> {
+ int serviceId = serviceInventoryRegister.getOrCreate(service.getServiceName(),
+ NodeType.fromRegisterServiceType(
+ service.getType()), null
+ );
+
+ JsonObject mapping = new JsonObject();
+ mapping.addProperty(KEY, service.getServiceName());
+ mapping.addProperty(VALUE, serviceId);
+ responseArray.add(mapping);
+ });
+ } catch (IOException e) {
+ JsonObject mapping = new JsonObject();
+ mapping.addProperty("error", e.getMessage());
+ responseArray.add(mapping);
+ logger.error(e.getMessage(), e);
+ }
+ return responseArray;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java
index 3eb3d5f..b087241 100755
--- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java
@@ -18,10 +18,12 @@
package org.apache.skywalking.oap.server.receiver.trace.provider;
+import java.io.IOException;
import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule;
import org.apache.skywalking.oap.server.configuration.api.DynamicConfigurationService;
import org.apache.skywalking.oap.server.core.CoreModule;
import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister;
+import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister;
import org.apache.skywalking.oap.server.library.module.ModuleConfig;
import org.apache.skywalking.oap.server.library.module.ModuleDefine;
import org.apache.skywalking.oap.server.library.module.ModuleProvider;
@@ -30,6 +32,7 @@ import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedExcepti
import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule;
import org.apache.skywalking.oap.server.receiver.trace.module.TraceModule;
import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.grpc.TraceSegmentReportServiceHandler;
+import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.rest.TraceSegmentCollectServletHandler;
import org.apache.skywalking.oap.server.receiver.trace.provider.parser.ISegmentParserService;
import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParseV2;
import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParserListenerManager;
@@ -41,8 +44,6 @@ import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.
import org.apache.skywalking.oap.server.receiver.trace.provider.parser.standardization.SegmentStandardizationWorker;
import org.apache.skywalking.oap.server.telemetry.TelemetryModule;
-import java.io.IOException;
-
public class TraceModuleProvider extends ModuleProvider {
private final TraceServiceModuleConfig moduleConfig;
@@ -80,7 +81,8 @@ public class TraceModuleProvider extends ModuleProvider {
segmentProducerV2 = new SegmentParseV2.Producer(getManager(), listenerManager(), moduleConfig);
- this.registerServiceImplementation(ISegmentParserService.class, new SegmentParserServiceImpl(segmentProducerV2));
+ this.registerServiceImplementation(
+ ISegmentParserService.class, new SegmentParserServiceImpl(segmentProducerV2));
}
public SegmentParserListenerManager listenerManager() {
@@ -99,19 +101,28 @@ public class TraceModuleProvider extends ModuleProvider {
public void start() throws ModuleStartException {
DynamicConfigurationService dynamicConfigurationService = getManager().find(ConfigurationModule.NAME)
.provider()
- .getService(DynamicConfigurationService.class);
+ .getService(
+ DynamicConfigurationService.class);
GRPCHandlerRegister grpcHandlerRegister = getManager().find(SharingServerModule.NAME)
.provider()
.getService(GRPCHandlerRegister.class);
+ JettyHandlerRegister jettyHandlerRegister = getManager().find(SharingServerModule.NAME)
+ .provider()
+ .getService(JettyHandlerRegister.class);
try {
dynamicConfigurationService.registerConfigChangeWatcher(thresholds);
dynamicConfigurationService.registerConfigChangeWatcher(uninstrumentedGatewaysConfig);
grpcHandlerRegister.addHandler(new TraceSegmentReportServiceHandler(segmentProducerV2, getManager()));
- SegmentStandardizationWorker standardizationWorkerV2 = new SegmentStandardizationWorker(getManager(), segmentProducerV2, moduleConfig
- .getBufferPath(), moduleConfig.getBufferOffsetMaxFileSize(), moduleConfig.getBufferDataMaxFileSize(), moduleConfig
- .isBufferFileCleanWhenRestart());
+ jettyHandlerRegister.addHandler(new TraceSegmentCollectServletHandler(segmentProducerV2));
+
+ SegmentStandardizationWorker standardizationWorkerV2 = new SegmentStandardizationWorker(
+ getManager(), segmentProducerV2, moduleConfig
+ .getBufferPath(), moduleConfig.getBufferOffsetMaxFileSize(), moduleConfig.getBufferDataMaxFileSize(),
+ moduleConfig
+ .isBufferFileCleanWhenRestart()
+ );
segmentProducerV2.setStandardizationWorker(standardizationWorkerV2);
} catch (IOException e) {
throw new ModuleStartException(e.getMessage(), e);
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/TraceSegmentCollectServletHandler.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/TraceSegmentCollectServletHandler.java
new file mode 100644
index 0000000..44bb243
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/TraceSegmentCollectServletHandler.java
@@ -0,0 +1,76 @@
+/*
+ * 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.oap.server.receiver.trace.provider.handler.v6.rest;
+
+import com.google.gson.JsonElement;
+import java.io.BufferedReader;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.skywalking.apm.network.language.agent.UpstreamSegment;
+import org.apache.skywalking.oap.server.library.server.jetty.JettyJsonHandler;
+import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.rest.reader.UpstreamSegmentJsonReader;
+import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParseV2;
+import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TraceSegmentCollectServletHandler extends JettyJsonHandler {
+
+ private static final Logger logger = LoggerFactory.getLogger(TraceSegmentCollectServletHandler.class);
+
+ private final SegmentParseV2.Producer segmentProducer;
+
+ private UpstreamSegmentJsonReader upstreamSegmentJsonReader = new UpstreamSegmentJsonReader();
+
+ public TraceSegmentCollectServletHandler(SegmentParseV2.Producer segmentProducer) {
+ this.segmentProducer = segmentProducer;
+ }
+
+ @Override
+ public String pathSpec() {
+ return "/v2/segments";
+ }
+
+ @Override
+ protected JsonElement doGet(HttpServletRequest req) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected JsonElement doPost(HttpServletRequest req) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("receive stream segment");
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ String line = null;
+ try {
+ BufferedReader reader = req.getReader();
+ while ((line = reader.readLine()) != null) {
+ stringBuilder.append(line);
+ }
+ UpstreamSegment upstreamSegment = upstreamSegmentJsonReader.read(stringBuilder.toString()).build();
+
+ segmentProducer.send(upstreamSegment, SegmentSource.Agent);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+
+ return null;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/SegmentJsonReader.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/SegmentJsonReader.java
new file mode 100644
index 0000000..2e78dc1
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/SegmentJsonReader.java
@@ -0,0 +1,33 @@
+/*
+ * 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.oap.server.receiver.trace.provider.handler.v6.rest.reader;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+
+public class SegmentJsonReader implements StreamJsonReader<SegmentObject.Builder> {
+
+ @Override
+ public SegmentObject.Builder read(String json) throws IOException {
+ SegmentObject.Builder builder = SegmentObject.newBuilder();
+ ProtoBufJsonUtils.fromJSON(json, builder);
+ return builder;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/StreamJsonReader.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/StreamJsonReader.java
new file mode 100644
index 0000000..13b7028
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/StreamJsonReader.java
@@ -0,0 +1,25 @@
+/*
+ * 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.oap.server.receiver.trace.provider.handler.v6.rest.reader;
+
+import java.io.IOException;
+
+public interface StreamJsonReader<T> {
+ T read(String json) throws IOException;
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/UpstreamSegmentJsonReader.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/UpstreamSegmentJsonReader.java
new file mode 100644
index 0000000..3344952
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/handler/v6/rest/reader/UpstreamSegmentJsonReader.java
@@ -0,0 +1,41 @@
+/*
+ * 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.oap.server.receiver.trace.provider.handler.v6.rest.reader;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.network.language.agent.UpstreamSegment;
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+
+public class UpstreamSegmentJsonReader implements StreamJsonReader<UpstreamSegment.Builder> {
+
+ private final SegmentJsonReader segmentJsonReader = new SegmentJsonReader();
+
+ @Override
+ public UpstreamSegment.Builder read(String json) throws IOException {
+ UpstreamSegment.Builder upstreamSegmentBuilder = UpstreamSegment.newBuilder();
+ ProtoBufJsonUtils.fromJSON(json, upstreamSegmentBuilder);
+
+ SegmentObject.Builder segmentBuilder = segmentJsonReader.read(json);
+
+ upstreamSegmentBuilder.setSegment(segmentBuilder.build().toByteString());
+
+ return upstreamSegmentBuilder;
+ }
+}
diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/segment/ProtoBufJsonUtilsTest.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/segment/ProtoBufJsonUtilsTest.java
new file mode 100644
index 0000000..559a908
--- /dev/null
+++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/segment/ProtoBufJsonUtilsTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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.oap.server.receiver.trace.provider.parser.listener.segment;
+
+import java.io.IOException;
+import org.apache.skywalking.apm.network.common.Command;
+import org.apache.skywalking.apm.network.common.Commands;
+import org.apache.skywalking.apm.network.language.agent.UpstreamSegment;
+import org.apache.skywalking.apm.network.language.agent.v2.SegmentObject;
+import org.apache.skywalking.oap.server.library.util.ProtoBufJsonUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ProtoBufJsonUtilsTest {
+ @Test
+ public void testProtoBuf() {
+ String json = "{\n" +
+ " \"spans\": [\n" +
+ " {\n" +
+ " \"operationName\": \"/tier2/lb\",\n" +
+ " \"startTime\": 1582526028207,\n" +
+ " \"endTime\": 1582526028221,\n" +
+ " \"spanType\": \"Exit\",\n" +
+ " \"spanId\": 1,\n" +
+ " \"isError\": false,\n" +
+ " \"parentSpanId\": 0,\n" +
+ " \"componentId\": 6000,\n" +
+ " \"peer\": \"User Service Name-nginx:upstream_ip:port\",\n" +
+ " \"spanLayer\": \"HTTP\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"operationName\": \"/tier2/lb\",\n" +
+ " \"startTime\": 1582526028207,\n" +
+ " \"tags\": [\n" +
+ " {\n" +
+ " \"key\": \"http.method\",\n" +
+ " \"value\": \"GET\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"key\": \"http.params\",\n" +
+ " \"value\": \"http://127.0.0.1/tier2/lb\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"endTime\": 1582526028221,\n" +
+ " \"spanType\": \"Entry\",\n" +
+ " \"spanId\": 0,\n" +
+ " \"isError\": false,\n" +
+ " \"parentSpanId\": -1,\n" +
+ " \"componentId\": 6000,\n" +
+ " \"refs\": [\n" +
+ " {\n" +
+ " \"parentTraceSegmentId\": {\n" +
+ " \"idParts\": [\n" +
+ " 1582526028032,\n" +
+ " 794206293,\n" +
+ " 69887\n" +
+ " ]\n" +
+ " },\n" +
+ " \"parentEndpointId\": 0,\n" +
+ " \"entryEndpointId\": 0,\n" +
+ " \"parentServiceInstanceId\": 1,\n" +
+ " \"parentEndpoint\": \"/ingress\",\n" +
+ " \"networkAddress\": \"#User Service Name-nginx:upstream_ip:port\",\n" +
+ " \"parentSpanId\": 1,\n" +
+ " \"entryServiceInstanceId\": 1,\n" +
+ " \"networkAddressId\": 0,\n" +
+ " \"entryEndpoint\": \"/ingress\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"spanLayer\": \"HTTP\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"serviceInstanceId\": 1,\n" +
+ " \"serviceId\": 1,\n" +
+ " \"traceSegmentId\": {\n" +
+ " \"idParts\": [\n" +
+ " 1582526028040,\n" +
+ " 794206293,\n" +
+ " 69887\n" +
+ " ]\n" +
+ " },\n" +
+ " \"globalTraceIds\": [\n" +
+ " {\n" +
+ " \"idParts\": [\n" +
+ " 1582526028032,\n" +
+ " 794206293,\n" +
+ " 69887\n" +
+ " ]\n" +
+ " }\n" +
+ " ]\n" +
+ "}";
+
+ UpstreamSegment.Builder builder = UpstreamSegment.newBuilder();
+ try {
+ ProtoBufJsonUtils.fromJSON(json, builder);
+ UpstreamSegment upstreamSegment = builder.build();
+ Assert.assertEquals(1582526028032L, upstreamSegment.getGlobalTraceIds(0).getIdParts(0));
+
+ SegmentObject.Builder segBuilder = SegmentObject.newBuilder();
+ ProtoBufJsonUtils.fromJSON(json, segBuilder);
+ SegmentObject segmentObject = segBuilder.build();
+ Assert.assertEquals(2, segmentObject.getSpansCount());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Test
+ public void testToJson() {
+ String json = "{\n" +
+ " \"commands\": [{\n" +
+ " }]\n" +
+ "}";
+ try {
+ Command command = Command.newBuilder().build();
+ final Commands nextCommands = Commands.newBuilder().addCommands(command).build();
+ Assert.assertEquals(json, ProtoBufJsonUtils.toJSON(nextCommands));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/pom.xml b/test/e2e/e2e-http-api-with-nginx-lua/pom.xml
new file mode 100755
index 0000000..012723a
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/pom.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ ~
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>apache-skywalking-e2e</artifactId>
+ <groupId>org.apache.skywalking</groupId>
+ <version>1.0.0</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>e2e-http-api-with-nginx-lua</artifactId>
+
+ <properties>
+ <e2e.container.version>1.1</e2e.container.version>
+ <e2e.container.name.prefix>skywalking-e2e-container-${build.id}-http-api-with-nginx-lua
+ </e2e.container.name.prefix>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.skywalking</groupId>
+ <artifactId>e2e-base</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring.boot.version}</version>
+ <configuration>
+ <executable>true</executable>
+ <addResources>true</addResources>
+ <excludeDevtools>true</excludeDevtools>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>io.fabric8</groupId>
+ <artifactId>docker-maven-plugin</artifactId>
+ <configuration>
+ <containerNamePattern>%a-%t-%i</containerNamePattern>
+ <images>
+ <image>
+ <name>skyapm/e2e-container:${e2e.container.version}</name>
+ <alias>e2e-container-app-for-nginx-lua</alias>
+ <run>
+ <env>
+ <INSTRUMENTED_SERVICE>${project.build.finalName}.jar</INSTRUMENTED_SERVICE>
+ <INSTRUMENTED_SERVICE_OPTS>-Dskywalking.agent.cool_down_threshold=1
+ </INSTRUMENTED_SERVICE_OPTS>
+ </env>
+ <ports>
+ <port>+webapp.host:webapp.port:8080</port>
+ <port>+client.host:client.port:9090</port>
+ </ports>
+ <volumes>
+ <bind>
+ <volume>${sw.home}:/sw</volume>
+ <volume>${project.build.directory}:/home</volume>
+ <volume>
+ ${project.basedir}/src/docker/rc.d/rc1-startup.sh:/rc.d/rc1-startup.sh:ro
+ </volume>
+ </bind>
+ </volumes>
+ <wait>
+ <http>
+ <url>
+ http://${docker.host.address}:${client.port}/e2e/info
+ </url>
+ <method>GET</method>
+ <status>200</status>
+ </http>
+ <time>300000</time>
+ </wait>
+ </run>
+ </image>
+
+ <image>
+ <name>openresty/openresty</name>
+ <alias>${e2e.container.name.prefix}-openresty</alias>
+
+ <run>
+ <env>
+ <SKYWALKING_NINGX_LUA_GIT_COMMIT_ID>c6aca516200573a64db7060cefb5d3608c571c3a
+ </SKYWALKING_NINGX_LUA_GIT_COMMIT_ID>
+ </env>
+ <links>
+ <link>e2e-container-app-for-nginx-lua:upstream</link>
+ </links>
+ <ports>
+ <port>+nginx.host:nginx.port:8080</port>
+ </ports>
+ <volumes>
+ <bind>
+ <volume>${project.basedir}/src/docker/rc.d:/rc.d:ro</volume>
+ </bind>
+ </volumes>
+ <wait>
+ <http>
+ <url>
+ http://${docker.host.address}:${nginx.port}
+ </url>
+ </http>
+ <time>3000000</time>
+ </wait>
+ <cmd>/rc.d/rc0-prepare.sh</cmd>
+ </run>
+ </image>
+ </images>
+ </configuration>
+ </plugin>
+
+ <!-- set the system properties that can be used in test codes -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <systemPropertyVariables>
+ <sw.webapp.host>
+ ${webapp.host}
+ </sw.webapp.host>
+ <sw.webapp.port>
+ ${webapp.port}
+ </sw.webapp.port>
+ <client.host>
+ ${client.host}
+ </client.host>
+ <client.port>
+ ${client.port}
+ </client.port>
+ <nginx.port>
+ ${nginx.port}
+ </nginx.port>
+ </systemPropertyVariables>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${maven-failsafe-plugin.version}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <ping.url>
+ http://${nginx.host}:${nginx.port}/ingress
+ </ping.url>
+ </systemPropertyVariables>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc0-prepare.sh b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc0-prepare.sh
new file mode 100755
index 0000000..39b7ed5
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc0-prepare.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+# Licensed to the SkyAPM 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.
+
+#!/bin/bash
+
+set -e
+
+var_application_file="/var/nginx/conf.d/nginx.conf"
+
+var_upstream_ip=$(cat /etc/hosts|grep upstream|awk '{print $1'})
+
+apt-get update && apt-get -y install git
+
+echo 'git clone skyalking-nginx-lua lib from https://github.com/apache/skywalking-nginx-lua.git'
+
+git clone https://github.com/apache/skywalking-nginx-lua.git /usr/share/skywalking-nginx-lua \
+ && cd /usr/share/skywalking-nginx-lua \
+ && git checkout ${SKYWALKING_NINGX_LUA_GIT_COMMIT_ID} \
+ && ls ./ \
+ && mkdir -p /var/nginx/conf.d
+
+
+generateNginxConf() {
+ cat <<EOT >> ${var_application_file}
+worker_processes 1;
+daemon off;
+error_log /dev/stdout error;
+
+events {
+ worker_connections 1024;
+}
+http {
+ lua_package_path "/usr/share/skywalking-nginx-lua/lib/skywalking/?.lua;;";
+ # Buffer represents the register inform and the queue of the finished segment
+ lua_shared_dict tracing_buffer 100m;
+
+ # Init is the timer setter and keeper
+ # Setup an infinite loop timer to do register and trace report.
+ init_worker_by_lua_block {
+ local metadata_buffer = ngx.shared.tracing_buffer
+
+ metadata_buffer:set('serviceName', 'User_Service_Name')
+ -- Instance means the number of Nginx deloyment, does not mean the worker instances
+ metadata_buffer:set('serviceInstanceName', 'User_Service_Instance_Name')
+
+ require("client"):startBackendTimer("http://${var_upstream_ip}:12800")
+ }
+ log_format sw_trace escape=json "$uri $request_body";
+
+ server {
+ listen 8080;
+
+ location /nginx/e2e/info {
+
+ rewrite_by_lua_block {
+ require("tracer"):start("User_Service_Name")
+ }
+
+ proxy_pass http://upstream:9090/e2e/info;
+
+ body_filter_by_lua_block {
+ require("tracer"):finish()
+ }
+
+ log_by_lua_block {
+ require("tracer"):prepareForReport()
+ }
+ }
+ }
+}
+EOT
+}
+
+generateNginxConf;
+
+echo 'generated nginx.conf:'
+
+cat ${var_application_file}
+
+/usr/bin/openresty -c ${var_application_file}
+sync
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc1-startup.sh b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc1-startup.sh
new file mode 100755
index 0000000..9328f7c
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/docker/rc.d/rc1-startup.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Licensed to the SkyAPM 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.
+
+echo 'starting OAP server...' \
+ && SW_STORAGE_ES_BULK_ACTIONS=1 \
+ && SW_STORAGE_ES_FLUSH_INTERVAL=1 \
+ && SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer1 \
+ && SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer1 \
+ && start_oap 'init'
+
+echo 'starting Web app...' \
+ && start_webapp '0.0.0.0' 8080
+
+echo 'starting instrumented services...' \
+ && start_instrumented_services
+
+check_tcp 127.0.0.1 \
+ 9090 \
+ 60 \
+ 10 \
+ "waiting for the instrumented service to be ready"
+
+if [[ $? -ne 0 ]]; then
+ echo "instrumented service failed to start in 30 * 10 seconds: "
+ cat ${SERVICE_LOG}/*
+ exit 1
+fi
+
+echo "SkyWalking e2e container is ready for tests"
+
+tail -f ${OAP_LOG_DIR}/* \
+ ${WEBAPP_LOG_DIR}/* \
+ ${SERVICE_LOG}/* \
+ ${ES_HOME}/logs/stdout.log
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
new file mode 100644
index 0000000..c661c17
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/SampleClientApplication.java
@@ -0,0 +1,29 @@
+/*
+ * 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.e2e.sample.client;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SampleClientApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(SampleClientApplication.class, args);
+ }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
new file mode 100644
index 0000000..03319c7
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/main/java/org/apache/skywalking/e2e/sample/client/TestController.java
@@ -0,0 +1,32 @@
+/*
+ * 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.e2e.sample.client;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/e2e")
+public class TestController {
+ @GetMapping("/info")
+ public String hello() {
+ return "e2e-container-info";
+ }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/main/resources/application.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/main/resources/application.yml
new file mode 100644
index 0000000..83d1e3d
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/main/resources/application.yml
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+server:
+ port: 9090
+
+spring:
+ main:
+ banner-mode: 'off'
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java b/test/e2e/e2e-http-api-with-nginx-lua/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
new file mode 100644
index 0000000..33eafb4
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/java/org/apache/skywalking/e2e/SampleVerificationITCase.java
@@ -0,0 +1,386 @@
+/*
+ * 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.e2e;
+
+import java.io.InputStream;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.skywalking.e2e.metrics.AtLeastOneOfMetricsMatcher;
+import org.apache.skywalking.e2e.metrics.Metrics;
+import org.apache.skywalking.e2e.metrics.MetricsQuery;
+import org.apache.skywalking.e2e.metrics.MetricsValueMatcher;
+import org.apache.skywalking.e2e.service.Service;
+import org.apache.skywalking.e2e.service.ServicesMatcher;
+import org.apache.skywalking.e2e.service.ServicesQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoint;
+import org.apache.skywalking.e2e.service.endpoint.EndpointQuery;
+import org.apache.skywalking.e2e.service.endpoint.Endpoints;
+import org.apache.skywalking.e2e.service.endpoint.EndpointsMatcher;
+import org.apache.skywalking.e2e.service.instance.Instance;
+import org.apache.skywalking.e2e.service.instance.Instances;
+import org.apache.skywalking.e2e.service.instance.InstancesMatcher;
+import org.apache.skywalking.e2e.service.instance.InstancesQuery;
+import org.apache.skywalking.e2e.topo.Call;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoData;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoMatcher;
+import org.apache.skywalking.e2e.topo.ServiceInstanceTopoQuery;
+import org.apache.skywalking.e2e.topo.TopoData;
+import org.apache.skywalking.e2e.topo.TopoMatcher;
+import org.apache.skywalking.e2e.topo.TopoQuery;
+import org.apache.skywalking.e2e.trace.Trace;
+import org.apache.skywalking.e2e.trace.TracesMatcher;
+import org.apache.skywalking.e2e.trace.TracesQuery;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.web.client.RestTemplate;
+import org.yaml.snakeyaml.Yaml;
+
+import static org.apache.skywalking.e2e.metrics.MetricsMatcher.verifyMetrics;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_CLIENT_METRICS;
+import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_RELATION_SERVER_METRICS;
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+public class SampleVerificationITCase {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SampleVerificationITCase.class);
+
+ private final RestTemplate restTemplate = new RestTemplate();
+ private final int retryInterval = 30;
+
+ private SimpleQueryClient queryClient;
+ private String nginxServiceUrl;
+
+ @Before
+ public void setUp() {
+ final String swWebappHost = System.getProperty("sw.webapp.host", "127.0.0.1");
+ final String swWebappPort = System.getProperty("sw.webapp.port", "32783");
+ final String nginxHost = System.getProperty("nginx.host", "127.0.0.1");
+ final String nginxPort = System.getProperty("nginx.port", "32782");
+ queryClient = new SimpleQueryClient(swWebappHost, swWebappPort);
+ nginxServiceUrl = "http://" + nginxHost + ":" + nginxPort;
+ }
+
+ @Test(timeout = 1200000)
+ @DirtiesContext
+ public void verify() throws Exception {
+ final LocalDateTime minutesAgo = LocalDateTime.now(ZoneOffset.UTC);
+
+ while (true) {
+ final List<Service> services = queryClient.services(
+ new ServicesQuery().start(minutesAgo).end(LocalDateTime.now()));
+
+ if (!services.isEmpty() && services.size() >= 2) {
+ break;
+ }
+ Thread.sleep(10000L);
+ }
+
+ while (true) {
+ try {
+ final Map<String, String> user = new HashMap<>();
+ user.put("name", "SkyWalking");
+ final ResponseEntity<String> responseEntity = restTemplate.getForEntity(
+ nginxServiceUrl + "/nginx/e2e/info", String.class);
+ LOGGER.info("responseEntity: {}", responseEntity);
+ assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(responseEntity.getBody()).isEqualTo("e2e-container-info");
+ final List<Trace> traces = queryClient.traces(new TracesQuery().start(minutesAgo)
+ .end(LocalDateTime.now())
+ .orderByDuration());
+ if (!traces.isEmpty() && traces.size() >= 2) {
+ break;
+ }
+ Thread.sleep(10000L);
+ } catch (Exception ignored) {
+ }
+ }
+
+ doRetryableVerification(() -> {
+ try {
+ verifyTraces(minutesAgo);
+ } catch (Exception e) {
+ LOGGER.warn(e.getMessage(), e);
+ }
+ });
+
+ doRetryableVerification(() -> {
+ try {
+ verifyServices(minutesAgo);
+ } catch (Exception e) {
+ LOGGER.warn(e.getMessage(), e);
+ }
+ });
+
+ doRetryableVerification(() -> {
+ try {
+ verifyTopo(minutesAgo);
+ } catch (Exception e) {
+ LOGGER.warn(e.getMessage(), e);
+ }
+ });
+
+ doRetryableVerification(() -> {
+ try {
+ verifyServiceInstanceTopo(minutesAgo);
+ } catch (Exception e) {
+ LOGGER.warn(e.getMessage(), e);
+ }
+ });
+ }
+
+ private void verifyTopo(LocalDateTime minutesAgo) throws Exception {
+ final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+ final TopoData topoData = queryClient.topo(new TopoQuery().stepByMinute()
+ .start(minutesAgo.minusDays(1))
+ .end(now));
+ LOGGER.info("topoData: {}", topoData);
+
+ InputStream expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml")
+ .getInputStream();
+
+ final TopoMatcher topoMatcher = new Yaml().loadAs(expectedInputStream, TopoMatcher.class);
+ topoMatcher.verify(topoData);
+ verifyServiceRelationMetrics(topoData.getCalls(), minutesAgo);
+ }
+
+ private void verifyServiceInstanceTopo(LocalDateTime minutesAgo) throws Exception {
+ final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+ final ServiceInstanceTopoData topoData = queryClient.serviceInstanceTopo(
+ new ServiceInstanceTopoQuery().stepByMinute()
+ .start(minutesAgo
+ .minusDays(1))
+ .end(now)
+ .clientServiceId("1")
+ .serverServiceId("3"));
+ LOGGER.info("instanceTopoData: {}", topoData);
+
+ InputStream expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml")
+ .getInputStream();
+
+ final ServiceInstanceTopoMatcher topoMatcher = new Yaml().loadAs(
+ expectedInputStream, ServiceInstanceTopoMatcher.class);
+ topoMatcher.verify(topoData);
+ verifyServiceInstanceRelationMetrics(topoData.getCalls(), minutesAgo);
+ }
+
+ private void verifyServices(LocalDateTime minutesAgo) throws Exception {
+ final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+ final List<Service> services = queryClient.services(new ServicesQuery().start(minutesAgo).end(now));
+ LOGGER.info("services: {}", services);
+
+ InputStream expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml")
+ .getInputStream();
+
+ final ServicesMatcher servicesMatcher = new Yaml().loadAs(expectedInputStream, ServicesMatcher.class);
+ servicesMatcher.verify(services);
+
+ for (Service service : services) {
+ LOGGER.info("verifying service instances: {}", service);
+
+ verifyServiceMetrics(service);
+
+ Instances instances = verifyServiceInstances(minutesAgo, now, service);
+
+ verifyInstancesMetrics(instances);
+
+ Endpoints endpoints = verifyServiceEndpoints(minutesAgo, now, service);
+
+ verifyEndpointsMetrics(endpoints);
+ }
+ }
+
+ private Instances verifyServiceInstances(LocalDateTime minutesAgo, LocalDateTime now,
+ Service service) throws Exception {
+ Instances instances = queryClient.instances(new InstancesQuery().serviceId(service.getKey())
+ .start(minutesAgo)
+ .end(now));
+ LOGGER.info("instances: {}", instances);
+ InputStream expectedInputStream;
+ if ("User_Service_Name".equals(service.getLabel())) {
+ expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.nginxInstances.yml")
+ .getInputStream();
+ } else {
+ expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml")
+ .getInputStream();
+ }
+ final InstancesMatcher instancesMatcher = new Yaml().loadAs(expectedInputStream, InstancesMatcher.class);
+ instancesMatcher.verify(instances);
+ return instances;
+ }
+
+ private Endpoints verifyServiceEndpoints(LocalDateTime minutesAgo, LocalDateTime now,
+ Service service) throws Exception {
+ Endpoints endpoints = queryClient.endpoints(new EndpointQuery().serviceId(service.getKey()));
+ LOGGER.info("instances: {}", endpoints);
+ InputStream expectedInputStream;
+
+ if ("/e2e/health-check".equals(endpoints.getEndpoints().get(0).getLabel())) {
+ expectedInputStream = new ClassPathResource(
+ "org.apache.skywalking.e2e.SampleVerificationITCase.nginxEndpoints.yml")
+ .getInputStream();
+ } else {
+ expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml")
+ .getInputStream();
+ }
+ final EndpointsMatcher endpointsMatcher = new Yaml().loadAs(expectedInputStream, EndpointsMatcher.class);
+ endpointsMatcher.verify(endpoints);
+ return endpoints;
+ }
+
+ private void verifyInstancesMetrics(Instances instances) throws Exception {
+ for (Instance instance : instances.getInstances()) {
+ for (String metricsName : ALL_INSTANCE_METRICS) {
+ LOGGER.info("verifying service instance response time: {}", instance);
+ final Metrics instanceMetrics = queryClient.metrics(new MetricsQuery().stepByMinute()
+ .metricsName(metricsName)
+ .id(instance.getKey()));
+ LOGGER.info("instanceMetrics: {}", instanceMetrics);
+ AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+ MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+ greaterThanZero.setValue("ge 0");
+ instanceRespTimeMatcher.setValue(greaterThanZero);
+ instanceRespTimeMatcher.verify(instanceMetrics);
+ LOGGER.info("{}: {}", metricsName, instanceMetrics);
+ }
+ }
+ }
+
+ private void verifyEndpointsMetrics(Endpoints endpoints) throws Exception {
+ for (Endpoint endpoint : endpoints.getEndpoints()) {
+ if (!endpoint.getLabel().equals("/e2e/info") || !endpoint.getLabel()
+ .equals("/nginx/e2e/info")) {
+ continue;
+ }
+ for (String metricName : ALL_ENDPOINT_METRICS) {
+ LOGGER.info("verifying endpoint {}, metrics: {}", endpoint, metricName);
+ final Metrics metrics = queryClient.metrics(new MetricsQuery().stepByMinute()
+ .metricsName(metricName)
+ .id(endpoint.getKey()));
+ LOGGER.info("metrics: {}", metrics);
+ AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+ MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+ greaterThanZero.setValue("ge 0");
+ instanceRespTimeMatcher.setValue(greaterThanZero);
+ instanceRespTimeMatcher.verify(metrics);
+ LOGGER.info("{}: {}", metricName, metrics);
+ }
+ }
+ }
+
+ private void verifyServiceMetrics(Service service) throws Exception {
+ for (String metricName : ALL_SERVICE_METRICS) {
+ LOGGER.info("verifying service {}, metrics: {}", service, metricName);
+ final Metrics serviceMetrics = queryClient.metrics(new MetricsQuery().stepByMinute()
+ .metricsName(metricName)
+ .id(service.getKey()));
+ LOGGER.info("serviceMetrics: {}", serviceMetrics);
+ AtLeastOneOfMetricsMatcher instanceRespTimeMatcher = new AtLeastOneOfMetricsMatcher();
+ MetricsValueMatcher greaterThanZero = new MetricsValueMatcher();
+ greaterThanZero.setValue("ge 0");
+ instanceRespTimeMatcher.setValue(greaterThanZero);
+ instanceRespTimeMatcher.verify(serviceMetrics);
+ LOGGER.info("{}: {}", metricName, serviceMetrics);
+ }
+ }
+
+ private void verifyTraces(LocalDateTime minutesAgo) throws Exception {
+ final LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
+
+ final List<Trace> traces = queryClient.traces(new TracesQuery().start(minutesAgo).end(now).orderByDuration());
+ LOGGER.info("traces: {}", traces);
+
+ InputStream expectedInputStream = new ClassPathResource(
+ "expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml")
+ .getInputStream();
+
+ final TracesMatcher tracesMatcher = new Yaml().loadAs(expectedInputStream, TracesMatcher.class);
+ tracesMatcher.verifyLoosely(traces);
+ }
+
+ private void verifyServiceInstanceRelationMetrics(List<Call> calls,
+ final LocalDateTime minutesAgo) throws Exception {
+ verifyRelationMetrics(
+ calls, minutesAgo, ALL_SERVICE_INSTANCE_RELATION_CLIENT_METRICS,
+ ALL_SERVICE_INSTANCE_RELATION_SERVER_METRICS
+ );
+ }
+
+ private void verifyServiceRelationMetrics(List<Call> calls, final LocalDateTime minutesAgo) throws Exception {
+ verifyRelationMetrics(
+ calls, minutesAgo, ALL_SERVICE_RELATION_CLIENT_METRICS, ALL_SERVICE_RELATION_SERVER_METRICS);
+ }
+
+ private void verifyRelationMetrics(List<Call> calls, final LocalDateTime minutesAgo, String[] relationClientMetrics,
+ String[] relationServerMetrics) throws Exception {
+ for (Call call : calls) {
+ for (String detectPoint : call.getDetectPoints()) {
+ switch (detectPoint) {
+ case "CLIENT": {
+ for (String metricName : relationClientMetrics) {
+ verifyMetrics(queryClient, metricName, call.getId(), minutesAgo);
+ }
+ break;
+ }
+ case "SERVER": {
+ for (String metricName : relationServerMetrics) {
+ verifyMetrics(queryClient, metricName, call.getId(), minutesAgo);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private void doRetryableVerification(Runnable runnable) throws InterruptedException {
+ while (true) {
+ try {
+ runnable.run();
+ break;
+ } catch (Throwable ignored) {
+ Thread.sleep(retryInterval);
+ }
+ }
+ }
+}
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
new file mode 100644
index 0000000..ed06316
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.endpoints.yml
@@ -0,0 +1,28 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+endpoints:
+ - key: not null
+ label: /e2e/info
+
+
+
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
new file mode 100644
index 0000000..26bb314
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.instances.yml
@@ -0,0 +1,34 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+instances:
+ - key: 2
+ label: not null
+ attributes:
+ - name: os_name
+ value: not null
+ - name: host_name
+ value: not null
+ - name: process_no
+ value: gt 0
+ - name: ipv4s
+ value: not null
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
new file mode 100644
index 0000000..6661a99
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.serviceInstanceTopo.yml
@@ -0,0 +1,41 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+nodes:
+ - id: 1
+ name: User
+ type: USER
+ serviceId: 1
+ serviceName: User
+ isReal: false
+ - id: 3
+ name: not null
+ serviceId: 3
+ serviceName: User_Service_Name
+ type: not null
+ isReal: true
+calls:
+ - id: 1_3
+ source: 1
+ detectPoints:
+ - SERVER
+ target: 3
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
new file mode 100644
index 0000000..ef0df12
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.services.yml
@@ -0,0 +1,27 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+services:
+ - key: 2
+ label: "Your_ApplicationName"
+ - key: 3
+ label: "User_Service_Name"
\ No newline at end of file
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
new file mode 100644
index 0000000..2ca7456
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.topo.yml
@@ -0,0 +1,47 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+nodes:
+ - id: 1
+ name: User
+ type: USER
+ isReal: false
+ - id: 2
+ name: Your_ApplicationName
+ type: Tomcat
+ isReal: true
+ - id: 3
+ name: User_Service_Name
+ type: Nginx
+ isReal: true
+calls:
+ - id: 1_3
+ source: 1
+ detectPoints:
+ - SERVER
+ target: 3
+ - id: 3_2
+ source: 3
+ detectPoints:
+ - CLIENT
+ - SERVER
+ target: 2
\ No newline at end of file
diff --git a/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
new file mode 100644
index 0000000..0552a1c
--- /dev/null
+++ b/test/e2e/e2e-http-api-with-nginx-lua/src/test/resources/expected-data/org.apache.skywalking.e2e.SampleVerificationITCase.traces.yml
@@ -0,0 +1,40 @@
+# 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.
+
+# 1 health-check by docker-maven-plugin
+# 1 drop table if exists, because we have `ddl-auto: create-drop`
+# 1 drop sequence
+# 1 create sequence
+# 1 create table statement
+
+traces:
+ - key: not null
+ endpointNames:
+ - /e2e/info
+ duration: ge 0
+ start: gt 0
+ isError: false
+ traceIds:
+ - not null
+
+ - key: not null
+ endpointNames:
+ - /nginx/e2e/info
+ duration: ge 0
+ start: gt 0
+ isError: false
+ traceIds:
+ - not null
\ No newline at end of file
diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml
index 0a6c8b5..31790ae 100644
--- a/test/e2e/pom.xml
+++ b/test/e2e/pom.xml
@@ -44,6 +44,7 @@
<module>e2e-6.x-agent-7.x-oap-compatibility</module>
<module>e2e-profile</module>
<module>e2e-protocol</module>
+ <module>e2e-http-api-with-nginx-lua</module>
</modules>
<properties>
diff --git a/tools/dependencies/known-oap-backend-dependencies-es7.txt b/tools/dependencies/known-oap-backend-dependencies-es7.txt
index 59c3f8d..2f20ac2 100755
--- a/tools/dependencies/known-oap-backend-dependencies-es7.txt
+++ b/tools/dependencies/known-oap-backend-dependencies-es7.txt
@@ -142,7 +142,8 @@ opencensus-contrib-grpc-metrics-0.24.0.jar
parent-join-client-7.0.0.jar
perfmark-api-0.19.0.jar
proto-google-common-protos-1.12.0.jar
-protobuf-java-3.4.0.jar
+protobuf-java-3.11.4.jar
+protobuf-java-util-3.11.4.jar
rank-eval-client-7.0.0.jar
reactive-streams-1.0.2.jar
reflectasm-1.11.7.jar
diff --git a/tools/dependencies/known-oap-backend-dependencies.txt b/tools/dependencies/known-oap-backend-dependencies.txt
index 836cced..8b9e854 100755
--- a/tools/dependencies/known-oap-backend-dependencies.txt
+++ b/tools/dependencies/known-oap-backend-dependencies.txt
@@ -140,7 +140,8 @@ opencensus-contrib-grpc-metrics-0.24.0.jar
parent-join-client-6.3.2.jar
perfmark-api-0.19.0.jar
proto-google-common-protos-1.12.0.jar
-protobuf-java-3.4.0.jar
+protobuf-java-3.11.4.jar
+protobuf-java-util-3.11.4.jar
rank-eval-client-6.3.2.jar
reactive-streams-1.0.2.jar
reflectasm-1.11.7.jar