これは、なにをしたくて書いたもの?
WildFly 40はMicroProfile 7.1の実装が含まれています。
以前はトレースとメトリクスだけを見ていたのですが、ログも送信できるようになっていたので簡単に見ておきます。
WildFly 40とMicroProfile
WildFly 40はMicroProfile 7.1に対応しています。
この中には、OpenTelemetry向けの仕様であるMicroProfile Telemetry 2.1が含まれています。
トレース・メトリクス・ログの3つのシグナルに対応しています。
MicroProfile TelemetryはOpenTelemetry SDKとインテグレーションするための仕様です。もっとも、API仕様は
ありませんが。
またWildFlyにはMicroProfile Telemetryサブシステムがあるのですが、ログに対応しているかどうかがよくわかりません
でした。
WildFly Admin Guide / Subsystem configuration / MicroProfile Telemetry Subsystem
少なくともWildFlyが使っているMicroProfile Telemetryの実装であるSmallRye Telemetryはしばらくログには対応して
いなかったのですが、2.8.0でログをサポートするようになっています。
Support OpenTelemetry Logs
Release 2.8.0 · smallrye/smallrye-opentelemetry · GitHub
では、今動かすとどうなるでしょう?と試してみたのが今回のエントリーです。今回は最低限の設定で、簡単に動かして
みようと思います。
環境
今回の環境はこちら。
$ java --version openjdk 25.0.3 2026-04-21 OpenJDK Runtime Environment (build 25.0.3+9-2-24.04.2-Ubuntu) OpenJDK 64-Bit Server VM (build 25.0.3+9-2-24.04.2-Ubuntu, mixed mode, sharing) $ mvn --version Apache Maven 3.9.16 (2bdd9fddda4b155ebf8000e807eb73fd829a51d5) Maven home: $HOME/.sdkman/candidates/maven/current Java version: 25.0.3, vendor: Ubuntu, runtime: /usr/lib/jvm/java-25-openjdk-amd64 Default locale: ja_JP, platform encoding: UTF-8 OS name: "linux", version: "6.8.0-134-generic", arch: "amd64", family: "unix"
なんとなくですが、データベースも用意しておきます。MySQLで172.17.0.2で動作しているものとします。
MySQL localhost:33060+ ssl practice SQL > select version(); +-----------+ | version() | +-----------+ | 8.4.10 | +-----------+ 1 row in set (0.0008 sec)
またテレメトリーデータはGrafana LGTMで受け取ることにします。
$ docker container run -it --rm --name lgtm \ -p 3000:3000 -p 4040:4040 -p 4317:4317 -p 4318:4318 -p 9090:9090 \ -e GF_PATHS_DATA=/data/grafana \ grafana/otel-lgtm:0.28.0
つまり、こんな感じになるようにします。
flowchart LR
クライアント --> |curl/HTTP| A
subgraph WildFly
A[JAX-RS / JPA]
end
subgraph Database
A -- JDBC --> M
M[MySQL]
end
subgraph Telemetry
A -- OTLP over gRPC[4317] --> B["OpenTelemetry Collector"]
B -- Tracing --> C["Grafana Tempo"]
B -- Logs --> D["Grafana Loki"]
B -- Metrics --> E["Prometheus"]
end
準備
それではアプリケーションを作成します。
Maven依存関係など。
<properties> <maven.compiler.release>25</maven.compiler.release> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-ee</artifactId> <version>40.0.1.Final</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.wildfly.bom</groupId> <artifactId>wildfly-expansion</artifactId> <version>40.0.1.Final</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.enterprise</groupId> <artifactId>jakarta.enterprise.cdi-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.transaction</groupId> <artifactId>jakarta.transaction-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.persistence</groupId> <artifactId>jakarta.persistence-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.data</groupId> <artifactId>jakarta.data-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-core</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.eclipse.microprofile.config</groupId> <artifactId>microprofile-config-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>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>ROOT</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.15.0</version> <configuration> <annotationProcessorPaths> <path> <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-processor</artifactId> </path> </annotationProcessorPaths> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.5.6</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.wildfly.plugins</groupId> <artifactId>wildfly-maven-plugin</artifactId> <version>6.0.0.Final</version> <executions> <execution> <id>package</id> <goals> <goal>package</goal> </goals> </execution> </executions> <configuration> <overwrite-provisioned-server>true</overwrite-provisioned-server> <discover-provisioning-info> <version>40.0.1.Final</version> <layers-for-jndi> <layer>microprofile-telemetry</layer> </layers-for-jndi> <add-ons> <add-on>mysql</add-on> </add-ons> <suggest>true</suggest> </discover-provisioning-info> <env> <MYSQL_DATASOURCE>MySqlDs</MYSQL_DATASOURCE> <MYSQL_JNDI>java:jboss/datasources/MySqlDs</MYSQL_JNDI> <MYSQL_URL>jdbc:mysql://172.17.0.2:3306/practice?characterEncoding=utf-8&connectionCollation=utf8mb4_0900_bin</MYSQL_URL> <MYSQL_USER>kazuhira</MYSQL_USER> <MYSQL_PASSWORD>password</MYSQL_PASSWORD> <MYSQL_ENABLED>true</MYSQL_ENABLED> </env> </configuration> </plugin> </plugins> </build>
Jakarta RESTful Web Services、Jakarta Contexts and Dependency Injection、Jakarta Dataの組み合わせですね。
今回用意したソースコードでは、microprofile-telemetry Layerは検出対象にならなかったので自分で追加しました…。
<layers-for-jndi> <layer>microprofile-telemetry</layer> </layers-for-jndi>
MicroProfile Configのプロパティーファイル。このファイルがMicroProfile Telemetryでのポイントですが、
otel.sdk.disabledをfalseにしてOpenTelemetry SDKを有効にします。
src/main/resources/META-INF/microprofile-config.properties
otel.sdk.disabled=false otel.service.name=application
あとはサンプルコードを並べていきましょう。
Jakarta Persistenceのエンティティー。
src/main/java/org/littlewings/wildfly/telemetry/book/Book.java
package org.littlewings.wildfly.telemetry.book; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @Entity @Table(name = "book") public class Book { @Id private String isbn; private String title; private Integer price; // getter/setter、toStringは省略 }
JPAの設定。
src/main/resources/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_2.xsd" version="3.2"> <persistence-unit name="MyPersistenceUnit" transaction-type="JTA"> <jta-data-source>java:jboss/datasources/MySqlDs</jta-data-source> <properties> <property name="hibernate.show_sql" value="true"/> <property name="hibernate.format_sql" value="true"/> <property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/> </properties> </persistence-unit> </persistence>
Jakarta Dataのリポジトリーインターフェース。
src/main/java/org/littlewings/wildfly/telemetry/book/BookRepository.java
package org.littlewings.wildfly.telemetry.book; import jakarta.data.repository.BasicRepository; import jakarta.data.repository.Repository; @Repository public interface BookRepository extends BasicRepository<Book, String> {}
JAX-RSのリソースクラス。
src/main/java/org/littlewings/wildfly/telemetry/book/BookResource.java
package org.littlewings.wildfly.telemetry.book; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import java.util.List; import org.jboss.logging.Logger; @Path("/books") @ApplicationScoped @Transactional public class BookResource { private Logger logger = Logger.getLogger(BookResource.class); @Inject private BookRepository bookRepository; @GET @Path("/{isbn}") @Produces(MediaType.APPLICATION_JSON) public Book findByIsbn(@PathParam("isbn") String isbn) { Book book = bookRepository.findById(isbn).orElse(null); logger.infof("find book: isbn = [%s], found book = %s", isbn, book); return book; } @GET @Produces(MediaType.APPLICATION_JSON) public List<Book> findAll() { List<Book> books = bookRepository.findAll().toList(); logger.infof("find all: %s", books); return books; } @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Book register(Book book) { logger.infof("register book: %s", book); return bookRepository.save(book); } @PUT @Path("/{isbn}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public void update(@PathParam("isbn") String isbn, Book book) { logger.infof("update book: %s", book); bookRepository.save(book); } @DELETE @Path("/{isbn}") public void delete(@PathParam("isbn") String isbn) { logger.infof("delete book: isbn = [%s]", isbn); bookRepository.deleteById(isbn); } }
ログ出力を入れています。
JAX-RSの有効化。
src/main/java/org/littlewings/wildfly/telemetry/RestApplication.java
package org.littlewings.wildfly.telemetry; import jakarta.ws.rs.ApplicationPath; import jakarta.ws.rs.core.Application; @ApplicationPath("/") public class RestApplication extends Application {}
動かしてみる
では、確認してみましょう。
WildFlyを起動。
$ mvn wildfly:dev
いくつか動かしてみます。
$ curl localhost:8080/books --json '{"isbn": "978-4774183169", "title": "パーフェクト Java EE", "price": 3520}' {"isbn":"978-4774183169","price":3520,"title":"パーフェクト Java EE"} $ curl localhost:8080/books --json '{"isbn": "978-4297156589", "title": "作って学ぶ Spring Boot入門", "price": 2970}' {"isbn":"978-4297156589","price":2970,"title":"作って学ぶ Spring Boot入門"} $ curl -s localhost:8080/books | jq [ { "isbn": "978-4297156589", "price": 2970, "title": "作って学ぶ Spring Boot入門" }, { "isbn": "978-4774183169", "price": 3520, "title": "パーフェクト Java EE" } ] $ curl localhost:8080/books/978-4774183169 {"isbn":"978-4774183169","price":3520,"title":"パーフェクト Java EE"} $ curl -X PUT localhost:8080/books/978-4297156589 --json '{"isbn": "978-4297156589", "title": "作って学ぶ Spring Boot入門", "price": 4970}' $ curl -X DELETE localhost:8080/books/978-4774183169
http://localhost:3000/にアクセスして、結果を見てみましょう。
トレース。

ログも入っています。

アプリケーション側だけではなくて、WildFlyのログも送信されていますね。
なにも考えずに出力しているだけなので、トレースと関連付けられているかどうか気になるところです。
トレースの一覧から

ひとつトレースを選び、クリックするとスパンが開きます。すると「Logs for this span」というボタンを押すと

対応するログに移動します。

いいですね。
メトリクスもちゃんとあります。

よいのではないでしょうか。
気になること
ちょっと気になるのは、ログのフォーマットですね。今回はデフォルトのまま使いましたが、WildFlyの場合はJSON Formatterを
使えばよいのでしょうか?
OpenTelemetry SDKを使う場合は、ロギングライブラリーのAppenderを使おうということでした。
Instrumentation ecosystem | OpenTelemetry
ログのフォーマットはこの時に使うロギングライブラリーのレイアウトに任せていた気がしますが、WildFlyの場合は
どうなんでしょうね。
また、以前もWildFlyのMicroProfile Telemetryを使った時に悩んだようですが、JDBCのトレースが取れません。
たぶん、こちらを使わないといけないんでしょうけどね。
3年前に扱った時もまったく同じことを言っていたようです(笑)。
WildFlyのMicroProfile Telemetryサブシステムを使って、トレースを試す - CLOVER🍀
おわりに
WildFly 40のMicroProfile Telemetryサブシステムを使って、トレース・メトリクス・ログの3つのシグナルをGrafana LGTMに
送ってみました。
今回はログが送れるかどうかを見たかったので簡単に済ませましたが、OpenTelemetryと組み合わせようと思うと
やっぱりいろいろと気になることがありますね。
3年前と同じ疑問が解決していなかったりするので、どこかでまた頑張って調べましょうか…?