This is a Java agent that extends OpenTelemetry Java Agent to provide Azure Application Insights telemetry. The agent is packaged as a single JAR that instruments applications at runtime without code changes.
- Agent Entry Point:
Agent.java- wraps OpenTelemetry Agent with Application Insights-specific initialization - Agent Bootstrap: Minimal classes loaded into bootstrap classloader for early initialization
- Agent Tooling: Main Application Insights logic (configuration, exporters, processors) isolated in agent classloader
- Instrumentation Modules: C Functions, ASP.NET Core interop, etc.
- Classic SDK: Legacy 2.x SDK maintained for compatibility
ustom instrumentation for Azure
agent/
├── agent/ # Final agent JAR assembly (shadow plugin)
├── agent-bootstrap/ # Bootstrap classloader components
├── agent-tooling/ # Core agent logic & Azure exporters
├── instrumentation/ # Custom instrumentation modules
└── runtime-attach/ # Dynamic attach support
# Build complete agent JAR
./gradlew assemble
# Agent JAR location
# agent/agent/build/libs/applicationinsights-agent-<version>.jarSmoke tests use containerized applications with the agent attached.
Generally you shouldn't run all of the smoke tests, as they can take a long time. Instead, focus on running a single test.
# Run a specific smoke test
./gradlew :smoke-tests:apps:HttpClients:smokeTest --tests "*HttpClientTest\$Tomcat8Java8Test"The project uses Spotless for consistent code formatting. Apply formatting to all code:
# Apply formatting to all files
./gradlew spotlessApply- ai.java-conventions: Base Java setup with JDK 17 toolchain, targets Java 8
- ai.javaagent-instrumentation: Plugin for OpenTelemetry instrumentation modules
- ai.smoke-test-war: WAR-based smoke test applications
- ai.shadow-conventions: JAR shadowing with relocation rules
The agent JAR is built in 3 critical steps (see agent/agent/build.gradle.kts):
- Relocate distro-specific libraries to avoid conflicts
- Isolate classes to
inst/directory with.classdataextensions - Merge with upstream OpenTelemetry agent, excluding duplicates
- Main config:
Configuration.java- comprehensive JSON-based configuration - Environment variables:
APPLICATIONINSIGHTS_CONNECTION_STRING, etc.
- Framework:
smoke-tests/framework/- shared test infrastructure - Apps:
smoke-tests/apps/- containerized test applications - Assertions:
DependencyAssert,RequestAssert,MetricAssertfor validating telemetry - Fake Ingestion: Mock Application Insights endpoint for testing
- Environment Matrix: Tests run across multiple environments (Java 8/11/17/21/23, Tomcat/Wildfly, HotSpot/OpenJ9)
- Nested Test Classes: Each abstract test class has nested static classes for different environments:
abstract class HttpClientTest { @Environment(TOMCAT_8_JAVA_8) static class Tomcat8Java8Test extends HttpClientTest {} @Environment(TOMCAT_8_JAVA_11) static class Tomcat8Java11Test extends HttpClientTest {} }
Use FriendlyException for user-facing errors with actionable messages:
throw new FriendlyException(
"Connection string is required",
"Please set APPLICATIONINSIGHTS_CONNECTION_STRING environment variable");- All dependencies managed through
dependencyManagement/module - Strict version conflict resolution (
failOnVersionConflict()) - Dependency locking enabled for reproducible builds
- Unit Tests: Standard JUnit 5 with 15-minute timeout
- Smoke Tests: Containerized integration tests with fake ingestion
- Muzzle Tests: Bytecode compatibility validation for instrumentation
agent/agent/build.gradle.kts- Agent assembly processagent/agent-tooling/src/main/java/.../configuration/Configuration.java- Main configurationsmoke-tests/framework/src/main/java/.../smoketest/- Test infrastructurebuildSrc/src/main/kotlin/ai.*.gradle.kts- Build conventions
- Agent JAR must be self-contained (no external dependencies)
- Bootstrap classes are loaded early - keep minimal
- Use
hideFromDependabot()for test-only dependencies - Smoke tests validate end-to-end functionality in realistic environments
- Check
gradle.lockfilewhen dependency issues arise
To identify which upstream commit introduced a regression:
- Update
dependencyManagement/build.gradle.ktsto use SNAPSHOT version (e.g.,2.10.0-alpha-SNAPSHOT) - Clone and bisect the upstream repo:
git clone https://github.com/open-telemetry/opentelemetry-java-instrumentation.git cd opentelemetry-java-instrumentation git bisect start v2.10.0 v2.9.0 - For each bisect iteration:
./gradlew publishToMavenLocal cd /path/to/ApplicationInsights-Java ./gradlew :smoke-tests:apps:YourApp:smokeTest --tests "*YourFailingTest" cd /path/to/opentelemetry-java-instrumentation git bisect good # or bad
- When done:
git bisect resetand restoredependencyManagement/build.gradle.kts