Skip to content

Auto-validation for tracing sample. #508

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ jobs:
working-directory: ./examples
run: |
mm.py ./src/main/java/io/dapr/examples/invoke/grpc/README.md
- name: Validate tracing example
working-directory: ./examples
run: |
mm.py ./src/main/java/io/dapr/examples/tracing/README.md
- name: Validate expection handling example
working-directory: ./examples
run: |
Expand Down
5 changes: 5 additions & 0 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,15 @@ public static void main(String[] args) throws Exception {
}).subscriberContext(getReactorContext()).block();
}
}

// This is an example, so for simplicity we are just exiting here.
// Normally a dapr app would be a web service and not exit main.
System.out.println("Done");
}
span.end();
shutdown();
System.out.println("Done");
}

private static void shutdown() {
private static void shutdown() throws Exception {
OpenTelemetrySdk.getGlobalTracerManagement().shutdown();
Validation.validate();
}


}
41 changes: 34 additions & 7 deletions examples/src/main/java/io/dapr/examples/tracing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,19 @@ The instrumentation for the service happens via the `OpenTelemetryIterceptor` cl

Use the follow command to execute the service:

```sh
<!-- STEP
name: Run demo service
expected_stdout_lines:
background: true
sleep: 20
-->

```bash
dapr run --app-id tracingdemo --app-port 3000 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3000
```

<!-- END_STEP -->

Once running, the TracingDemoService is now ready to be invoked by Dapr.

### Running the Demo middle service app
Expand Down Expand Up @@ -208,10 +217,19 @@ public class OpenTelemetryConfig {

Use the follow command to execute the service:

```sh
<!-- STEP
name: Run proxy service
expected_stdout_lines:
background: true
sleep: 20
-->

```bash
dapr run --app-id tracingdemoproxy --app-port 3001 -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.TracingDemoService -p 3001
```

<!-- END_STEP -->

### Running the InvokeClient app

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:
Expand Down Expand Up @@ -247,13 +265,10 @@ private static final String SERVICE_APP_ID = "tracingdemoproxy";
}).subscriberContext(getReactorContext()).block();
}
}

// This is an example, so for simplicity we are just exiting here.
// Normally a dapr app would be a web service and not exit main.
System.out.println("Done");
}
span.end();
shutdown();
System.out.println("Done");
}
///...
}
Expand All @@ -262,9 +277,21 @@ private static final String SERVICE_APP_ID = "tracingdemoproxy";
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.

Execute the follow script in order to run the InvokeClient example, passing two messages for the remote method:
```sh

<!-- STEP
name: Run demo client
expected_stdout_lines:
- '== APP == Done'
background: true
sleep: 20
-->

```bash
dapr run -- java -jar target/dapr-java-sdk-examples-exec.jar io.dapr.examples.tracing.InvokeClient "message one" "message two"
```

<!-- END_STEP -->

Open the `tracingdemo` console and check the output as follows:

```txt
Expand Down
97 changes: 97 additions & 0 deletions examples/src/main/java/io/dapr/examples/tracing/Validation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) Microsoft Corporation and Dapr Contributors.
* Licensed under the MIT License.
*/

package io.dapr.examples.tracing;

import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import net.minidev.json.JSONArray;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
* Class used to verify that traces are present as expected.
*/
final class Validation {

private static final OkHttpClient HTTP_CLIENT = new OkHttpClient();

public static final String JSONPATH_PROXY_ECHO_SPAN_ID =
"$..[?(@.parentId=='%s' && @.name=='calllocal/tracingdemoproxy/proxy_echo')]['id']";

public static final String JSONPATH_ECHO_SPAN_ID =
"$..[?(@.parentId=='%s' && @.name=='calllocal/tracingdemo/echo')]['id']";

public static final String JSONPATH_PROXY_SLEEP_SPAN_ID =
"$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracingdemoproxy/proxy_sleep')]['id']";

public static final String JSONPATH_SLEEP_SPAN_ID =
"$..[?(@.parentId=='%s' && @.duration > 1000000 && @.name=='calllocal/tracingdemo/sleep')]['id']";

static void validate() throws Exception {
// Must wait for some time to make sure Zipkin receives all spans.
Thread.sleep(5000);
HttpUrl.Builder urlBuilder = new HttpUrl.Builder();
urlBuilder.scheme("http")
.host("localhost")
.port(9411);
urlBuilder.addPathSegments("api/v2/traces");
Request.Builder requestBuilder = new Request.Builder()
.url(urlBuilder.build());
requestBuilder.method("GET", null);

Request request = requestBuilder.build();

Response response = HTTP_CLIENT.newCall(request).execute();
DocumentContext documentContext = JsonPath.parse(response.body().string());
String mainSpanId = readOne(documentContext, "$..[?(@.name == \"example's main\")]['id']").toString();

// Validate echo
assertCount(documentContext,
String.format(JSONPATH_PROXY_ECHO_SPAN_ID, mainSpanId),
2);
String proxyEchoSpanId = readOne(documentContext,
String.format(JSONPATH_PROXY_ECHO_SPAN_ID, mainSpanId))
.toString();
String proxyEchoSpanId2 = readOne(documentContext,
String.format(JSONPATH_PROXY_ECHO_SPAN_ID, proxyEchoSpanId))
.toString();
readOne(documentContext,
String.format(JSONPATH_ECHO_SPAN_ID, proxyEchoSpanId2));

// Validate sleep
assertCount(documentContext,
String.format(JSONPATH_PROXY_SLEEP_SPAN_ID, mainSpanId),
2);
String proxySleepSpanId = readOne(documentContext,
String.format(JSONPATH_PROXY_SLEEP_SPAN_ID, mainSpanId))
.toString();
String proxySleepSpanId2 = readOne(documentContext,
String.format(JSONPATH_PROXY_SLEEP_SPAN_ID, proxySleepSpanId))
.toString();
readOne(documentContext,
String.format(JSONPATH_SLEEP_SPAN_ID, proxySleepSpanId2));
}

private static Object readOne(DocumentContext documentContext, String path) {
JSONArray arr = documentContext.read(path);
if (arr.size() == 0) {
throw new RuntimeException("No record found for " + path);
}

return arr.get(0);
}

private static void assertCount(DocumentContext documentContext, String path, int expectedCount) {
JSONArray arr = documentContext.read(path);
if (arr.size() != expectedCount) {
throw new RuntimeException(
String.format("Unexpected count %d vs expected %d for %s", arr.size(), expectedCount, path));
}
}

}