-
Notifications
You must be signed in to change notification settings - Fork 18
[Changes Requested] Maven plugin for appmap java recorder #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
dustinbyrne
merged 13 commits into
getappmap:master
from
marcuss:maven-plugin-appmap-java
Feb 25, 2021
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
78c39f1
Initial version of java map plugin.
marcuss 1692b04
Trying to register a java recorder by code from within the plugin mojo.
marcuss 51c1cb7
Adding the missing agent library so the plugin can fire up the record…
marcuss a3df52e
First Attempt to add proper test to the maven dependency project.
marcuss 02e18fd
Renaming project artifacts to adhere to tech specs.
marcuss 909bbce
First working version of the AppMap plugin being loaded as per techni…
marcuss 95a78b9
Minor refactor of the working command line version.
marcuss f021384
Minor refactor of the working command line version.
marcuss 4caa606
Maven Plugin for AppMap Java Agent.
marcuss d93311b
Added README.md file.
marcuss aded373
Changes as requested in code review. drop the java identifier since i…
marcuss 1581894
changed as requested during code review PR
marcuss 33849a8
Fixed build issue.
marcuss File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| AppLand AppMap Maven Plugin for Java | ||
| -------------------------------- | ||
|
|
||
|
|
||
| - [Building](#building) | ||
| - [Agent Configuration](#agent-configuration) | ||
| - [Maven Plugin Configuration](#maven-plugin-config) | ||
| - [Plugin Goals](#plugin-goals) | ||
| - [Plugin configuration options](#plugin-configuration) | ||
| - [Example](#example) | ||
|
|
||
|
|
||
| # Building | ||
| Artifacts will be written to `target/` use `appmap-java-plugin-[VERSION].jar`. as your maven plugin. | ||
| ```bash | ||
| $ mvn clean install | ||
| ``` | ||
|
|
||
| # Agent Configuration | ||
| When you run your program, the agent reads configuration settings from `appmap.yml` by default. | ||
|
|
||
| Please read configuration options from [AppMap Java Agent README.md](../README.md) | ||
|
|
||
| # Maven Plugin Configuration | ||
|
|
||
| ## Plugin goals | ||
| prepare-agent : adds appmap.jar to JVM execution as javaagent | ||
|
|
||
| ## Plugin configuration options | ||
| outputDirectory (default: ./target/appmap/) | ||
| configFile (default: ./appmap.yml) | ||
| debug (enabled|disabled, default: disabled) | ||
| eventValueSize (integer, default 1024) | ||
| skip(Boolean, default false) | ||
|
|
||
| ## Example plugin config in a standard POM.xml file | ||
| ```xml | ||
| <!-- AppMap Java agent, default parameters --> | ||
| <plugin> | ||
| <groupId>com.appland</groupId> | ||
| <artifactId>appmap-maven-plugin</artifactId> | ||
| <version>${appmap-java.version}</version> | ||
| <configuration> | ||
| <outputDirectory></outputDirectory> | ||
| <configFile>appmap.yml</configFile> | ||
| <debug>enabled</debug> | ||
| <eventValueSize>1024</eventValueSize> | ||
| <skip>false</skip> | ||
| </configuration> | ||
| <executions> | ||
| <execution> | ||
| <goals> | ||
| <goal>prepare-agent</goal> | ||
| </goals> | ||
| </execution> | ||
| </executions> | ||
| </plugin> | ||
| ``` | ||
|
|
||
|
|
||
| # Running | ||
| To run the java agent with correct plugin configuration you only need to build your project as usual without skipping | ||
| the test goal. | ||
|
|
||
| ```bash | ||
| $ mvn clean install | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
| <groupId>com.appland</groupId> | ||
| <artifactId>appmap-maven-plugin</artifactId> | ||
| <packaging>maven-plugin</packaging> | ||
| <version>0.5.0-SNAPSHOT</version> | ||
| <name>Appland Java Recorder Maven Plugin</name> | ||
| <description>This maven plugin helps you automatically generate an Appland AppMap using the Java Recorder. | ||
| </description> | ||
| <url>https://github.com/applandinc/appmap-java/tree/master/java-maven-plugin</url> | ||
|
|
||
| <properties> | ||
| <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
| <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> | ||
| </properties> | ||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>com.appland</groupId> | ||
| <artifactId>appmap-agent</artifactId> | ||
| <version>0.5.0</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>org.apache.maven</groupId> | ||
| <artifactId>maven-plugin-api</artifactId> | ||
| <version>3.6.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.apache.maven.plugin-tools</groupId> | ||
| <artifactId>maven-plugin-annotations</artifactId> | ||
| <version>3.6.0</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.apache.maven</groupId> | ||
| <artifactId>maven-core</artifactId> | ||
| <version>3.5.4</version> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>junit</groupId> | ||
| <artifactId>junit</artifactId> | ||
| <version>4.13.1</version> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-plugin-plugin</artifactId> | ||
| <version>3.6.0</version> | ||
| <configuration> | ||
| <!-- see http://jira.codehaus.org/browse/MNG-5346 --> | ||
| <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound> | ||
| </configuration> | ||
| <executions> | ||
| <execution> | ||
| <id>mojo-descriptor</id> | ||
| <goals> | ||
| <goal>descriptor</goal> | ||
| </goals> | ||
| </execution> | ||
| </executions> | ||
| </plugin> | ||
| </plugins> | ||
| </build> | ||
| </project> |
123 changes: 123 additions & 0 deletions
123
appmap-java-maven-plugin/src/main/java/com/appland/appmap/AppMapAgentMojo.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| package com.appland.appmap; | ||
|
|
||
| import org.apache.commons.lang3.StringEscapeUtils; | ||
| import org.apache.maven.artifact.Artifact; | ||
| import org.apache.maven.plugin.AbstractMojo; | ||
| import org.apache.maven.plugin.MojoExecutionException; | ||
| import org.apache.maven.plugins.annotations.Parameter; | ||
| import org.apache.maven.project.MavenProject; | ||
|
|
||
| import java.io.File; | ||
| import java.util.*; | ||
|
|
||
| import static java.lang.String.format; | ||
|
|
||
| public abstract class AppMapAgentMojo extends AbstractMojo { | ||
|
|
||
| static final String APPMAP_AGENT_ARTIFACT_NAME = "com.appland:appmap-agent"; | ||
| static final String SUREFIRE_ARG_LINE = "argLine"; | ||
|
|
||
| @Parameter(property = "skip") | ||
| protected boolean skip = false; | ||
|
|
||
| @Parameter(property = "project.outputDirectory") | ||
| protected File outputDirectory = new File("tmp"); | ||
|
|
||
| @Parameter(property = "project.configFile") | ||
| protected File configFile = new File("appmap.yml"); | ||
|
|
||
| @Parameter(property = "project.debug") | ||
| protected String debug = "disabled"; | ||
|
|
||
| @Parameter(property = "project.eventValueSize") | ||
| protected Integer eventValueSize = 1024; | ||
|
|
||
| @Parameter(property = "plugin.artifactMap") | ||
| protected Map<String, Artifact> pluginArtifactMap; | ||
|
|
||
| @Parameter(property = "project") | ||
| private MavenProject project; | ||
|
|
||
| public abstract void execute() throws MojoExecutionException; | ||
|
|
||
| protected void skipMojo() { | ||
| } | ||
|
|
||
| protected void loadAppMapJavaAgent() { | ||
| final String newValue = buildArguments(); | ||
| setProjectArgLineProperty(newValue); | ||
| getLog().info(SUREFIRE_ARG_LINE | ||
| + " set to " + StringEscapeUtils.unescapeJava(newValue)); | ||
| } | ||
|
|
||
| /** | ||
| * This method builds the needed parameter to run the Agent, if previous configuration is found is also attached in | ||
| * the SUREFIRE_ARG_LINE, if previous version of the AppMap agent is found is removed and replaced with the version | ||
| * of this maven plugin | ||
| * | ||
| * @return formatted and escaped arguments to run on command line | ||
| */ | ||
| private String buildArguments() { | ||
| List<String> args = new ArrayList<String>(); | ||
| final String oldConfig = getCurrentArgLinePropertyValue(); | ||
| if (oldConfig != null) { | ||
| final List<String> oldArgs = Arrays.asList(oldConfig.split(" ")); | ||
| removeOldAppMapAgentFromCommandLine(oldArgs); | ||
| args.addAll(oldArgs); | ||
| } | ||
| addMvnAppMapCommandLineArgsFirst(args); | ||
| StringBuilder builder = new StringBuilder(); | ||
| for ( String arg : args) { | ||
| builder.append(arg).append(" "); | ||
| } | ||
| return builder.toString(); | ||
| } | ||
|
|
||
| /** | ||
| * Generate required quotes JVM argument based on current configuration and | ||
| * prepends it to the given argument command line. If a agent with the same | ||
| * JAR file is already specified this parameter is removed from the existing | ||
| * command line, does the same for xbootclasspath command. | ||
| */ | ||
| private void removeOldAppMapAgentFromCommandLine(List<String> oldArgs) { | ||
| final String plainAgent = format("-javaagent:%s", getAppMapAgentJar()); | ||
| final String xbootClasspath = format("-Xbootclasspath/a:%s", getAppMapAgentJar()); | ||
| for (final Iterator<String> i = oldArgs.iterator(); i.hasNext(); ) { | ||
| final String oldCommand = i.next(); | ||
| if (oldCommand.startsWith(plainAgent) || oldCommand.startsWith(xbootClasspath)) { | ||
| i.remove(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private void addMvnAppMapCommandLineArgsFirst(List<String> args) { | ||
| args.add(StringEscapeUtils.escapeJava( | ||
| format("-Xbootclasspath/a:%s", getAppMapAgentJar(), this) | ||
| )); | ||
| args.add(StringEscapeUtils.escapeJava( | ||
| format("-javaagent:%s=%s", getAppMapAgentJar(), this) | ||
| )); | ||
|
|
||
| args.add(0, "-Dappmap.debug=" + StringEscapeUtils.escapeJava(debug)); | ||
| args.add(0, "-Dappmap.output.directory=" + StringEscapeUtils.escapeJava(format("%s", outputDirectory))); | ||
| args.add(0, "-Dappmap.config.file=" + StringEscapeUtils.escapeJava(format("%s", configFile))); | ||
| args.add(0, "-Dappmap.event.valueSize=" + eventValueSize); | ||
| } | ||
|
|
||
|
|
||
| private Object setProjectArgLineProperty(String newValue) { | ||
| return project.getProperties().setProperty(SUREFIRE_ARG_LINE, newValue); | ||
| } | ||
|
|
||
| private String getCurrentArgLinePropertyValue() { | ||
| return project.getProperties().getProperty(SUREFIRE_ARG_LINE); | ||
| } | ||
|
|
||
| protected File getAppMapAgentJar() { | ||
| return pluginArtifactMap.get(APPMAP_AGENT_ARTIFACT_NAME).getFile(); | ||
| } | ||
|
|
||
| public MavenProject getProject() { | ||
| return project; | ||
| } | ||
| } |
32 changes: 32 additions & 0 deletions
32
appmap-java-maven-plugin/src/main/java/com/appland/appmap/LoadJavaAppMapAgentMojo.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package com.appland.appmap; | ||
|
|
||
|
|
||
| import org.apache.maven.plugin.MojoExecutionException; | ||
| import org.apache.maven.plugins.annotations.LifecyclePhase; | ||
| import org.apache.maven.plugins.annotations.Mojo; | ||
|
|
||
| /** | ||
| * Goal that adds appmap.jar to JVM execution as javaagent, | ||
| * right before the test execution begins. | ||
| */ | ||
| @Mojo(name = "prepare-agent", defaultPhase = LifecyclePhase.TEST_COMPILE) | ||
| public class LoadJavaAppMapAgentMojo extends AppMapAgentMojo { | ||
|
|
||
| @Override | ||
| public void execute() | ||
| throws MojoExecutionException { | ||
| try { | ||
| if (skip) { | ||
| getLog().info("Skipping AppLand AppMap execution because property skip is set."); | ||
| skipMojo(); | ||
| return; | ||
| } else { | ||
| getLog().info("Initializing AppLand AppMap Java Recorder." ); | ||
| loadAppMapJavaAgent(); | ||
| } | ||
| } catch (Exception e) { | ||
| getLog().error("Error initializing AppLand AppMap Java Recorder"); | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
| } | ||
51 changes: 51 additions & 0 deletions
51
appmap-java-maven-plugin/src/test/java/com/appland/appmap/LoadJavaMapAgentMojoTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.appland.appmap; | ||
|
|
||
| import static org.junit.Assert.assertEquals; | ||
|
|
||
| import com.appland.appmap.output.v1.Event; | ||
|
|
||
| import com.appland.appmap.record.IRecordingSession; | ||
| import com.appland.appmap.record.Recorder; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
|
|
||
| public class LoadJavaMapAgentMojoTest { | ||
|
|
||
| @Before | ||
| public void before() throws Exception { | ||
| final IRecordingSession.Metadata metadata = | ||
| new IRecordingSession.Metadata(); | ||
|
|
||
| Recorder.getInstance().start(metadata); | ||
| } | ||
|
|
||
| @Test | ||
| public void testAllEventsWritten() { | ||
| final Recorder recorder = Recorder.getInstance(); | ||
| final Long threadId = Thread.currentThread().getId(); | ||
| final Event[] events = new Event[] { | ||
| new Event(), | ||
| new Event(), | ||
| new Event(), | ||
| }; | ||
|
|
||
| for (int i = 0; i < events.length; i++) { | ||
| final Event event = events[i]; | ||
| event | ||
| .setDefinedClass("SomeClass") | ||
| .setMethodId("SomeMethod") | ||
| .setStatic(false) | ||
| .setLineNumber(315) | ||
| .setThreadId(threadId); | ||
|
|
||
| recorder.add(event); | ||
| assertEquals(event, recorder.getLastEvent()); | ||
| } | ||
|
|
||
| final String appmapJson = recorder.stop(); | ||
| final String expectedJson = "\"thread_id\":" + threadId.toString(); | ||
| final int numMatches = StringUtils.countMatches(appmapJson, expectedJson); | ||
| assertEquals(numMatches, events.length); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.