|
| 1 | +# Application Insights Java Agent - Development Guide |
| 2 | + |
| 3 | +## Architecture Overview |
| 4 | + |
| 5 | +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. |
| 6 | + |
| 7 | +### Key Components |
| 8 | + |
| 9 | +- **Agent Entry Point**: `Agent.java` - wraps OpenTelemetry Agent with Application Insights-specific initialization |
| 10 | +- **Agent Bootstrap**: Minimal classes loaded into bootstrap classloader for early initialization |
| 11 | +- **Agent Tooling**: Main Application Insights logic (configuration, exporters, processors) isolated in agent classloader |
| 12 | +- **Instrumentation Modules**: C Functions, ASP.NET Core interop, etc. |
| 13 | +- **Classic SDK**: Legacy 2.x SDK maintained for compatibility |
| 14 | + |
| 15 | +### Multi-Module Build Structure |
| 16 | +ustom instrumentation for Azure |
| 17 | +``` |
| 18 | +agent/ |
| 19 | +├── agent/ # Final agent JAR assembly (shadow plugin) |
| 20 | +├── agent-bootstrap/ # Bootstrap classloader components |
| 21 | +├── agent-tooling/ # Core agent logic & Azure exporters |
| 22 | +├── instrumentation/ # Custom instrumentation modules |
| 23 | +└── runtime-attach/ # Dynamic attach support |
| 24 | +``` |
| 25 | + |
| 26 | +## Development Workflows |
| 27 | + |
| 28 | +### Building the Agent |
| 29 | + |
| 30 | +```bash |
| 31 | +# Build complete agent JAR |
| 32 | +./gradlew assemble |
| 33 | + |
| 34 | +# Agent JAR location |
| 35 | +# agent/agent/build/libs/applicationinsights-agent-<version>.jar |
| 36 | +``` |
| 37 | + |
| 38 | +### Running Smoke Tests |
| 39 | + |
| 40 | +Smoke tests use containerized applications with the agent attached. |
| 41 | + |
| 42 | +Generally you shouldn't run all of the smoke tests, as they can take a long time. |
| 43 | +Instead, focus on running a single test. |
| 44 | + |
| 45 | +```bash |
| 46 | +# Run a specific smoke test |
| 47 | +./gradlew :smoke-tests:apps:HttpClients:smokeTest --tests "*HttpClientTest\$Tomcat8Java8Test" |
| 48 | +``` |
| 49 | + |
| 50 | +## Project-Specific Conventions |
| 51 | + |
| 52 | +### Build Conventions (buildSrc/) |
| 53 | + |
| 54 | +- **ai.java-conventions**: Base Java setup with JDK 17 toolchain, targets Java 8 |
| 55 | +- **ai.javaagent-instrumentation**: Plugin for OpenTelemetry instrumentation modules |
| 56 | +- **ai.smoke-test-war**: WAR-based smoke test applications |
| 57 | +- **ai.shadow-conventions**: JAR shadowing with relocation rules |
| 58 | + |
| 59 | +### Agent JAR Assembly Process |
| 60 | + |
| 61 | +The agent JAR is built in **3 critical steps** (see `agent/agent/build.gradle.kts`): |
| 62 | + |
| 63 | +1. **Relocate** distro-specific libraries to avoid conflicts |
| 64 | +2. **Isolate** classes to `inst/` directory with `.classdata` extensions |
| 65 | +3. **Merge** with upstream OpenTelemetry agent, excluding duplicates |
| 66 | + |
| 67 | +### Configuration Pattern |
| 68 | + |
| 69 | +- Main config: `Configuration.java` - comprehensive JSON-based configuration |
| 70 | +- Environment variables: `APPLICATIONINSIGHTS_CONNECTION_STRING`, etc. |
| 71 | + |
| 72 | +### Smoke Test Pattern |
| 73 | + |
| 74 | +- **Framework**: `smoke-tests/framework/` - shared test infrastructure |
| 75 | +- **Apps**: `smoke-tests/apps/` - containerized test applications |
| 76 | +- **Assertions**: `DependencyAssert`, `RequestAssert`, `MetricAssert` for validating telemetry |
| 77 | +- **Fake Ingestion**: Mock Application Insights endpoint for testing |
| 78 | +- **Environment Matrix**: Tests run across multiple environments (Java 8/11/17/21/23, Tomcat/Wildfly, HotSpot/OpenJ9) |
| 79 | +- **Nested Test Classes**: Each abstract test class has nested static classes for different environments: |
| 80 | + ```java |
| 81 | + abstract class HttpClientTest { |
| 82 | + @Environment(TOMCAT_8_JAVA_8) |
| 83 | + static class Tomcat8Java8Test extends HttpClientTest {} |
| 84 | + |
| 85 | + @Environment(TOMCAT_8_JAVA_11) |
| 86 | + static class Tomcat8Java11Test extends HttpClientTest {} |
| 87 | + } |
| 88 | + ``` |
| 89 | + |
| 90 | +## Common Patterns |
| 91 | + |
| 92 | +### Error Handling |
| 93 | + |
| 94 | +Use `FriendlyException` for user-facing errors with actionable messages: |
| 95 | + |
| 96 | +```java |
| 97 | +throw new FriendlyException( |
| 98 | + "Connection string is required", |
| 99 | + "Please set APPLICATIONINSIGHTS_CONNECTION_STRING environment variable"); |
| 100 | +``` |
| 101 | + |
| 102 | +### Dependency Management |
| 103 | + |
| 104 | +- All dependencies managed through `dependencyManagement/` module |
| 105 | +- Strict version conflict resolution (`failOnVersionConflict()`) |
| 106 | +- Dependency locking enabled for reproducible builds |
| 107 | + |
| 108 | +### Testing Patterns |
| 109 | + |
| 110 | +- **Unit Tests**: Standard JUnit 5 with 15-minute timeout |
| 111 | +- **Smoke Tests**: Containerized integration tests with fake ingestion |
| 112 | +- **Muzzle Tests**: Bytecode compatibility validation for instrumentation |
| 113 | + |
| 114 | +## Key Files for Understanding |
| 115 | + |
| 116 | +- `agent/agent/build.gradle.kts` - Agent assembly process |
| 117 | +- `agent/agent-tooling/src/main/java/.../configuration/Configuration.java` - Main configuration |
| 118 | +- `smoke-tests/framework/src/main/java/.../smoketest/` - Test infrastructure |
| 119 | +- `buildSrc/src/main/kotlin/ai.*.gradle.kts` - Build conventions |
| 120 | + |
| 121 | +## Development Tips |
| 122 | + |
| 123 | +- Agent JAR must be self-contained (no external dependencies) |
| 124 | +- Bootstrap classes are loaded early - keep minimal |
| 125 | +- Use `hideFromDependabot()` for test-only dependencies |
| 126 | +- Smoke tests validate end-to-end functionality in realistic environments |
| 127 | +- Check `gradle.lockfile` when dependency issues arise |
0 commit comments