Skip to content

Commit

Permalink
[WFLY-15849] OpenTelemetry Quickstart
Browse files Browse the repository at this point in the history
  • Loading branch information
jasondlee committed Jul 31, 2023
1 parent 147fdac commit b8feea5
Show file tree
Hide file tree
Showing 15 changed files with 1,183 additions and 0 deletions.
285 changes: 285 additions & 0 deletions opentelemetry-tracing/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
include::../shared-doc/attributes.adoc[]

= observability-tracing: OpenTelemetry Tracing QuickStart
:author: Jason Lee
:level: Beginner
:technologies: OpenTelemetry Tracing

[abstract]
The `observability-tracing` quickstart demonstrates the use of the OpenTelemetry tracing specification in {productName}.

:standalone-server-type: default
:archiveType: war
:archiveName: {artifactId}
:uses-jaeger:


== 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]

[[start_the_eap_standalone_server]]
== Start the {productName} Standalone Server
include::../shared-doc/define-standalone-server-attributes.adoc[]

. Open a terminal and navigate to the root of the {productName} directory.
. Start the {productName} server with the {serverProfile} by typing the following command.

[source,subs="+quotes,attributes+",options="nowrap"]
----
$ __{jbossHomeName}__/bin/standalone.sh {serverArguments}
----

By default, OpenTelemetry is not enabled, so we need to enable that now:

[source,subs="+quotes,attributes+",options="nowrap"]
----
$ __{jbossHomeName}__/bin/jboss-cli.sh -c << EOL
/extension=org.wildfly.extension.opentelemetry:add()
/subsystem=opentelemetry:add()
/subsystem=opentelemetry:write-attribute(name=span-processor-type,value=simple)
reload
EOL
----


== Solution

We recommend that you follow the instructions that
<<creating-new-project, create the application step by step>>. However, you can
also go right to the completed example which is available in this directory.

// Build and Deploy the Quickstart
include::../shared-doc/build-and-deploy-the-quickstart.adoc[leveloffset=+1]

// Undeploy the Quickstart
include::../shared-doc/undeploy-the-quickstart.adoc[leveloffset=+1]

// Run the Quickstart in Red Hat CodeReady Studio or Eclipse
include::../shared-doc/run-the-quickstart-in-jboss-developer-studio.adoc[leveloffset=+1]

[[creating-new-project]]
== Creating the Maven Project

[source,options="nowrap"]
----
mvn archetype:generate \
-DgroupId=org.wildfly.quickstarts \
-DartifactId=opentelemetry-tracing \
-DinteractiveMode=false \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-simple
cd opentelemetry-tracing
----

Open the project in your favourite IDE.

The first thing to do is to setup our dependencies. In order to use the same versions that ship with WildFly, add the
following `dependencyManagement` section to your `pom.xml`:

[source,xml,subs="attributes+"]
-----
<dependencyManagement>
<dependencies>
<!-- This BOM makes most of the dependencies from WildFly available for normal (non-plugin use) -->
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-standard-ee-bom</artifactId>
<version>${version.server.bom}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-common-expansion-dependency-management</artifactId>
<version>${version.server.bom}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- importing the ee-with-tools BOM adds specs and other useful artifacts as managed dependencies -->
<dependency>
<groupId>org.wildfly.bom</groupId>
<artifactId>wildfly-ee-with-tools</artifactId>
<version>${version.server.bom}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
-----

Next, replace the `dependencies` section in your `pom.xml` with the following:

[source,xml,subs="attributes+"]
----
<dependencies>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Import the Jakarta REST API, we use provided scope as the API is included in the server -->
<dependency>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-context</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.arquillian.junit</groupId>
<artifactId>arquillian-junit-container</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
----

All dependencies can have provided scope.

Now we need to modify the `properties`:

[source,xml]
----
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
<!-- The versions for BOMs, Dependencies and Plugins -->
<version.server.bom>29.0.0.Beta1</version.server.bom>
<version.server.bootable-jar>${version.server.bom}</version.server.bootable-jar>
<version.microprofile.bom>${version.server.bom}</version.microprofile.bom>
<version.wildfly-jar.maven.plugin>7.0.0.Final</version.wildfly-jar.maven.plugin>
<version.jkube.maven.plugin>1.0.1</version.jkube.maven.plugin>
</properties>
----

As we are going to be deploying this application to the {productName} server, let's
also add a maven plugin that will simplify the deployment operations (you can replace the generated build section):

[source,xml]
----
<build>
<!-- Set the name of the archive -->
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- Allows to use mvn wildfly:deploy -->
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
----

== Writing the application

As this is a Jakarta REST application we need to create an application class.
Create `JakartaRestApplication` with the
following content:

NOTE: The new file should be created in
`src/main/java/org/wildfly/quickstarts/opentelemetry/JakartaRestApplication.java`.

[source,java]
----
include::src/main/java/org/wildfly/quickstarts/opentelemetry/JakartaRestApplication.java[]
----

Now we are ready to start working with OpenTelemetry.

== 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

That said, notice in `ExplicitlyTracedBean` that we inject the `Tracer` and create several spans. If you have no need for custom spans, then there is no need to inject the `Tracer`. Just build and deploy your Jakarta REST application, and {productName} will do the rest for you.

== 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.

[NOTE]
=====
To avoid the need to use superuser privileges, we will use http://podman.io[Podman], which is, for most uses, a drop-in replacement for Docker. If you already have Docker installed and would prefer to use that, simply replace `podman` with `docker`.
If you don't have Podman installed on your machine please follow the instructions at https://podman.io/getting-started/installation.html.
=====

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.

== Running the applications

=== Build and deploy the application

[source,options="nowrap"]
----
$ mvn clean package wildfly:deploy
----

and make a few requests to `TracedResource` by accessing `http://localhost:8080/opentelemetry-tracing/hello/traced` or
``http://localhost:8080/opentelemetry-tracing/hello/cdi-trace` in your browser or request the same URLs via curl from a
terminal window. You will see the spans created in the Jaeger console (`http://localhost:16686`) under the service
`opentelemtry-tracing.war`.

Congratulations! We have tracing in our application with both implicit and explicit instrumentation. As stated, if you're not
interested in custom spans, all you need to do to get tracing of your Jakarta REST application is to enable the subsystem.

//Bootable JAR
include::../shared-doc/build-and-run-the-quickstart-with-bootable-jar.adoc[leveloffset=+1]

== 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`.
14 changes: 14 additions & 0 deletions opentelemetry-tracing/configure-opentelemetry.cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# CLI script to configure OpenTelemetry for the quickstart application in the application server

if (outcome != success) of /extension=org.wildfly.extension.opentelemetry:read-resource
/extension=org.wildfly.extension.opentelemetry:add()
end-if

if (outcome != success) of /subsystem=opentelemetry:read-resource
/subsystem=opentelemetry:add()
end-if

# Set the batch delay to 0 to speed up export times for testing
/subsystem=opentelemetry:write-attribute(name=batch-delay,value=1)

reload
11 changes: 11 additions & 0 deletions opentelemetry-tracing/jaeger.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
podman 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
Loading

0 comments on commit b8feea5

Please sign in to comment.