Skip to content

Commit 157d5be

Browse files
committed
Auto-validation for tracing sample.
1 parent 9296a83 commit 157d5be

File tree

5 files changed

+143
-13
lines changed

5 files changed

+143
-13
lines changed

.github/workflows/validate.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ jobs:
112112
working-directory: ./examples
113113
run: |
114114
mm.py ./src/main/java/io/dapr/examples/invoke/grpc/README.md
115+
- name: Validate tracing example
116+
working-directory: ./examples
117+
run: |
118+
mm.py ./src/main/java/io/dapr/examples/tracing/README.md
115119
- name: Validate expection handling example
116120
working-directory: ./examples
117121
run: |

examples/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@
7474
<artifactId>spring-boot-autoconfigure</artifactId>
7575
<version>2.3.5.RELEASE</version>
7676
</dependency>
77+
<dependency>
78+
<groupId>com.jayway.jsonpath</groupId>
79+
<artifactId>json-path</artifactId>
80+
<version>2.4.0</version>
81+
</dependency>
7782
<dependency>
7883
<groupId>io.opentelemetry</groupId>
7984
<artifactId>opentelemetry-sdk</artifactId>

examples/src/main/java/io/dapr/examples/tracing/InvokeClient.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,15 @@ public static void main(String[] args) throws Exception {
6666
}).subscriberContext(getReactorContext()).block();
6767
}
6868
}
69-
70-
// This is an example, so for simplicity we are just exiting here.
71-
// Normally a dapr app would be a web service and not exit main.
72-
System.out.println("Done");
7369
}
7470
span.end();
7571
shutdown();
72+
System.out.println("Done");
7673
}
7774

78-
private static void shutdown() {
75+
private static void shutdown() throws Exception {
7976
OpenTelemetrySdk.getGlobalTracerManagement().shutdown();
77+
Validation.validate();
8078
}
8179

82-
8380
}

examples/src/main/java/io/dapr/examples/tracing/README.md

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,19 @@ The instrumentation for the service happens via the `OpenTelemetryIterceptor` cl
126126

127127
Use the follow command to execute the service:
128128

129-
```sh
129+
<!-- STEP
130+
name: Run demo service
131+
expected_stdout_lines:
132+
background: true
133+
sleep: 20
134+
-->
135+
136+
```bash
130137
dapr run --app-id tracingdemo --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3000
131138
```
132139

140+
<!-- END_STEP -->
141+
133142
Once running, the TracingDemoService is now ready to be invoked by Dapr.
134143

135144
### Running the Demo middle service app
@@ -208,10 +217,19 @@ public class OpenTelemetryConfig {
208217

209218
Use the follow command to execute the service:
210219

211-
```sh
220+
<!-- STEP
221+
name: Run proxy service
222+
expected_stdout_lines:
223+
background: true
224+
sleep: 20
225+
-->
226+
227+
```bash
212228
dapr run --app-id tracingdemoproxy --app-port 3001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3001
213229
```
214230

231+
<!-- END_STEP -->
232+
215233
### Running the InvokeClient app
216234

217235
This sample code uses the Dapr SDK for invoking two remote methods (`proxy_echo` and `proxy_sleep`). It is also instrumented with OpenTelemetry. See the code snippet below:
@@ -247,13 +265,10 @@ private static final String SERVICE_APP_ID = "tracingdemoproxy";
247265
}).subscriberContext(getReactorContext()).block();
248266
}
249267
}
250-
251-
// This is an example, so for simplicity we are just exiting here.
252-
// Normally a dapr app would be a web service and not exit main.
253-
System.out.println("Done");
254268
}
255269
span.end();
256270
shutdown();
271+
System.out.println("Done");
257272
}
258273
///...
259274
}
@@ -262,9 +277,21 @@ private static final String SERVICE_APP_ID = "tracingdemoproxy";
262277
The class knows the app id for the remote application. It uses `invokeMethod` method to invoke API calls on the service endpoint. The request object includes an instance of `io.opentelemetry.context.Context` for the proper tracing headers to be propagated.
263278

264279
Execute the follow script in order to run the InvokeClient example, passing two messages for the remote method:
265-
```sh
280+
281+
<!-- STEP
282+
name: Run demo client
283+
expected_stdout_lines:
284+
- '== APP == Done'
285+
background: true
286+
sleep: 20
287+
-->
288+
289+
```bash
266290
dapr run -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.InvokeClient "message one" "message two"
267291
```
292+
293+
<!-- END_STEP -->
294+
268295
Once running, the output should display the messages sent from invoker in the demo service output as follows:
269296

270297
![exposeroutput](https://raw.githubusercontent.com/dapr/java-sdk/master/examples/src/main/resources/img/exposer-service.png)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation and Dapr Contributors.
3+
* Licensed under the MIT License.
4+
*/
5+
6+
package io.dapr.examples.tracing;
7+
8+
import com.jayway.jsonpath.DocumentContext;
9+
import com.jayway.jsonpath.JsonPath;
10+
import net.minidev.json.JSONArray;
11+
import okhttp3.HttpUrl;
12+
import okhttp3.OkHttpClient;
13+
import okhttp3.Request;
14+
import okhttp3.Response;
15+
16+
/**
17+
* Class used to verify that traces are present as expected.
18+
*/
19+
final class Validation {
20+
21+
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient();
22+
23+
public static final String JSONPATH_PROXY_ECHO_SPAN_ID =
24+
"$..[?(@.parentId=='%s' && @.name=='calllocal/tracingdemoproxy/proxy_echo')]['id']";
25+
26+
public static final String JSONPATH_ECHO_SPAN_ID =
27+
"$..[?(@.parentId=='%s' && @.name=='calllocal/tracingdemo/echo')]['id']";
28+
29+
public static final String JSONPATH_PROXY_SLEEP_SPAN_ID =
30+
"$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracingdemoproxy/proxy_sleep')]['id']";
31+
32+
public static final String JSONPATH_SLEEP_SPAN_ID =
33+
"$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracingdemo/sleep')]['id']";
34+
35+
static void validate() throws Exception {
36+
// Must wait for some time to make sure Zipkin receives all spans.
37+
Thread.sleep(5000);
38+
HttpUrl.Builder urlBuilder = new HttpUrl.Builder();
39+
urlBuilder.scheme("http")
40+
.host("localhost")
41+
.port(9411);
42+
urlBuilder.addPathSegments("api/v2/traces");
43+
Request.Builder requestBuilder = new Request.Builder()
44+
.url(urlBuilder.build());
45+
requestBuilder.method("GET", null);
46+
47+
Request request = requestBuilder.build();
48+
49+
Response response = HTTP_CLIENT.newCall(request).execute();
50+
DocumentContext documentContext = JsonPath.parse(response.body().string());
51+
String mainSpanId = readOne(documentContext, "$..[?(@.name == \"example's main\")]['id']").toString();
52+
53+
// Validate echo
54+
assertCount(documentContext,
55+
String.format(JSONPATH_PROXY_ECHO_SPAN_ID, mainSpanId),
56+
2);
57+
String proxyEchoSpanId = readOne(documentContext,
58+
String.format(JSONPATH_PROXY_ECHO_SPAN_ID, mainSpanId))
59+
.toString();
60+
String proxyEchoSpanId2 = readOne(documentContext,
61+
String.format(JSONPATH_PROXY_ECHO_SPAN_ID, proxyEchoSpanId))
62+
.toString();
63+
readOne(documentContext,
64+
String.format(JSONPATH_ECHO_SPAN_ID, proxyEchoSpanId2));
65+
66+
// Validate sleep
67+
assertCount(documentContext,
68+
String.format(JSONPATH_PROXY_SLEEP_SPAN_ID, mainSpanId),
69+
2);
70+
String proxySleepSpanId = readOne(documentContext,
71+
String.format(JSONPATH_PROXY_SLEEP_SPAN_ID, mainSpanId))
72+
.toString();
73+
String proxySleepSpanId2 = readOne(documentContext,
74+
String.format(JSONPATH_PROXY_SLEEP_SPAN_ID, proxySleepSpanId))
75+
.toString();
76+
readOne(documentContext,
77+
String.format(JSONPATH_SLEEP_SPAN_ID, proxySleepSpanId2));
78+
}
79+
80+
private static Object readOne(DocumentContext documentContext, String path) {
81+
JSONArray arr = documentContext.read(path);
82+
if (arr.size() == 0) {
83+
throw new RuntimeException("No record found for " + path);
84+
}
85+
86+
return arr.get(0);
87+
}
88+
89+
private static void assertCount(DocumentContext documentContext, String path, int expectedCount) {
90+
JSONArray arr = documentContext.read(path);
91+
if (arr.size() != expectedCount) {
92+
throw new RuntimeException(
93+
String.format("Unexpected count %d vs expected %d for %s", arr.size(), expectedCount, path));
94+
}
95+
}
96+
97+
}

0 commit comments

Comments
 (0)