diff --git a/.github/workflows/quickstart_opentelemetry_ci.yml b/.github/workflows/quickstart_opentelemetry_ci.yml new file mode 100644 index 0000000000..1d6003ac87 --- /dev/null +++ b/.github/workflows/quickstart_opentelemetry_ci.yml @@ -0,0 +1,15 @@ + +name: WildFly OpenTelemetry Quickstart CI + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + paths: + - 'micrometer/**' + - '.github/workflows/quickstart_ci.yml' +jobs: + call-quickstart_ci: + uses: ./.github/workflows/quickstart_ci.yml + with: + QUICKSTART_PATH: opentelemetry-tracing + MICROPROFILE: false diff --git a/opentelemetry-tracing/README.adoc b/opentelemetry-tracing/README.adoc new file mode 100644 index 0000000000..5da23c922d --- /dev/null +++ b/opentelemetry-tracing/README.adoc @@ -0,0 +1,157 @@ +include::../shared-doc/attributes.adoc[] + += observability-tracing: OpenTelemetry Tracing QuickStart +:author: Jason Lee +:level: Beginner +:technologies: OpenTelemetry Tracing +:custom-bootable-jar-layers: {lt}layer{gt}opentelemetry{lt}/layer{gt} + +[abstract] +The `observability-tracing` quickstart demonstrates the use of the OpenTelemetry tracing specification in {productName}. + +:standalone-server-type: default +:archiveType: war +:archiveName: {artifactId} +:restoreScriptName: restore-configuration.cli + + +== What is it? + +OpenTelemetry is a set of APIs, SDKs, tooling and integrations that are designed for the creation and management of +telemetry data such as traces, metrics, and logs. OpenTelemetry support in {productName} is limited to traces only. +{productName}'s support of OpenTelemetry provides out of the box tracing of Jakarta REST calls, as well as +container-managed Jakarta REST Client invocations. Additionally, applications can have injected a `Tracer` instance +in order to create and manage custom `Span`s as a given application may require. By default, these traces are exported +to a Jaeger instance listening on the same host. + +== Architecture + +In this quickstart, we have a collection of CDI beans and REST endpoints that expose functionalities of the OpenTelemetry support in {productName}. + +// System Requirements +include::../shared-doc/system-requirements.adoc[leveloffset=+1] + +// Use of {jbossHomeName} +include::../shared-doc/use-of-jboss-home-name.adoc[leveloffset=+1] + +== Steps + +[[configure_the_server]] +=== Configure the Server + +You enable Micrometer by running JBoss CLI commands. For your convenience, this quickstart batches the commands into a `configure-micrometer.cli` script provided in the root directory of this quickstart. + +. Before you begin, make sure you do the following: + +* xref:back_up_standalone_server_configuration[Back up the {productName} standalone server configuration] as described above. +* xref:start_the_eap_standalone_server[Start the {productName} server with the standalone default profile] as described above. + +. Review the `configure-micrometer.cli` file in the root of this quickstart directory. This script adds the configuration that enables Micrometer for the quickstart components. Comments in the script describe the purpose of each block of commands. +. Open a new terminal, navigate to the root directory of this quickstart, and run the following command, replacing `__{jbossHomeName}__` with the path to your server: ++ +[source,subs="+quotes,attributes+",options="nowrap"] +---- +$ __{jbossHomeName}__/bin/jboss-cli.sh --connect --file=configure-opentelemetry.cli +---- ++ +NOTE: For Windows, use the `__{jbossHomeName}__\bin\jboss-cli.bat` script. ++ + +You should see the following result when you run the script: ++ +[source,options="nowrap"] +---- +The batch executed successfully +process-state: reload-required +---- + +. You'll need to reload the configuration after that: ++ +[source,subs="+quotes,attributes+",options="nowrap"] +---- +$ __{jbossHomeName}__/bin/jboss-cli.sh --connect --commands=reload +---- + +== Running the Jaeger service + +To collect the traces from our application we will be using the Jaeger tracing system. To run the Jaeger service we will use its Docker container. + +Run the following command, or execute `jaeger.sh` in the project directory: + +[source,bash] +---- +include::jaeger.sh[] +---- + +NOTE: If this is your first time running Jaeger in this manner, this can take a minute. + +Now you can access `http://localhost:16686` in your browser to see the Jaeger UI console. + +Now we can start adding our custom spans from our application. + +=== Creating traces + +==== Implicit tracing of REST resources + +The OpenTelemetry support in {productName} provides an implicit tracing of all Jakarta REST resources. That means that for all applications, {productName} will automatically: + +* extract the Span context from the incoming Jakarta REST request +* start a new Span on incoming Jakarta REST request and close it when the request is completed +* inject Span context to any outgoing Jakarta REST request +* start a Span for any outgoing Jakarta REST request and finish the Span when the request is completed + +==== Explicit tracing + +The OpenTelemetry API also supports explicit tracing should your application required it: + +[source,java] +----- +include::src/main/java/org/wildfly/quickstarts/opentelemetry/ExplicitlyTracedBean.java[] +----- + +include::../shared-doc/build-and-deploy-the-quickstart.adoc[leveloffset=+1] + +== Access the quickstart application + +You can either access the application via your browser at http://localhost:8080/opentelemetry-tracing/hello/implicit-trace[], or http://localhost:8080/opentelemetry-tracing/hello/explicit-trace[]. You can also access it from the command line: + +[source,bash] +---- +$ curl http://localhost:8080/opentelemetry-tracing/hello/implicit-trace +$ curl http://localhost:8080/opentelemetry-tracing/hello/explicit-trace +---- + +Either endpoing should return a simple document: + +[source] +----- +hello +----- + +=== View the traces + +You can view the traces by accessing the Jaeger http://localhost:16686/[console]. + +// Server Distribution Testing +include::../shared-doc/run-integration-tests-with-server-distribution.adoc[leveloffset=+2] +// Undeploy the Quickstart +include::../shared-doc/undeploy-the-quickstart.adoc[leveloffset=+2] +// Restore the {productName} Standalone Server Configuration +include::../shared-doc/restore-standalone-server-configuration.adoc[leveloffset=+2] +// Restore the {productName} Standalone Server Configuration Manually +include::../shared-doc/restore-standalone-server-configuration-manual.adoc[leveloffset=+3] +// Bootable JAR +include::../shared-doc/build-and-run-the-quickstart-with-bootable-jar.adoc[leveloffset=+1] +// OpenShift +include::../shared-doc/build-and-run-the-quickstart-with-openshift.adoc[leveloffset=+1] +// Build and run sections for other environments/builds +ifndef::ProductRelease,EAPXPRelease[] +include::../shared-doc/build-and-run-the-quickstart-with-provisioned-server.adoc[leveloffset=+1] +endif::[] + +== Conclusion + +OpenTelemetry Tracing provides the mechanisms for your application to participate +in the distributed tracing with minimal effort on the application side. The Jakarta REST +resources are always traced by default, but the specification allows you to create +individual spans directly with the CDI injection of the `io.opentelemetry.api.trace.Tracer`. diff --git a/opentelemetry-tracing/charts/helm.yaml b/opentelemetry-tracing/charts/helm.yaml new file mode 100644 index 0000000000..44a27be81b --- /dev/null +++ b/opentelemetry-tracing/charts/helm.yaml @@ -0,0 +1,6 @@ +build: + uri: https://github.com/wildfly/quickstart.git + ref: main + contextDir: opentelemetry-tracing +deploy: + replicas: 1 diff --git a/opentelemetry-tracing/configure-opentelemetry.cli b/opentelemetry-tracing/configure-opentelemetry.cli new file mode 100644 index 0000000000..54ca8695c9 --- /dev/null +++ b/opentelemetry-tracing/configure-opentelemetry.cli @@ -0,0 +1,6 @@ +# CLI script to enable OpenTelemetry for the quickstart application in the application server +/extension=org.wildfly.extension.opentelemetry:add() +/subsystem=opentelemetry:add() + +# Reload the server configuration +reload diff --git a/opentelemetry-tracing/jaeger.sh b/opentelemetry-tracing/jaeger.sh new file mode 100755 index 0000000000..c9b26b93c7 --- /dev/null +++ b/opentelemetry-tracing/jaeger.sh @@ -0,0 +1,11 @@ +docker run \ + -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ + -p 5775:5775/udp \ + -p 6831:6831/udp \ + -p 6832:6832/udp \ + -p 5778:5778 \ + -p 16686:16686 \ + -p 14268:14268 \ + -p 14250:14250 \ + -p 9411:9411 \ + jaegertracing/all-in-one:latest diff --git a/opentelemetry-tracing/pom.xml b/opentelemetry-tracing/pom.xml new file mode 100644 index 0000000000..d24957d807 --- /dev/null +++ b/opentelemetry-tracing/pom.xml @@ -0,0 +1,291 @@ + + 4.0.0 + + org.wildfly.quickstarts + wildfly-quickstart-parent + + 5 + + + + opentelemetry-tracing + 31.0.0.Beta1-SNAPSHOT + war + + Quickstart: opentelemetry-tracing + + + + 30.0.0.Final + + ${version.server} + 4.2.0.Final + 10.0.0.Final + 4.0.0.Final + + + + + jboss-public-maven-repository + JBoss Public Maven Repository + https://repository.jboss.org/nexus/content/groups/public/ + + true + never + + + true + never + + default + + + redhat-ga-maven-repository + Red Hat GA Maven Repository + https://maven.repository.redhat.com/ga/ + + true + never + + + true + never + + default + + + + + + jboss-public-maven-repository + JBoss Public Maven Repository + https://repository.jboss.org/nexus/content/groups/public/ + + true + + + true + + + + redhat-ga-maven-repository + Red Hat GA Maven Repository + https://maven.repository.redhat.com/ga/ + + true + + + true + + + + + + + + org.wildfly.bom + wildfly-ee-with-tools + ${version.bom.ee} + pom + import + + + + + org.wildfly + wildfly-common-expansion-dependency-management + ${version.server} + pom + import + + + + + + + + jakarta.inject + jakarta.inject-api + provided + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + + jakarta.ws.rs + jakarta.ws.rs-api + provided + + + + io.opentelemetry + opentelemetry-api + provided + + + + io.opentelemetry + opentelemetry-context + provided + + + + + junit + junit + test + + + + + + ${project.artifactId} + + + + org.wildfly.plugins + wildfly-maven-plugin + ${version.plugin.wildfly} + + + org.wildfly.plugins + wildfly-jar-maven-plugin + ${version.plugin.wildfly-jar} + + + + + + + + provisioned-server + + + + org.wildfly.plugins + wildfly-maven-plugin + + + + org.wildfly:wildfly-galleon-pack:${version.server} + + + + + cdi + jaxrs-server + opentelemetry + + + ROOT.war + + + + + package + + + + + + + + + + bootable-jar + + + + org.wildfly.plugins + wildfly-jar-maven-plugin + + wildfly@maven(org.jboss.universe:community-universe)#${version.server} + + cdi + jaxrs-server + opentelemetry + + + true + + + + + + package + + + + + + + + + + openshift + + + + org.wildfly.plugins + wildfly-maven-plugin + + + + org.wildfly:wildfly-galleon-pack:${version.server} + + + org.wildfly.cloud:wildfly-cloud-galleon-pack:${version.pack.cloud} + + + + cdi + jaxrs-server + opentelemetry + + ROOT.war + + + + + package + + + + + + + + + + integration-testing + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + **/*IT + + + + + + integration-test + + + + + + + + + diff --git a/opentelemetry-tracing/restore-configuration.cli b/opentelemetry-tracing/restore-configuration.cli new file mode 100644 index 0000000000..102a792b25 --- /dev/null +++ b/opentelemetry-tracing/restore-configuration.cli @@ -0,0 +1,8 @@ +# CLI script to restore the application server configuration that was modified to run the quickstart + +# Remove the WildFly OpenTelemetry extension +/subsystem=opentelemetry:remove() +/extension=org.wildfly.extension.opentelemetry:remove() + +# Reload the server configuration +reload diff --git a/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/ExplicitlyTracedBean.java b/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/ExplicitlyTracedBean.java new file mode 100644 index 0000000000..dfffb74836 --- /dev/null +++ b/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/ExplicitlyTracedBean.java @@ -0,0 +1,31 @@ +package org.wildfly.quickstarts.opentelemetry; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; + +@RequestScoped +public class ExplicitlyTracedBean { + + @Inject + private Tracer tracer; + + public String getHello() { + Span prepareHelloSpan = tracer.spanBuilder("prepare-hello").startSpan(); + prepareHelloSpan.makeCurrent(); + + String hello = "hello"; + + Span processHelloSpan = tracer.spanBuilder("process-hello").startSpan(); + processHelloSpan.makeCurrent(); + + hello = hello.toUpperCase(); + + processHelloSpan.end(); + prepareHelloSpan.end(); + + return hello; + } +} diff --git a/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/JakartaRestApplication.java b/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/JakartaRestApplication.java new file mode 100644 index 0000000000..2647df706a --- /dev/null +++ b/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/JakartaRestApplication.java @@ -0,0 +1,10 @@ +package org.wildfly.quickstarts.opentelemetry; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationScoped +@ApplicationPath("/") +public class JakartaRestApplication extends Application { +} diff --git a/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/TracedResource.java b/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/TracedResource.java new file mode 100644 index 0000000000..09ebe7b169 --- /dev/null +++ b/opentelemetry-tracing/src/main/java/org/wildfly/quickstarts/opentelemetry/TracedResource.java @@ -0,0 +1,54 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2020, Red Hat, Inc. and/or its affiliates, and individual + * contributors by the @authors tag. See the copyright.txt in the + * distribution for a full listing of individual contributors. + * + * Licensed 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.wildfly.quickstarts.opentelemetry; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +@Path("/") +@RequestScoped +public class TracedResource { + public static final String TRACE_IMPLICIT = "/implicit-trace"; + public static final String TRACE_EXPLICIT = "/explicit-trace"; + + @Inject + private ExplicitlyTracedBean tracedBean; + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String getRootResponse() { + return "OpenTelemetry Tracing quickstart deployed successfully. You can find the available operations in the included README file."; + } + + @GET + @Path(TRACE_IMPLICIT) + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "hello"; + } + + @GET + @Path(TRACE_EXPLICIT) + @Produces(MediaType.TEXT_PLAIN) + public String cdiHello() { + return tracedBean.getHello(); + } +} diff --git a/opentelemetry-tracing/src/test/java/org/wildfly/quickstarts/opentelemetry/BasicRuntimeIT.java b/opentelemetry-tracing/src/test/java/org/wildfly/quickstarts/opentelemetry/BasicRuntimeIT.java new file mode 100644 index 0000000000..d7e78f4901 --- /dev/null +++ b/opentelemetry-tracing/src/test/java/org/wildfly/quickstarts/opentelemetry/BasicRuntimeIT.java @@ -0,0 +1,63 @@ +/* + * Copyright 2023 Red Hat, Inc. + * + * Licensed 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.wildfly.quickstarts.opentelemetry; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; + +import org.junit.Test; + +public class BasicRuntimeIT { + private static final String DEFAULT_SERVER_HOST = "http://localhost:8080/opentelemetry-tracing"; + + @Test + public void testHTTPEndpointIsAvailable() throws IOException, InterruptedException, URISyntaxException { + String applicationUrl = getApplicationUrl(); + + final HttpRequest request = HttpRequest.newBuilder() + .uri(new URI(applicationUrl)) + .GET() + .build(); + + final HttpResponse response = getHttpClient().send(request, HttpResponse.BodyHandlers.ofString()); + assertEquals(200, response.statusCode()); + } + + static String getApplicationUrl() { + String serverHost = System.getenv("SERVER_HOST"); + if (serverHost == null) { + serverHost = System.getProperty("server.host"); + } + if (serverHost == null) { + serverHost = DEFAULT_SERVER_HOST; + } + return serverHost; + } + + static HttpClient getHttpClient() { + return HttpClient.newBuilder() + .followRedirects(HttpClient.Redirect.ALWAYS) + .connectTimeout(Duration.ofMinutes(1)) + .build(); + } +} diff --git a/opentelemetry-tracing/src/test/java/org/wildfly/quickstarts/opentelemetry/OpenTelemetryIT.java b/opentelemetry-tracing/src/test/java/org/wildfly/quickstarts/opentelemetry/OpenTelemetryIT.java new file mode 100644 index 0000000000..c103dd3c19 --- /dev/null +++ b/opentelemetry-tracing/src/test/java/org/wildfly/quickstarts/opentelemetry/OpenTelemetryIT.java @@ -0,0 +1,47 @@ +/* + * Copyright 2023 Red Hat, Inc. + * + * Licensed 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.wildfly.quickstarts.opentelemetry; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import org.junit.Test; + +public class OpenTelemetryIT { + @Test + public void testImplicit() throws IOException, InterruptedException, URISyntaxException { + String applicationUrl = BasicRuntimeIT.getApplicationUrl(); + + final HttpClient client = BasicRuntimeIT.getHttpClient(); + final HttpRequest implicit = HttpRequest.newBuilder().uri(new URI(applicationUrl + "/implicit-trace")).GET().build(); + assertEquals(200, client.send(implicit, HttpResponse.BodyHandlers.ofString()).statusCode()); + } + + @Test + public void testExplicit() throws IOException, InterruptedException, URISyntaxException { + String applicationUrl = BasicRuntimeIT.getApplicationUrl(); + + final HttpClient client = BasicRuntimeIT.getHttpClient(); + final HttpRequest implicit = HttpRequest.newBuilder().uri(new URI(applicationUrl + "/explicit-trace")).GET().build(); + assertEquals(200, client.send(implicit, HttpResponse.BodyHandlers.ofString()).statusCode()); + } +} diff --git a/pom.xml b/pom.xml index d315311f55..6385d35bdf 100644 --- a/pom.xml +++ b/pom.xml @@ -339,6 +339,7 @@ microprofile-reactive-messaging-kafka microprofile-rest-client numberguess + opentelemetry-tracing remote-helloworld-mdb security-domain-to-domain servlet-async