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

Add ability to pass arguments to a Java agent #50

Open felixscheinost opened 10 months ago

felixscheinost commented 10 months ago

It would be cool if it would be possible to pass arguments to an agent.

It seems that currently JavaForkOptionsConfigurer always does -javaagent:<agent jar> only.

Arguments could be passed using -javaagent:<agent jar>=<arguments>.

ryandens commented 10 months ago

Hi @felixscheinost, thanks for the suggestion! Just to make sure I understand the use case correctly, is the idea that you wanted to provide opinionated conventions for configuration across all distribution/execution contexts? I was thinking about providing a configuration extension point for this agent in https://github.com/ryandens/javaagent-gradle-plugin/issues/3 but ultimately determined the extension point itself wasn't necessary for vendors to build something opinionated by composing rather than extending this plugin.

The main challenge that I could envision is figuring out how to respect an order of precedence between system properties defined on a top level construct provided by this plugin and system properties provided explicitly to the task this plugin configures (such as the dist, jib, or run tasks). This could pose more risk to users accidentally configuring their application the wrong way than the benefit it would provide, but I'm open to discussion here if you can provide more context on how you as a user might expect this to work

felixscheinost commented 10 months ago

Thanks for your quick response!

Part of your response went over my head but I think that no, I am not talking about a convention for configuration.

A concrete example would be jmx_exporter agent.

It is configured like this:

java -javaagent:./jmx_prometheus_javaagent-0.19.0.jar=12345:config.yaml -jar yourJar.jar

where 12345:config.yaml needs to be customized for each application.

If I understand correctly, doing:

dependencies {
   javaagent("io.prometheus.jmx:jmx_prometheus_javaagent:0.20.0")
}

would modify the JVM args like this:

java -javaagent:<jmx_prometheus_javaagent.jar dependency> [...]

right? And I think currently this plugin doesn't offer any way to set the =12345:config.yaml part of the JVM argument?

ryandens commented 9 months ago

Cool, this makes sense to me and seems like a reasonable use case. I'll take a look at what's feasible. Something I'd like to make sure we get correct is to make sure that these values can be different for each distribution, if necessary. Most likely, we'd want to set a default value for all distributions while allowing individual distributions to override that value.

One of the value propositions of this plugin is that it allows users to configure their javaagent dependencies just like they would their other dependencies, so I'm hoping to avoid complicated configuration to this plugin.

ryandens commented 9 months ago

Took a quick stab at this. The API I'm working on looks kinda like this:

The name agentOptions is derived from java.lang.instrument package-info.java

javaagent {
  agentOptions = '12345:config.yaml'
}

application {
    mainClass = 'com.ryandens.HelloWorld'
    applicationDefaultJvmArgs = ['-Xmx256m']
    javaagent {
        agentOptions = '12345:config.yaml'
    }
}

tasks.run {
    // defaults to whatever was provided in JavaApplication extension but allowed to be overriden for the run task here 
    javaagent {
        agentOptions = '12345:config.yaml'
    }
}

jib {
 javaagent {
        agentOptions = '12345:config.yaml'
 }
}

However, this quickly ran into the problem of supporting multiple javaagents (a feature this plugin already supports).

The options, I think are:

  1. Fail the build with an exception if a user tries to configure multiple java agents and specify and agent options flag
  2. Have the API of the javaagent extension be something like
 javaagent {
        agentOptions = mapOf("agentFileName" to "12345:config.yaml")
 }

Which gives the most flexibility but adds the most complexity. In addition, it forces users to know the file name their maven artifact coordinates resolve to, which makes the usage of an agent more brittle.

I'm going to sit on this for a bit as a result so I can figure out what makes the most sense for the plugin as a whole. But, if people want to add feedback, context, or ideas, please do so.

jmvillagra commented 5 months ago

Hej, Any progress here? I was looking into the exact use case for the prometheus.jmx. Cool plugin btw.

ryandens commented 5 months ago

Thanks! I have the changes in a feature branch i'm working on, but haven't been able to upstream them yet. Will post a more detailed update soon