Setting up a Java Agent

By Chris Maki | March 19, 2019

I was recently testing out Appoptics APM for an article I was writing. During the process I noticed there wasn’t a lot of info online about setting up a gradle project with a Java agent, so I thought I’d write one. I’ll start with a quick overview of some popular Java agents and then show you how to create a Java Gradle project and add a Java agent to it. At the end of the post, there will be a working Java application that includes a Java agent.

Java Agents

Java agents have been around for a long time, they were really popular in the early 2010’s and are still actively used today. That said, I think Java agents are more common than ever before, as a result, I found it harder to find good documentation online. I think its because everyone sorta knows how it’s done. Except for me.

I haven’t configured a Java agent in years so I thought I’d put together a short post on creating a simple Java, Gradle, Spring Boot application and add a Java agent to the project. The process of adding a Java agent is the same for any agent. Here are a few popular APM tools that use a Java agent:

  1. New Relic

  2. DataDog APM

  3. Want to write you own java agent? Check out this tutorial.

  4. ZeroTurnaround how to create a Java Agent from JavaOne 2016.

Create Project

To create your project skeleton, use the Spring Initializr project available at start.spring.io. A quick note, all the examples in this post use a tool called HTTPie, it makes working with web service endpoints so easy. Install instructions are here.

When you run the Spring Initializr from the command line, the zip file that’s created does not have a root directory, when you create a project from the Initializr website, the zip file will have a root directory.

1 2 3 4 5 6 7
mkdir rcs-app cd rcs-app http -j https://start.spring.io/starter.zip type==gradle-project \ packageName==com.ripcitysoftware.agent \ dependencies==web,devtools,actuator -o rcs-agent.zip unzip rcs-agent.zip (1) rm rcs-agent.zip
1 Since we created the zip file from the command line, there’s no root directory

You are now ready to run the Spring Boot basic application, it won’t do anything BUT because we added the actuator dependency, you can access a few endpoints, this is enough for this example.

gradle bootRun

> Configure project :
Copying task ':copyAppOptics' to /private/tmp/rcs-app/build/lib

> Task :bootRun

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-03-19 10:18:48.535  INFO 67002 --- [  restartedMain] c.ripcitysoftware.agent.DemoApplication  : Starting DemoApplication on macinfiityi9mbp.lan with PID 67002 (/private/tmp/rcs-app/build/classes/java/main started by chrismaki in /private/tmp/rcs-app)
...

Install APM

I’ll be using Appoptics APM for this example. The process should be the same for any APM vendor because they all run as agents and need a configuration file. For Appoptics, they only show you how to configure Maven, here you’ll configure Gradle.

The AppOptics APM config file, javaagent.json, needs to be in the same directory as the appoptics.jar file.

In order to add APM support to your Gradle project, you’ll need to update the gradle.build file created by Spring Initializr. Here is the entire, updated and annotated build.gradle file with Appoptics APM dependencies and configuration:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
plugins { id 'org.springframework.boot' version '2.1.3.RELEASE' id 'java' id 'application' (1) } apply plugin: 'io.spring.dependency-management' group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '1.8' repositories { mavenCentral() } configurations { (2) appOptics } applicationDefaultJvmArgs = ["-javaagent:$buildDir/libs/appoptics.jar"] (3) dependencies { appOptics 'com.appoptics.agent.java:appoptics-agent:+' (4) implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' runtimeOnly 'org.springframework.boot:spring-boot-devtools' testImplementation 'org.springframework.boot:spring-boot-starter-test' } task copyAppOptics(type: Copy) { (5) println "Copying ${it} to ${project.buildDir}/lib" from configurations.appOptics into "${project.buildDir}/libs" rename { it.substring(0, it.indexOf("-")) + it.substring(it.lastIndexOf("."), it.size()) } } task copyAppOpticsConfig(type: Copy) { (6) from "$buildDir/resources/main/javaagent.json" into "${project.buildDir}/libs" } assemble.dependsOn copyAppOptics, copyAppOpticsConfig (7) bootRun.dependsOn copyAppOptics, copyAppOpticsConfig (8)
1 Add the application plugin, this is needed so you can set the applicationDefaultJvmArgs variable.
2 Add the appOptics configuration (you can use any name you’d like, but the name here needs to match the name used in the dependencies section).
3 This is where we add the AppOptics APM agent, without this line, the APM agent wouldn’t be included in the project. We don’t specify a version so you always get the latest, released version.
4 Add the latest AppOptics APM agent to the project.
5 This task will take the appoptics.jar dependency defined in step (5), remove the version number, rename it to appoptics.jar and then copy it to the build dir.
6 This task copies the javaagent.json file and places it in the same directory as the AppOptics APM agent.
7 This triggers the copyAppOptics task when the assemble task is executed.
8 Ensures appoptics.jar and javaagent.json are copied to $buildDir/libs before Spring Boot Run is executed.

You may be wondering, where did javaagent.json come from? Great question, in order to get a configuration file you need to create an Appoptics account, and then download the config file. Whether you use Appoptics or another tool, they all need a configuration file. You can download the config file for Appoptics from here.

Running your app

Once your project is configured and running correctly, you should see the following output from AppOptics (you may have to scroll back to the top of your output, the agent reports its status before Spring Boot starts):

 $ gradle clean bootrun
 ...
> Task :bootRun
Mar 19, 2019 INFO [AppOptics] Java agent version 6.9.0 started successfully
Mar 19, 2019 INFO [AppOptics] Java agent jar location: /private/tmp/rcs-app/build/libs/appoptics.jar
Mar 19, 2019 INFO [AppOptics] Java agent config location: /private/tmp/rcs-app/build/libs/javaagent.json
Mar 19, 2019 INFO [AppOptics] Java agent service name: rcs-service
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

Congratuations, you now have a Spring Boot, Gradle project running a Java agent. Other than finding the APM agents configuration file, everything you need is done in the build.gradle file.

Conclusion

In this quick tutorial, I created a basic Spring Boot project, ran it from the command line to make sure it worked correctly. Then I updated the gradle.build file with a java agent dependency and added two functions to copy the agent and its configuration file to the build directory. Finally, I ran the app and verified that the Java agent started and the app was still working.

Is your configuration for Gradle the same for a Java agent? If not, please let me know how you’ve got it configured. If you found this post helpful, please Upvote it or share it on Facebook or Twitter.

Thanks for dropping by!

comments powered by Disqus