Test Glowroot Custom Plugin Jvm Instrumentation
This is a test for capturing some methods calls performed by an instrumentated jvm.
It used internally a custom plugin writen with Glowroot
A sample usage is here to detect all file write access performed by maven in "/home" sub dirs.
Internally, the plugin instrument all calls to "java.io.FileOutputStream.open(" and "java.io.File.renameTo()",
filter if the path starts with "/home/", and print the corresponding stack trace with the count/total of write access.
Discover Glowroot
https://github.com/glowroot
Glowroot is an APM (Application Performance Management) like many other expensive closed-source tools, but it is free and Open Source..
The performance measurment offer a rich centralised server and a web UI, but this is not required. Glowroot can run as embedded server, or no server.
Moreover, glowroot is internally based on a jvm instrumentation engine, is modular by plugins, and can be used without the performance api parts.
Step 1: download and unzip GlowRoot agent
wget https://github.com/glowroot/glowroot/releases/download/v0.13.4/glowroot-0.13.4-dist.zip
unzip glowroot-0.13.4-dist.zip
Step 2: Create a custom Glowroot plugin
Create the pom.xml with the following dependencies
<properties>
<glowroot.version> 0.13.4</glowroot.version>
</properties>
<dependencies>
<!--
<dependency>
<groupId>org.glowroot</groupId>
<artifactId>glowroot-agent-api</artifactId>
<version>${glowroot.version}</version>
<scope>provided</scope>
</dependency>
-->
<dependency>
<groupId> org.glowroot</groupId>
<artifactId> glowroot-agent-plugin-api</artifactId>
<version> ${glowroot.version}</version>
<scope> provided</scope>
</dependency>
</dependencies>
Edit the file src/main/resources/META-INF/glowroot.plugin.json
{
"name" : "File Plugin" ,
"id" : "file" ,
"properties" : [
],
"aspects" : [
"fr.an.test.glowroot.FileAspect"
]
}
Then code in java the instrumentation.
Here, I am not interrested in performance traces, but only adding a "System.out.println()" for all java.io.* calls that modify files:
java.io.FileOutputStream.open(String,boolean)
java.io.File.mkdir()
java.io.File.mkdirs()
java.io.File.renameTo(File)
java.io.File.delete()
java.io.File.deleteOnExit()
package fr . an . test . glowroot ;
import java.io.File ;
import org.glowroot.agent.plugin.api.weaving.BindParameter ;
import org.glowroot.agent.plugin.api.weaving.BindReceiver ;
import org.glowroot.agent.plugin.api.weaving.OnBefore ;
import org.glowroot.agent.plugin.api.weaving.Pointcut ;
public class FileAspect {
/**
* Instrument calls to <code>java.io.FileOutputStream.open()</code>
*/
@Pointcut ( className = "java.io.FileOutputStream" , methodName = "open" , methodParameterTypes = { "java.lang.String" , "boolean" })
public static class FileOutputStreamOpenAdvice {
@OnBefore
public static void onBefore ( @BindParameter String path ) {
System . out . println ( "***** FileOutputStream.open() '" + path + "' ... " );
}
}
// more... truncated
}
Compile it:
mvn package
Step 3: Run a jvm with the Glowroot plugin and agent
execute a java process, by adding jvm arguments
-javaagent :./glowroot/glowroot.jar -Xbootclasspath /a:./glowroot-plugin.jar"
For example for instrumenting maven itself
./mvn-glowroot-file.sh install
cf detailed script:
#!/bin/bash
# file: mvn-glowroot-file.sh
# script similar to "mvn", that add glowroot file write plugin instrumentation
PROJECT_VERSION = $( mvn -q -DforceStdout help :evaluate -Dexpression = project.version)
PLUGIN_JAR = "./target/test-glowroot- ${ PROJECT_VERSION } .jar"
MAVEN_OPTS = " ${ MAVEN_OPTS } -javaagent:./glowroot/glowroot.jar"
MAVEN_OPTS = " ${ MAVEN_OPTS } -Xbootclasspath/a: ${ PLUGIN_JAR } "
# MAVEN_OPTS="${MAVEN_OPTS} -Dglowroot.debug.printClassLoading=true"
export MAVEN_OPTS
mvn $@
Step 4: Analyse logs
Here for the mvn execution with the custom glowroot agent, I get these result logs.
2019-05-11 18:48:54.056 INFO org.glowroot - Glowroot version: 0.13.4, built 2019-04-21 20:27:33 +0000
2019-05-11 18:48:54.056 INFO org.glowroot - Java version: 1.8.0_202 (Oracle Corporation / Windows 10)
2019-05-11 18:48:54.056 INFO org.glowroot - Java args: -javaagent:./glowroot/glowroot.jar -Xbootclasspath/a:./target/test-glowroot-0.0.1-SNAPSHOT.jar
**** cinit class fr.an.test.glowroot.FileAspect
**** logging only java.io.File modifications under path:'' with pattern:.*
***** (1/1) FileOutputStream.open() 'C:\ProgramData\Oracle\Java\.oracle_jre_usage\8f6ba24f3ed3fb62.timestamp'
***** File.mkdirs() 'C:\cygwin64\tmp'
***** (2/2) FileOutputStream.open() 'D:\arn\devPerso\mygithub\test-snippets\test-glowroot\glowroot\data\data.lock.db'
2019-05-11 18:49:02.814 INFO org.glowroot - UI listening on 127.0.0.1:4000 (to access the UI from remote machines, change the bind address to 0.0.0.0, either in
the Glowroot UI under Configuration > Web or directly in the admin.json file, and then restart JVM to take effect)
***** File.mkdirs() 'C:\Users\arnau\.m2\repository'
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< fr.an.tests:test-glowroot >----------------------
[INFO] Building test-glowroot 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ test-glowroot ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:compile (default-compile) @ test-glowroot ---
***** (3/3) FileOutputStream.open() 'D:\arn\devPerso\mygithub\test-snippets\test-glowroot\target\maven-status\maven-compiler-plugin\compile\default-compile\input
Files.lst'
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ test-glowroot ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\arn\devPerso\mygithub\test-snippets\test-glowroot\src\test\resources
[INFO]
[INFO] --- maven-compiler-plugin:3.7.0:testCompile (default-testCompile) @ test-glowroot ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ test-glowroot ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ test-glowroot ---
***** File.mkdirs() 'D:\arn\devPerso\mygithub\test-snippets\test-glowroot\target'
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ test-glowroot ---
[INFO] Installing D:\arn\devPerso\mygithub\test-snippets\test-glowroot\target\test-glowroot-0.0.1-SNAPSHOT.jar to C:\Users\arnau\.m2\repository\fr\an\tests\test-
glowroot\0.0.1-SNAPSHOT\test-glowroot-0.0.1-SNAPSHOT.jar
***** File.mkdirs() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\0.0.1-SNAPSHOT'
[INFO] Installing D:\arn\devPerso\mygithub\test-snippets\test-glowroot\pom.xml to C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\0.0.1-SNAPSHOT\test-glowroot-0.0.1-SNAPSHOT.pom
***** (4/4) FileOutputStream.open() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\0.0.1-SNAPSHOT\test-glowroot-0.0.1-SNAPSHOT.pom'
***** File.mkdirs() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\0.0.1-SNAPSHOT'
***** File.mkdirs() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\0.0.1-SNAPSHOT'
***** (5/5) FileOutputStream.open() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\0.0.1-SNAPSHOT\maven-metadata-local.xml'
***** File.mkdirs() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot'
***** (6/6) FileOutputStream.open() 'C:\Users\arnau\.m2\repository\fr\an\tests\test-glowroot\maven-metadata-local.xml'
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.859 s
[INFO] Finished at: 2019-05-11T18:49:07+02:00
[INFO] ------------------------------------------------------------------------
***** (1/1) File.delete() 'D:\arn\devPerso\mygithub\test-snippets\test-glowroot\glowroot\data\data.lock.db'
***** (2/2) File.delete() 'D:\arn\devPerso\mygithub\test-snippets\test-glowroot\glowroot\tmp\.lock'
Conclusion
Such logs are even better when combined with stack traces and statistic counts.
It is very helpfull to understand deep inside a jvm what is going on, without touching the program source code
View the full source-code
https://github.com/Arnaud-Nauwynck/test-snippets/tree/master/test-glowroot