Blog Post

Apps on Azure Blog
6 MIN READ

Send traces from Micronaut native image applications to Azure Monitor

Logico_jp's avatar
Logico_jp
Icon for Microsoft rankMicrosoft
Aug 15, 2025

The original post (Japanese) was written on 23 July 2025.

MicronautからAzure Monitorにtraceを送信したい – Logico Inside

This entry is related to the following one. Please take a look for background information.

Send signals from Micronaut native image applications to Azure Monitor | Microsoft Community Hub

Prerequisites

  • Maven: 3.9.10
  • JDK version 21
  • Micronaut: 4.9.0 or later

The following tutorial was used as a reference.

OpenTelemetry Tracing with Oracle Cloud and the Micronaut Framework

As of 13 August 2025, GDK (Graal Dev Kit) guides are also available.

Create and Trace a Micronaut Application Using Azure Monitor

Create an archetype

We can create an archetype using Micronaut’s CLI (mn) or Micronaut Launch. In this entry, use application.yml instead of application.properties for application configuration. So, we need to specify the feature “yaml” so that we can include dependencies for using yaml.

Micronaut Launch

mn create-app \
--build=maven \
--jdk=21 \
--lang=java \
--test=junit \
--features=tracing-opentelemetry-http,validation,graalvm,azure-tracing,http-client,yaml \
dev.logicojp.micronaut.azuremonitor-metric

When using Micronaut Launch, click [FEATURES] and select the following features.

  • tracing-opentelemetry-http
  • validation
  • graalvm
  • azure-tracing
  • http-client
  • yaml

After all features are selected, click [GENERATE PROJECT] and choose [Download Zip] to download an archetype in Zip file.

Implementation

<dependency>
  <groupid>io.micronaut.tracing</groupid>
  <artifactid>micronaut-tracing-opentelemetry-http</artifactid>
  <scope>compile</scope>
</dependency>

In this section, we’re going to use the tutorial in Micronaut Guides. We can use these codes as they are, but several points are modified.

a) For sending traces to Application Insights

Please note that we didn’t include metrics in this article because we discussed them in the last one.

Starting with Micronaut 4.9.0, a feature package called micronaut-azure-tracing has been added. This feature enables sending traces to Application Insights.

<dependency>
    <groupid>io.micronaut.azure</groupid>
    <artifactid>micronaut-azure-tracing</artifactid>
</dependency>

Indeed, this dependency is necessary for sending data to Application Insights. However, adding this dependency and specifying the Application Insights connection string is not enough to send traces from applications. micronaut-azure-tracing depends upon the three dependencies listed below. This shows that adding dependencies for trace collection and creation are required.

  • com.azure:azure-monitor-opentelemetry-autoconfigure
  • io.micronaut:micronaut-inject
  • io.micronaut.tracing:micronaut-tracing-opentelemetry

In this case, we want to obtain HTTP traces, so we will add dependencies for generating HTTP traces.

<dependency>
  <groupid>io.micronaut.tracing</groupid>
  <artifactid>micronaut-tracing-opentelemetry-http</artifactid>
  <scope>compile</scope>
</dependency>

Where setting the connection string for micronaut-azure-tracing is different from where for micrometer-azure-monitor ( azure.tracing.connection-string). If we want to retrieve not only metrics but traces, the setting location is different, which can be confusing. We can also use environment variables to specify the connection string.

azure.tracing.connection-string="InstrumentationKey=...."
azure:
  tracing:
    connection-string: InstrumentationKey=....

b) pom.xml

To use the GraalVM Reachability Metadata Repository, we need to add this dependency. The latest version is 0.11.0 as of 23 July, 2025.

<dependency>
    <groupid>org.graalvm.buildtools</groupid>
    <artifactid>graalvm-reachability-metadata</artifactid>
    <version>0.11.0</version>
</dependency>

Add the GraalVM Maven plugin and enable the use of GraalVM Reachability Metadata obtained from the above dependency. This plugin lets us set optimization levels using buildArg (in this example, the optimisation level is specified). We can also add it to native-image.properties, the native-image tool (and the Maven/Gradle plugin) will read it.

<plugin>
    <groupid>org.graalvm.buildtools</groupid>
    <artifactid>native-maven-plugin</artifactid>
    <configuration>
        <metadatarepository>
            <enabled>true</enabled>
        </metadatarepository>
        <buildargs combine.children="append">
            <buildarg>-Ob</buildarg>
        </buildargs>
        <quickbuild>true</quickbuild>
    </configuration>
</plugin>

c) To avoid version conflicts with dependencies used in the Azure SDK

This often happens when using Netty and/or Jackson. To avoid version conflicts during Native Image generation, Micronaut offers alternative components that we can choose. For example, if we want to avoid Netty version conflicts, we can use undertow.

DependenciesAlternatives
Nettyundertow, jetty, Tomcat
JacksonJSON-P / JSON-B, BSON
HTTP ClientJDK HTTP Client

For now, let’s build it as a Java application.

mvn clean package

Test as a Java application

At first, verify that the application is running without any problems and that traces are being sent to Application Insights. Then, run the application using the Tracing Agent to generate the necessary configuration files.

# (1) Collect configuration files such as reflect-config.json
$JAVA_HOME/bin/java \
  -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/{groupId}/{artifactId}/ \
  -jar ./target/{artifactId}-{version}.jar
# (2)-a Generate a trace file
$JAVA_HOME/bin/java \
  -agentlib:native-image-agent=trace-output=/path/to/trace-file.json \
  -jar ./target/{artifactId}-{version}.jar
# (2)-b Generate a reachability metadata file from the collected trace file
native-image-configure generate \
  --trace-input=/path/to/trace-file.json \
  --output-dir=/path/to/config-dir/

Configure Native Image with the Tracing Agent

Collect Metadata with the Tracing Agent

Make the following files in the specified folder.

  • jni-config.json
  • reflect-config.json
  • proxy-config.json
  • resource-config.json
  • reachability-metadata.json

These files can be located at src/main/resources/META-INF/native-image. The native-image tool picks up configuration files located in the directory src/main/resources/META-INF/native-image. However, it is recommended that we place the files in subdirectories divided by groupId and artifactId, as shown below.

src/main/resources/META-INF/native-image/{groupId}/{artifactId}

native-image.properties

When creating a native image, we call the following command.

mvn package -Dpackaging=native-image

We should specify the timing of class initialization (build time or runtime), the command line options for the native-image tool (the same command line options work in Maven/Gradle plugin), and the JVM arguments in the native-image.properties file. Indeed, these settings can be specified in pom.xml, but it is recommended that they be externalized.

This is also explained in the metric entry, so some details will be left out. If needed, please check the metric entry.

Send metrics from Micronaut native image applications to Azure Monitor | Microsoft Community Hub

Build a Native Image application

Building a native image application takes a long time (though it has got quicker over time). If building it for testing purpose, we strongly recommend enabling Quick Build and setting the optimization level to -Ob option (although this will still take time). See below for more information.

Maven plugin for GraalVM Native Image
Gradle plugin for GraalVM Native Image
Optimizations and Performance

Test as a native image application

Let’s check if the application works. To check the inventory of desktop, execute the following call.

curl https://<container apps="" url="" and="" port="">/store/inventory/desktop</container>

We should receive a response like this.

{"warehouse":7,"item":"desktop","store":2}

In Azure Monitor (Application Insights) Application Map, we can observe this interaction visually.

 

Switching to the trace page shows us traces and custom properties on the right of the screen.

Press enter or click to view image in full size

Then, we add an order. For example, if we place an order for five desktops and then receive 202 Accepted, we need to call inventory check API again. This will show that the number has increased by five and the desktop order has changed to seven (original was 2).

$ curl -X "POST" "https://<container apps="" url="" and="" port="">/store/order" \
        -H 'Content-Type: application/json; charset=utf-8' \
        -d $'{"item":"desktop", "count":5}'

$ curl https://<container apps="" url="" and="" port="">/store/inventory/desktop</container></container>

Within azuremonitor-trace, an HTTP Client is used internally to execute POST /warehouse/order. Looking at the Application Map in Azure Monitor (Application Insights), we can confirm that a call to azuremonitor-trace itself is occurring.

The trace at the time of order placement is as follows.

Clicking ‘View all’ in the red frame, we can check the details of each trace.

 

Updated Aug 15, 2025
Version 3.0
No CommentsBe the first to comment