-
Notifications
You must be signed in to change notification settings - Fork 31
Telemetry configuration example #202
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
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
bd2d65b
Telemetry configuration example
tjquinno 33209b3
Copyright, style
tjquinno 2cd159e
Review comments; rebase in attempt to fix pipeline builds
tjquinno 13007a5
Checkstyle
tjquinno a971036
Review comments
tjquinno a985ef4
Review comment - remove refc to se
tjquinno File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # Helidon OpenTelemetry SE Example | ||
|
|
||
| This project implements a simple Hello World REST service using Helidon SE and using OpenTelemetry tracing prepared using Helidon configuration. | ||
|
|
||
| ## Download and start a telemetry back-end | ||
| One easy way to see telemetry in action is to run a back-end server that can collect OpenTelemetry OTLP telemetry data and display it. This example Helidon service by default uses OpenTelemetry to transmit its data using OTLP. | ||
|
|
||
| One option is to download the [Jaeger back-end](https://www.jaegertracing.io/download/), install it, and run it, but most modern backends support OTLP. Later steps in this example use Jaeger as an example back-end. | ||
|
|
||
| ## View the telemetry configuration | ||
| Look at the `src/main/resources/application.yaml` file. It contains configuration for OpenTelemetry. Note these settings under `telemetry`: | ||
| * `service` - Assigns the service name by which all telemetry from this application is identified. You will use this later when using the telemetry back-end UI to browse traces. | ||
| * `tracing.attributes` - Declares settings applied to all traces transmitted to the back-end. | ||
| * `processors` - Specifies a single span processor, `simple`, which emits each span as soon as it is ended. This makes sure that OpenTelemetry sends span data to the back-end as soon as possible. | ||
|
|
||
| **NOTE**: In production systems, you should use the default `batch` processor type (with its additional settings if you wish) for better network performance. | ||
|
|
||
| ## Build and run | ||
|
|
||
| With JDK21 | ||
| ```bash | ||
| mvn package | ||
| java -jar target/helidon-examples-telemetry-config.jar | ||
| ``` | ||
|
|
||
| ## Exercise the application | ||
|
|
||
| Basic: | ||
| ``` | ||
| curl -X GET http://localhost:8080/simple-greet | ||
| Hello World! | ||
| ``` | ||
|
|
||
|
|
||
| JSON: | ||
| ``` | ||
| curl -X GET http://localhost:8080/greet | ||
| {"message":"Hello World!"} | ||
|
|
||
| curl -X GET http://localhost:8080/greet/Joe | ||
| {"message":"Hello Joe!"} | ||
|
|
||
| curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting | ||
|
|
||
| curl -X GET http://localhost:8080/greet/Jose | ||
| {"message":"Hola Jose!"} | ||
| ``` | ||
|
|
||
| ## Use the telemetry back-end to view tracing information | ||
| Use a browser to access the back-end UI and view the spans. For example, with Jaeger: | ||
| 1. Access `http://localhost:16686`. | ||
| 2. Expand the upper-left "Service" drop list and select "otel-config-example" and then click the "Find Traces" button.  | ||
|
|
||
| Recall that the configuration assigns "otel-config-example" as the `telemetry.service`, so that is the service name the back-end displays. | ||
| 3. The UI displays separate traces for each of the requests you made to the Helidon service. | ||
| 4. Click on one of the traces. | ||
| 5. The back-end shows two or more spans, depending on which trace you clicked.  | ||
| 6. Click on any of the spans.  Note that the "Process" tags include values for `x` and `y` from the `attributes` settings in the `application.yaml` config file. | ||
|
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <!-- | ||
|
|
||
| Copyright (c) 2025 Oracle and/or its affiliates. | ||
|
|
||
| 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. | ||
|
|
||
| --> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <parent> | ||
| <groupId>io.helidon.applications</groupId> | ||
| <artifactId>helidon-se</artifactId> | ||
| <version>4.3.0-SNAPSHOT</version> | ||
| <relativePath/> | ||
| </parent> | ||
| <groupId>io.helidon.examples.telemetry</groupId> | ||
| <artifactId>helidon-examples-telemetry-config</artifactId> | ||
| <version>1.0-SNAPSHOT</version> | ||
| <name>Helidon Examples Telemetry Configuration</name> | ||
|
|
||
| <properties> | ||
| <mainClass>io.helidon.examples.telemetry.otelconfig.Main</mainClass> | ||
| </properties> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>io.helidon.webserver</groupId> | ||
| <artifactId>helidon-webserver</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.telemetry</groupId> | ||
| <artifactId>helidon-telemetry-opentelemetry-config</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.webserver.observe</groupId> | ||
| <artifactId>helidon-webserver-observe-tracing</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.http.media</groupId> | ||
| <artifactId>helidon-http-media-jsonp</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.config</groupId> | ||
| <artifactId>helidon-config-yaml</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.opentelemetry</groupId> | ||
| <artifactId>opentelemetry-api</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.tracing.providers</groupId> | ||
| <artifactId>helidon-tracing-providers-opentelemetry</artifactId> | ||
| <scope>runtime</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.webserver.observe</groupId> | ||
| <artifactId>helidon-webserver-observe-telemetry-tracing</artifactId> | ||
| <scope>runtime</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.opentelemetry</groupId> | ||
| <artifactId>opentelemetry-exporter-otlp</artifactId> | ||
| <scope>runtime</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.logging</groupId> | ||
| <artifactId>helidon-logging-jul</artifactId> | ||
| <scope>runtime</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.telemetry.testing</groupId> | ||
| <artifactId>helidon-telemetry-testing-tracing</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.webclient</groupId> | ||
| <artifactId>helidon-webclient</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter-api</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.hamcrest</groupId> | ||
| <artifactId>hamcrest-all</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.helidon.webserver.testing.junit5</groupId> | ||
| <artifactId>helidon-webserver-testing-junit5</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-dependency-plugin</artifactId> | ||
| <executions> | ||
| <execution> | ||
| <id>copy-libs</id> | ||
| </execution> | ||
| </executions> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> | ||
136 changes: 136 additions & 0 deletions
136
...telemetry/config/src/main/java/io/helidon/examples/telemetry/otelconfig/GreetService.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| /* | ||
| * Copyright (c) 2025 Oracle and/or its affiliates. | ||
| * | ||
| * 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 io.helidon.examples.telemetry.otelconfig; | ||
|
|
||
| import java.util.Collections; | ||
| import java.util.concurrent.atomic.AtomicReference; | ||
|
|
||
| import io.helidon.config.Config; | ||
| import io.helidon.http.Status; | ||
| import io.helidon.webserver.http.HttpRules; | ||
| import io.helidon.webserver.http.HttpService; | ||
| import io.helidon.webserver.http.ServerRequest; | ||
| import io.helidon.webserver.http.ServerResponse; | ||
|
|
||
| import jakarta.json.Json; | ||
| import jakarta.json.JsonBuilderFactory; | ||
| import jakarta.json.JsonObject; | ||
|
|
||
| /** | ||
| * A simple service to greet you. Examples: | ||
| * <p> | ||
| * Get default greeting message: | ||
| * {@code curl -X GET http://localhost:8080/greet} | ||
| * <p> | ||
| * Get greeting message for Joe: | ||
| * {@code curl -X GET http://localhost:8080/greet/Joe} | ||
| * <p> | ||
| * Change greeting | ||
| * {@code curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting} | ||
| * <p> | ||
| * The message is returned as a JSON object | ||
| */ | ||
| class GreetService implements HttpService { | ||
|
|
||
|
|
||
| private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); | ||
|
|
||
| /** | ||
| * The config value for the key {@code greeting}. | ||
| */ | ||
| private final AtomicReference<String> greeting = new AtomicReference<>(); | ||
|
|
||
| GreetService() { | ||
| this(Config.global().get("app")); | ||
| } | ||
|
|
||
| GreetService(Config appConfig) { | ||
| greeting.set(appConfig.get("greeting").asString().orElse("Ciao")); | ||
| } | ||
|
|
||
| /** | ||
| * A service registers itself by updating the routing rules. | ||
| * | ||
| * @param rules the routing rules. | ||
| */ | ||
| @Override | ||
| public void routing(HttpRules rules) { | ||
| rules | ||
| .get("/", this::getDefaultMessageHandler) | ||
| .get("/{name}", this::getMessageHandler) | ||
| .put("/greeting", this::updateGreetingHandler); | ||
| } | ||
|
|
||
| /** | ||
| * Return a worldly greeting message. | ||
| * | ||
| * @param request the server request | ||
| * @param response the server response | ||
| */ | ||
| private void getDefaultMessageHandler(ServerRequest request, | ||
| ServerResponse response) { | ||
| sendResponse(response, "World"); | ||
| } | ||
|
|
||
| /** | ||
| * Return a greeting message using the name that was provided. | ||
| * | ||
| * @param request the server request | ||
| * @param response the server response | ||
| */ | ||
| private void getMessageHandler(ServerRequest request, | ||
| ServerResponse response) { | ||
| String name = request.path().pathParameters().get("name"); | ||
| sendResponse(response, name); | ||
| } | ||
|
|
||
| private void sendResponse(ServerResponse response, String name) { | ||
| String msg = String.format("%s %s!", greeting.get(), name); | ||
|
|
||
| JsonObject returnObject = JSON.createObjectBuilder() | ||
| .add("message", msg) | ||
| .build(); | ||
| response.send(returnObject); | ||
| } | ||
|
|
||
| private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { | ||
|
|
||
| if (!jo.containsKey("greeting")) { | ||
| JsonObject jsonErrorObject = JSON.createObjectBuilder() | ||
| .add("error", "No greeting provided") | ||
| .build(); | ||
| response.status(Status.BAD_REQUEST_400) | ||
| .send(jsonErrorObject); | ||
| return; | ||
| } | ||
|
|
||
| greeting.set(jo.getString("greeting")); | ||
| response.status(Status.NO_CONTENT_204).send(); | ||
| } | ||
|
|
||
| /** | ||
| * Set the greeting to use in future messages. | ||
| * | ||
| * @param request the server request | ||
| * @param response the server response | ||
| */ | ||
| private void updateGreetingHandler(ServerRequest request, | ||
| ServerResponse response) { | ||
| updateGreetingFromJson(request.content().as(JsonObject.class), response); | ||
| } | ||
|
|
||
| } |
66 changes: 66 additions & 0 deletions
66
examples/telemetry/config/src/main/java/io/helidon/examples/telemetry/otelconfig/Main.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| /* | ||
| * Copyright (c) 2025 Oracle and/or its affiliates. | ||
| * | ||
| * 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 io.helidon.examples.telemetry.otelconfig; | ||
|
|
||
| import io.helidon.config.Config; | ||
| import io.helidon.logging.common.LogConfig; | ||
| import io.helidon.service.registry.Services; | ||
| import io.helidon.webserver.WebServer; | ||
| import io.helidon.webserver.http.HttpRouting; | ||
|
|
||
| /** | ||
| * The application main class. | ||
| */ | ||
| public class Main { | ||
|
|
||
| /** | ||
| * Cannot be instantiated. | ||
| */ | ||
| private Main() { | ||
| } | ||
|
|
||
| /** | ||
| * Application main entry point. | ||
| * @param args command line arguments. | ||
| */ | ||
| public static void main(String[] args) { | ||
|
|
||
| // load logging configuration | ||
| LogConfig.configureRuntime(); | ||
|
|
||
| // initialize config from default configuration | ||
| Config config = Services.get(Config.class); | ||
|
|
||
| WebServer server = WebServer.builder() | ||
| .config(config.get("server")) | ||
| .routing(Main::routing) | ||
| .build() | ||
| .start(); | ||
|
|
||
| System.out.println("WEB server is up! http://localhost:" + server.port() + "/simple-greet"); | ||
|
|
||
| } | ||
|
|
||
| /** | ||
| * Updates HTTP Routing. | ||
| */ | ||
| static void routing(HttpRouting.Builder routing) { | ||
| routing | ||
| .register("/greet", new GreetService()) | ||
| .get("/simple-greet", (req, res) -> res.send("Hello World!")); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add
<name>There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed