Dice app for java (#2625)
Co-authored-by: Mateusz Rzeszutek <mrzeszutek@splunk.com> Co-authored-by: Phillip Carter <pcarter@fastmail.com>
This commit is contained in:
parent
28a1670271
commit
d373aa84f6
|
|
@ -1,138 +1,221 @@
|
|||
---
|
||||
title: Getting Started
|
||||
description: Get telemetry from a client-server app in less than 5 minutes!
|
||||
spelling: cSpell:ignore helloworld javaagent
|
||||
spelling: cSpell:ignore helloworld javaagent springframework autoreconfigure
|
||||
spelling: cSpell:ignore rolldice aarch Nanos darwin autoconfigure webmvc
|
||||
weight: 1
|
||||
---
|
||||
|
||||
In this page, you'll learn how to set up and get tracing telemetry from a simple
|
||||
hello-world client-server example.
|
||||
This page will show you how to get started with OpenTelemetry in Java.
|
||||
|
||||
You'll work with gRPC's [Java Quick start example][], which uses gRPC to
|
||||
communicate between the client and server. You can work through this page even
|
||||
if you aren't familiar with gRPC.
|
||||
You will learn how you can instrument a simple java application automatically,
|
||||
in such a way that traces, metrics and logs are emitted to the console.
|
||||
|
||||
## Get and run the example
|
||||
## Prerequisites
|
||||
|
||||
First, get and run the hello-world example without instrumentation:
|
||||
Ensure that you have the following installed locally:
|
||||
|
||||
1. [Get the example code.][]
|
||||
2. [Run the example:][] you should see the client output "Hello world".
|
||||
3. Stop the server before proceeding, if it is still running.
|
||||
- Java JDK
|
||||
- [Gradle](https://gradle.org/)
|
||||
|
||||
## Run the instrumented example
|
||||
## Example Application
|
||||
|
||||
The following example uses a basic spring boot application.
|
||||
|
||||
### Dependencies
|
||||
|
||||
Create a folder called `java-simple` and within that folder, create a file
|
||||
called `build.gradle.kts` with the following content:
|
||||
|
||||
```kotlin
|
||||
plugins {
|
||||
id("java")
|
||||
id("org.springframework.boot") version "3.0.6"
|
||||
id("io.spring.dependency-management") version "1.1.0"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.setSrcDirs(setOf("."))
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
}
|
||||
```
|
||||
|
||||
### Code
|
||||
|
||||
In that same folder, create a file called `DiceApplication.java` and add the
|
||||
following code to the file:
|
||||
|
||||
```java
|
||||
package otel;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DiceApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication app = new SpringApplication(DiceApplication.class);
|
||||
app.setBannerMode(Banner.Mode.OFF);
|
||||
app.run(args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create another file called `RollController.java` and add the following code to
|
||||
the file:
|
||||
|
||||
```java
|
||||
package otel;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class RollController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(RollController.class);
|
||||
|
||||
@GetMapping("/rolldice")
|
||||
public String index(@RequestParam("player") Optional<String> player) {
|
||||
int result = this.getRandomNumber(1, 6);
|
||||
if (player.isPresent()) {
|
||||
logger.info("{} is rolling the dice: {}", player.get(), result);
|
||||
} else {
|
||||
logger.info("Anonymous player is rolling the dice: {}", result);
|
||||
}
|
||||
return Integer.toString(result);
|
||||
}
|
||||
|
||||
public int getRandomNumber(int min, int max) {
|
||||
return ThreadLocalRandom.current().nextInt(min, max + 1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To test the application, build and run it:
|
||||
|
||||
```console
|
||||
gradle assemble
|
||||
java -jar ./build/libs/java-simple.jar
|
||||
```
|
||||
|
||||
## Instrumentation
|
||||
|
||||
Next, you'll use a [Java agent to automatically instrument](../automatic) the
|
||||
client and server at launch time. While you can [configure the Java agent][] in
|
||||
a number of ways, the steps below use environment variables.
|
||||
application at launch time. While you can [configure the Java agent][] in a
|
||||
number of ways, the steps below use environment variables.
|
||||
|
||||
1. Download [opentelemetry-javaagent.jar][] from [Releases][] of the
|
||||
`opentelemetry-java-instrumentation` repo. The JAR file contains the agent
|
||||
and all automatic instrumentation packages.
|
||||
{{% alert color="info" %}}<i class="fas fa-edit"></i> Take note of the path
|
||||
to the JAR file.{{% /alert %}}
|
||||
2. Set and export variables that specify the Java agent JAR and a [console
|
||||
exporter][], using a notation suitable for your shell/terminal environment
|
||||
— we illustrate a notation for bash-like shells:
|
||||
1. Download [opentelemetry-javaagent.jar][] from [Releases][] of the
|
||||
`opentelemetry-java-instrumentation` repo. The JAR file contains the agent
|
||||
and all automatic instrumentation packages:
|
||||
|
||||
```console
|
||||
$ export JAVA_OPTS="-javaagent:PATH/TO/opentelemetry-javaagent.jar"
|
||||
$ export OTEL_TRACES_EXPORTER=logging
|
||||
$ export OTEL_METRICS_EXPORTER=logging
|
||||
```
|
||||
```console
|
||||
curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
|
||||
```
|
||||
|
||||
{{% alert title="Important" color="warning" %}}Replace `PATH/TO` above, with
|
||||
your path to the JAR.{{% /alert %}}
|
||||
{{% alert color="info" %}}<i class="fas fa-edit"></i> Take note of the path
|
||||
to the JAR file.{{% /alert %}}
|
||||
|
||||
3. Run the **server** as a background process. For example, for bash-like
|
||||
shells run:
|
||||
2. Set and export variables that specify the Java agent JAR and a [console
|
||||
exporter][], using a notation suitable for your shell/terminal environment
|
||||
— we illustrate a notation for bash-like shells:
|
||||
|
||||
```console
|
||||
$ ./build/install/examples/bin/hello-world-server &
|
||||
[otel.javaagent 2022-03-19 13:38:16:712 +0000] [main] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 1.12.0
|
||||
Mar 19, 2022 1:38:18 PM io.grpc.examples.helloworld.HelloWorldServer start
|
||||
...
|
||||
```
|
||||
```console
|
||||
$ export JAVA_TOOL_OPTIONS="-javaagent:PATH/TO/opentelemetry-javaagent.jar" \
|
||||
OTEL_TRACES_EXPORTER=logging \
|
||||
OTEL_METRICS_EXPORTER=logging \
|
||||
OTEL_LOGS_EXPORTER=logging
|
||||
```
|
||||
|
||||
Note the output from the `otel.javaagent`.
|
||||
{{% alert title="Important" color="warning" %}}Replace `PATH/TO` above, with
|
||||
your path to the JAR.{{% /alert %}}
|
||||
|
||||
4. From the _same_ terminal, run the **client**:
|
||||
3. Run your **application** once again:
|
||||
|
||||
```console
|
||||
$ ./build/install/examples/bin/hello-world-client
|
||||
[otel.javaagent 2022-03-19 13:38:48:462 +0000] [main] INFO io.opentelemetry.javaagent.tooling.VersionLogger - opentelemetry-javaagent - version: 1.12.0
|
||||
Mar 19, 2022 1:38:50 PM io.grpc.examples.helloworld.HelloWorldClient greet
|
||||
INFO: Will try to greet world ...
|
||||
[Trace output elided -- see below for details]
|
||||
Mar 19, 2022 1:38:51 PM io.grpc.examples.helloworld.HelloWorldClient greet
|
||||
INFO: Greeting: Hello world
|
||||
```
|
||||
```console
|
||||
$ java -jar ./build/libs/java-simple.jar
|
||||
...
|
||||
```
|
||||
|
||||
5. Stop the server process. For example, for bash-like shells run:
|
||||
Note the output from the `otel.javaagent`.
|
||||
|
||||
```console
|
||||
$ jobs
|
||||
[1]+ Running ./build/install/examples/bin/hello-world-server &
|
||||
$ kill %1
|
||||
...
|
||||
*** server shut down
|
||||
```
|
||||
4. From _another_ terminal, send a request using `curl`:
|
||||
|
||||
At step 4, you should have seen trace output from the server and client that
|
||||
looks something like this (trace output is line-wrapped for convenience):
|
||||
```console
|
||||
$ curl localhost:8080/rolldice
|
||||
```
|
||||
|
||||
5. Stop the server process. For example, for bash-like shells run:
|
||||
|
||||
At step 4, you should have seen trace & log output from the server and client
|
||||
that looks something like this (trace output is line-wrapped for convenience):
|
||||
|
||||
```sh
|
||||
[otel.javaagent 2022-03-19 13:38:51:310 +0000] [grpc-default-executor-0] INFO
|
||||
io.opentelemetry.exporter.logging.LoggingSpanExporter -
|
||||
'helloworld.Greeter/SayHello' : 150407692a813ceb4e9f49a02c8b1fd0
|
||||
ee15310978e6f6d3 SERVER [tracer: io.opentelemetry.grpc-1.6:1.12.0]
|
||||
AttributesMap{data={net.transport=ip_tcp, rpc.grpc.status_code=0,
|
||||
rpc.service=helloworld.Greeter, thread.id=16, rpc.method=SayHello,
|
||||
rpc.system=grpc, net.peer.ip=127.0.0.1, thread.name=grpc-default-executor-0,
|
||||
net.peer.port=44186}, capacity=128, totalAddedValues=9}
|
||||
|
||||
[otel.javaagent 2022-03-19 13:38:51:368 +0000] [main] INFO
|
||||
io.opentelemetry.exporter.logging.LoggingSpanExporter -
|
||||
'helloworld.Greeter/SayHello' : 150407692a813ceb4e9f49a02c8b1fd0
|
||||
6ed56cd008f241c5 CLIENT [tracer: io.opentelemetry.grpc-1.6:1.12.0]
|
||||
AttributesMap{data={net.transport=ip_tcp, net.peer.name=localhost,
|
||||
rpc.grpc.status_code=0, rpc.service=helloworld.Greeter, thread.id=1,
|
||||
rpc.method=SayHello, rpc.system=grpc, thread.name=main, net.peer.port=50051},
|
||||
capacity=128, totalAddedValues=9}
|
||||
[otel.javaagent 2023-04-24 17:33:54:567 +0200] [http-nio-8080-exec-1] INFO
|
||||
io.opentelemetry.exporter.logging.LoggingSpanExporter - 'RollController.index' :
|
||||
70c2f04ec863a956e9af975ba0d983ee 7fd145f5cda13625 INTERNAL [tracer:
|
||||
io.opentelemetry.spring-webmvc-6.0:1.25.0-alpha] AttributesMap{data=
|
||||
{thread.id=39, thread.name=http-nio-8080-exec-1}, capacity=128,
|
||||
totalAddedValues=2}
|
||||
[otel.javaagent 2023-04-24 17:33:54:568 +0200] [http-nio-8080-exec-1] INFO
|
||||
io.opentelemetry.exporter.logging.LoggingSpanExporter - 'GET /rolldice' :
|
||||
70c2f04ec863a956e9af975ba0d983ee 647ad186ad53eccf SERVER [tracer:
|
||||
io.opentelemetry.tomcat-10.0:1.25.0-alpha] AttributesMap{
|
||||
data={user_agent.original=curl/7.87.0, net.host.name=localhost,
|
||||
net.transport=ip_tcp, http.target=/rolldice, net.sock.peer.addr=127.0.0.1,
|
||||
thread.name=http-nio-8080-exec-1, net.sock.peer.port=53422,
|
||||
http.route=/rolldice, net.sock.host.addr=127.0.0.1, thread.id=39,
|
||||
net.protocol.name=http, http.status_code=200, http.scheme=http,
|
||||
net.protocol.version=1.1, http.response_content_length=1,
|
||||
net.host.port=8080, http.method=GET}, capacity=128, totalAddedValues=17}
|
||||
```
|
||||
|
||||
At step 5, when stopping the server, you should see an output of all the metrics
|
||||
collected (metrics output is line-wrapped and shortened for convenience):
|
||||
|
||||
```sh
|
||||
[otel.javaagent 2022-10-18 10:12:12:650 +0200] [Thread-0] INFO
|
||||
[otel.javaagent 2023-04-24 17:34:25:347 +0200] [PeriodicMetricReader-1] INFO
|
||||
io.opentelemetry.exporter.logging.LoggingMetricExporter - Received a collection
|
||||
of 15 metrics for export.
|
||||
[otel.javaagent 2022-10-18 10:12:12:651 +0200] [Thread-0] INFO
|
||||
of 19 metrics for export.
|
||||
[otel.javaagent 2023-04-24 17:34:25:347 +0200] [PeriodicMetricReader-1] INFO
|
||||
io.opentelemetry.exporter.logging.LoggingMetricExporter - metric:
|
||||
ImmutableMetricData{resource=Resource{...},
|
||||
instrumentationScopeInfo=InstrumentationScopeInfo{...},
|
||||
name=rpc.server.duration, description=The duration of an inbound RPC invocation,
|
||||
unit=ms, type=HISTOGRAM,
|
||||
data=ImmutableHistogramData{aggregationTemporality=CUMULATIVE,
|
||||
points=[ImmutableHistogramPointData{getStartEpochNanos=1666080515038517000,
|
||||
getEpochNanos=1666080732649264000, getAttributes={net.host.name="localhost",
|
||||
net.transport="ip_tcp", rpc.grpc.status_code=0, rpc.method="SayHello",
|
||||
rpc.service="helloworld.Greeter", rpc.system="grpc"}, getSum=20.300248000000003,
|
||||
getCount=12, hasMin=true, getMin=0.278541, hasMax=true, getMax=16.563833,
|
||||
getBoundaries=[5.0, 10.0, 25.0, 50.0, 75.0, 100.0, 250.0, 500.0, 750.0, 1000.0,
|
||||
2500.0, 5000.0, 7500.0, 10000.0], getCounts=[11, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0], getExemplars=[ImmutableDoubleExemplarData{filteredAttributes={},
|
||||
epochNanos=1666080530527597000,
|
||||
spanContext=ImmutableSpanContext{traceId=f60e0940793cb1dc95bcb86e4668a548,
|
||||
spanId=9737452b2e78e75f, traceFlags=01,
|
||||
traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=true},
|
||||
value=0.278541}, ImmutableDoubleExemplarData{filteredAttributes={},
|
||||
epochNanos=1666080519431994000,
|
||||
spanContext=ImmutableSpanContext{traceId=723ace62b22b2db3bc8323be279e0e55,
|
||||
spanId=44159949946521e7, traceFlags=01,
|
||||
traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=true},
|
||||
value=16.563833}]}]}}
|
||||
ImmutableMetricData{resource=Resource{schemaUrl=
|
||||
https://opentelemetry.io/schemas/1.19.0, attributes={host.arch="aarch64",
|
||||
host.name="OPENTELEMETRY", os.description="Mac OS X 13.3.1", os.type="darwin",
|
||||
process.command_args=[/bin/java, -jar, java-simple.jar],
|
||||
process.executable.path="/bin/java", process.pid=64497,
|
||||
process.runtime.description="Homebrew OpenJDK 64-Bit Server VM 20",
|
||||
process.runtime.name="OpenJDK Runtime Environment",
|
||||
process.runtime.version="20", service.name="java-simple",
|
||||
telemetry.auto.version="1.25.0", telemetry.sdk.language="java",
|
||||
telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.25.0"}},
|
||||
instrumentationScopeInfo=InstrumentationScopeInfo{name=io.opentelemetry.runtime-metrics,
|
||||
version=1.25.0, schemaUrl=null, attributes={}},
|
||||
name=process.runtime.jvm.buffer.limit, description=Total capacity of the buffers
|
||||
in this pool, unit=By, type=LONG_SUM, data=ImmutableSumData{points=
|
||||
[ImmutableLongPointData{startEpochNanos=1682350405319221000,
|
||||
epochNanos=1682350465326752000, attributes=
|
||||
{pool="mapped - 'non-volatile memory'"}, value=0, exemplars=[]},
|
||||
ImmutableLongPointData{startEpochNanos=1682350405319221000,
|
||||
epochNanos=1682350465326752000, attributes={pool="mapped"},
|
||||
value=0, exemplars=[]},
|
||||
ImmutableLongPointData{startEpochNanos=1682350405319221000,
|
||||
epochNanos=1682350465326752000, attributes={pool="direct"},
|
||||
value=8192, exemplars=[]}], monotonic=false, aggregationTemporality=CUMULATIVE}}
|
||||
...
|
||||
```
|
||||
|
||||
|
|
@ -152,13 +235,8 @@ For more:
|
|||
https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#logging-exporter
|
||||
[exporter]:
|
||||
https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md#exporters
|
||||
[get the example code.]:
|
||||
https://grpc.io/docs/languages/java/quickstart/#get-the-example-code
|
||||
[java quick start example]: https://grpc.io/docs/languages/java/quickstart/
|
||||
[manual instrumentation]: ../manual
|
||||
[opentelemetry-javaagent.jar]:
|
||||
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
|
||||
[releases]:
|
||||
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases
|
||||
[run the example:]:
|
||||
https://grpc.io/docs/languages/java/quickstart/#run-the-example
|
||||
|
|
|
|||
|
|
@ -2683,6 +2683,10 @@
|
|||
"StatusCode": 200,
|
||||
"LastSeen": "2023-02-15T21:26:16.922966-05:00"
|
||||
},
|
||||
"https://gradle.org/": {
|
||||
"StatusCode": 206,
|
||||
"LastSeen": "2023-04-24T17:44:10.474433+02:00"
|
||||
},
|
||||
"https://grafana.com/": {
|
||||
"StatusCode": 200,
|
||||
"LastSeen": "2023-02-15T21:24:27.889758-05:00"
|
||||
|
|
|
|||
Loading…
Reference in New Issue