ryandens / javaagent-gradle-plugin

A set of Gradle plugins to ease building Java applications that leverage instrumentation agents in development and/or in production
Apache License 2.0
48 stars 8 forks source link

Javaagent Gradle Plugin

Build

Javaagent Application Plugin Javaagent Jib Plugin Javaagent Test Plugin Javaagent OTel Modification Plugin

A set of vendor-agnostic Gradle plugins to ease building Java applications that leverage instrumentation agents in development and/or in production

The work on this software project is in no way associated with my employer nor with the role I'm having at my employer. Any requests for changes will be decided upon exclusively by myself based on my personal preferences. I maintain this project as much or as little as my spare time permits.

Application Plugin integration

This Gradle plugin tightly integrates with the Gradle application plugin to make instrumenting your application build by Gradle easy! Simply register the javaagent-application plugin and then specify the javaagent you would like to attach in the dependencies block

plugins {
    application
    id("com.ryandens.javaagent-application") version "0.6.1"
}

application {
    mainClass.set("yourMainClassName")
}

dependencies {
    javaagent("io.opentelemetry.javaagent:opentelemetry-javaagent:1.11.1")
}

Now, when you run the ApplicationPlugin's run task, your application will be instrumented with the javaagent specified by the javaagent Gradle configuration! In addition, the distributions created by the distTar and distZip ApplicationPlugin tasks include the javaagent JAR in the archive's dependency directory. Finally, the distribution start scripts have been modified to automatically attach the agent via the command line -javaagent flag.

Jib integration

Jib is a build tool for containerizing Java applications without a Docker daemon. This project integrates with the jib-gradle-plugin via the jib-extensions API to add the javaagent JAR as a new layer in the container image and modifies the entrypoint of the container to automatically attach the agent at runtime via the command line -javaagent flag. Simply register the javaagent-jib plugin and then specify the javaagent you would like to attach in the dependencies block.

plugins {
    java
    id("com.google.cloud.tools.jib") version "3.1.4"
    id("com.ryandens.javaagent-jib") version "0.6.1"
}

jib.container {
    mainClass = "yourMainClassName"
}

dependencies {
    javaagent("io.opentelemetry.javaagent:opentelemetry-javaagent:1.11.1")
}

Java Test Task integration

The Gradle Java Plugin creates a test task that launches a forked JVM from the build for testing purposes. The com.ryandens.javaagent-test plugin automatically configures the jvm to be launched with the javaagents specified by the javaagent configuration attached. This enables the use of runtime analysis via javaagents for projects. Common uses cases for this include collecting telemetry data from test runs or leveraging an Interactive Application Security Testing (IAST) product.

plugins {
    java
    id("com.ryandens.javaagent-test") version "0.6.1"
}

tasks.named<Test>("test") {
  useJUnitPlatform()
}

dependencies {
    javaagent("io.opentelemetry.javaagent:opentelemetry-javaagent:1.11.1")  
    testJavaagent("com.ryandens.example:agent:1.0.0") // only attached to test task but ignored by other gradle plugins in this project.
}

OpenTelemetry Integration

OpenTelemetry is a set of tools that enable distributed tracing. OpenTelemetry Instrumentation for Java is a project that is often consumed as a javaagent in order to instrument OSS libraries with distributed tracing logic. There are many distributions of this agent by specific vendors. In addition, OpenTelemetry offers a number of extension points that consumers of the libraries and vendors can take advantage of.

This integration strives to make it easier for consumers of OpenTelemetry distributions to modify their chosen distributions with other extensions and instrumentation modules. This is desirable because OpenTelemetry provides a high-level API for instrumentation which makes writing instrumentation modules using their API a lot more approachable for those unfamiliar with bytecode manipulation.

This integration can be used by applying the javaagent-otel-modification plugin, specifying the OTel distribution you would like to extend and the libraries or projects you would like to extend it with. In addition, this plugin also applies the JavaagentBasePlugin and registers the outputted extended OpenTelemetry agent as a project dependency with the javaagent configuration. This does effectively nothing on its own, but allows for seamless integration with plugins that leverage the javaagent configuration (such as javaagent-application and javaagent-jib) so that the extended OpenTelemetry agent is configured is included in the desired application distribution or execution method.

plugins {
  application
  id("com.ryandens.javaagent-otel-modification") version "0.6.1"
  id("com.ryandens.javaagent-application") version "0.6.1"
}

dependencies {
  // the otel configuration is used to identify the desired distribution to modify
  otel("io.opentelemetry.javaagent:opentelemetry-javaagent:1.12.0")
  // the otelExtension configuration expects a shaded JAR that conforms to OTel's rules
  otelExtension("io.opentelemetry.contrib:opentelemetry-samplers:1.12.0-alpha")
  // the otelInstrumentation expects a project whose references to the OTel API have been relocated in order to match the agent's shaded class names. Note, this plugin will rename the files from .class -> .classdata 
  otelInstrumentation(project(":custom-instrumentation"))
}

application {
  // Define the main class for the application.
  mainClass.set("com.ryandens.javaaagent.example.App")
}

setOf(tasks.distTar, tasks.distZip).forEach {
  it.configure {
    dependsOn(tasks.extendedAgent)
  }
}