Logico_jp provides a detailed walkthrough on instrumenting Micronaut Java applications to send traces and metrics to Azure Monitor, using zero-code OpenTelemetry and native-image techniques.

Send Traces and Metrics from Micronaut Apps to Azure Monitor with Zero-Code Instrumentation

Author: Logico_jp
Original post: 13 August 2025

This article demonstrates how to use zero-code instrumentation to collect telemetry (traces and metrics) from a Micronaut-based REST API and send it directly to Azure Monitor’s Application Insights. The approach focuses on minimizing code changes—leveraging configuration and dependencies for tracing HTTP and JDBC activity, and deploying as both a regular JVM application and a GraalVM native image.

Prerequisites

  • Maven 3.9.10
  • JDK 21
  • Micronaut 4.9.0 or later
  • Azure Monitor / Application Insights provisioned
  • PostgreSQL Flexible Server provisioned

Key References

Project Archetype and Features

When creating the archetype (via mn CLI or Micronaut Launch), include these features:

  • graalvm
  • management
  • micrometer-azure-monitor
  • azure-tracing
  • yaml (for application.yml config)
  • validation
  • postgres
  • jdbc-hikari
  • data-jpa

Core Dependencies

To instrument HTTP and JDBC:

<dependency>
  <groupId>io.micronaut.tracing</groupId>
  <artifactId>micronaut-tracing-opentelemetry-http</artifactId>
</dependency>
<dependency>
  <groupId>io.micronaut.tracing</groupId>
  <artifactId>micronaut-tracing-opentelemetry-jdbc</artifactId>
</dependency>

For GraalVM native-image:

<dependency>
  <groupId>org.graalvm.buildtools</groupId>
  <artifactId>graalvm-reachability-metadata</artifactId>
  <version>0.11.0</version>
</dependency>

Maven plugin for native image:

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

Application Configuration (application.yml)

Set up database and Azure Monitor connections by environment variable:

micronaut:
  application:
    name: micronaut-telemetry-movie
  metrics:
    enabled: true
    export:
      azuremonitor:
        enabled: true
        step: PT1M
        connectionString: ${AZURE_MONITOR_CONNECTION_STRING}

datasources:
  default:
    driver-class-name: org.postgresql.Driver
    db-type: postgres
    url: ${JDBC_URL}
    username: ${JDBC_USERNAME}
    password: ${JDBC_PASSWORD}

azure:
  tracing:
    connection-string: ${AZURE_MONITOR_CONNECTION_STRING}

otel:
  exclusions: /health, /info, /metrics, /actuator/health, /actuator/info, /actuator/metrics

Building and Running

  • Java application: Run with standard JVM to verify traces/metrics reach Application Insights.
  • Native image: Use Maven’s native-maven-plugin and GraalVM, collect config files with the tracing agent, and build with mvn package -Dpackaging=native-image.
  • Place configuration files (reflect, proxy, resource, reachability-metadata) under src/main/resources/META-INF/native-image/{groupId}/{artifactId} for pickup by the native-image tool.

Refer to GraalVM docs for config file generation.

Testing

  • Initialize database data:

    curl -X PUT https://<app_url>/api/movies
    # Response: {"message":"Database initialized with default movies."}
    
  • Verify movies exist:

    curl https://<app_url>/api/movies
    
  • Check metrics via REST endpoint: /metrics

Caveats

  • JVM-related metrics (like jvm.memory.max) do not provide full info in native images (returns -2).
  • Logs require explicit OpenTelemetry setup; zero-code only covers metrics/traces.

Sample log setup (constructor-based OpenTelemetry registration):

@Inject
AzureTracingConfigurationProperties azureTracingConfigurationProperties;

private static final Logger logger = LoggerFactory.getLogger(MovieController.class);

public MovieController(AzureTracingConfigurationProperties azureTracingConfigurationProperties) {
  this.azureTracingConfigurationProperties = azureTracingConfigurationProperties;
  AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder = AutoConfiguredOpenTelemetrySdk.builder();
  AzureMonitorAutoConfigure.customize(sdkBuilder, azureTracingConfigurationProperties.getConnectionString());
  OpenTelemetryAppender.install(sdkBuilder.build().getOpenTelemetrySdk());
  logger.info("OpenTelemetry configured for MovieController.");
}

Summary

Zero-code instrumentation significantly streamlines collecting performance and trace data from Micronaut applications to Azure Monitor. Explicit configuration (and sometimes explicit code for logs) is still occasionally necessary, especially for advanced scenarios or native images.

This post appeared first on “Microsoft Tech Community”. Read the entire article here