Skip to content

Commit

Permalink
Merge pull request #1 from newrelic-experimental/distributed2
Browse files Browse the repository at this point in the history
Distributed2
  • Loading branch information
dhilpipre authored Apr 7, 2023
2 parents 29b8ccd + b2c611d commit 58e999e
Show file tree
Hide file tree
Showing 21 changed files with 892 additions and 126 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
.java-version
.git
.github
.settings
.classpath
.project
bin
build
81 changes: 34 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,64 @@
[![New Relic Experimental header](https://github.com/newrelic/opensource-website/raw/main/src/images/categories/Experimental.png)](https://opensource.newrelic.com/oss-category/#new-relic-experimental)


![GitHub forks](https://img.shields.io/github/forks/newrelic-experimental/java-instrumentation-template?style=social)
![GitHub stars](https://img.shields.io/github/stars/newrelic-experimental/java-instrumentation-template?style=social)
![GitHub watchers](https://img.shields.io/github/watchers/newrelic-experimental/java-instrumentation-template?style=social)
![GitHub forks](https://img.shields.io/github/forks/newrelic-experimental/newrelic-java-rmi?style=social)
![GitHub stars](https://img.shields.io/github/stars/newrelic-experimental/newrelic-java-rmi?style=social)
![GitHub watchers](https://img.shields.io/github/watchers/newrelic-experimental/newrelic-java-rmi?style=social)

![GitHub all releases](https://img.shields.io/github/downloads/newrelic-experimental/java-instrumentation-template/total)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/newrelic-experimental/java-instrumentation-template)
![GitHub last commit](https://img.shields.io/github/last-commit/newrelic-experimental/java-instrumentation-template)
![GitHub Release Date](https://img.shields.io/github/release-date/newrelic-experimental/java-instrumentation-template)
![GitHub all releases](https://img.shields.io/github/downloads/newrelic-experimental/newrelic-java-rmi/total)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/newrelic-experimental/newrelic-java-rmi)
![GitHub last commit](https://img.shields.io/github/last-commit/newrelic-experimental/newrelic-java-rmi)
![GitHub Release Date](https://img.shields.io/github/release-date/newrelic-experimental/newrelic-java-rmi)


![GitHub issues](https://img.shields.io/github/issues/newrelic-experimental/java-instrumentation-template)
![GitHub issues closed](https://img.shields.io/github/issues-closed/newrelic-experimental/java-instrumentation-template)
![GitHub pull requests](https://img.shields.io/github/issues-pr/newrelic-experimental/java-instrumentation-template)
![GitHub pull requests closed](https://img.shields.io/github/issues-pr-closed/newrelic-experimental/java-instrumentation-template)
![GitHub issues](https://img.shields.io/github/issues/newrelic-experimental/newrelic-java-rmi)
![GitHub issues closed](https://img.shields.io/github/issues-closed/newrelic-experimental/newrelic-java-rmi)
![GitHub pull requests](https://img.shields.io/github/issues-pr/newrelic-experimental/newrelic-java-rmi)
![GitHub pull requests closed](https://img.shields.io/github/issues-pr-closed/newrelic-experimental/newrelic-java-rmi)


# [Project Name - use format "newrelic-java-<name>"] [build badges go here when available]
# New Relic Java Instrumentation for Java RMI

>[Brief description - what is the project and value does it provide? How often should users expect to get releases? How is versioning set up? Where does this project want to go?]
Provides instrumentation for the Java RMI on both the server and client side.

## Value

|Metrics | Events | Logs | Traces | Visualization | Automation |
|:-:|:-:|:-:|:-:|:-:|:-:|
|:x:|:x:|:x:|:white_check_mark:|:x:|:x:|

### List of Metrics,Events,Logs,Traces
|Name | Type | Description |
|:-:|:-:|:-:|
|*metric.name* | Metric| *description*|
|*event.name* | Event| *description*|
|*log.name* | Log| *description*|
|*trace.name*| Trace| *description*
|---|---|---|


## Installation

> [Include a step-by-step procedure on how to get your code installed. Be sure to include any third-party dependencies that need to be installed separately]
This use this instrumentation.
1. Download the latest release.
2. In the New Relic Java Agent directory (directory containing newrelic.jar), create a directory named extensions if it doe not already exist.
3. Copy the jars into the extensions directory.
4. Restart the application.

## Getting Started

>[Simple steps to start working with the software similar to a "Hello World"]
After deployment, you should be able to see:
The client and server transactions will be tied together with Distributed Tracing.

## Usage
### Client
See RMI calls as an external service.
### Server
See a transaction for the RMI class and method call.

>[**Optional** - Include more thorough instructions on how to use the software. This section might not be needed if the Getting Started section is enough. Remove this section if it's not needed.]
## Building

>[**Optional** - Include this section if users will need to follow specific instructions to build the software from source. Be sure to include any third party build dependencies that need to be installed separately. Remove this section if it's not needed.]

## Testing
## Building

>[**Optional** - Include instructions on how to run tests if we include tests with the codebase. Remove this section if it's not needed.]
If you make changes to the instrumentation code and need to build the instrumentation jars, follow these steps
1. Set environment variable NEW_RELIC_EXTENSIONS_DIR. Its value should be the directory where you want to build the jars (i.e. the extensions directory of the Java Agent).
2. Build one or all of the jars.
a. To build one jar, run the command: gradlew _moduleName_:clean _moduleName_:install
b. To build all jars, run the command: gradlew clean install
3. Restart the application

## Support

New Relic has open-sourced this project. This project is provided AS-IS WITHOUT WARRANTY OR DEDICATED SUPPORT. Issues and contributions should be reported to the project here on GitHub.

>[Choose 1 of the 2 options below for Support details, and remove the other one.]
>[Option 1 - no specific thread in Community]
>We encourage you to bring your experiences and questions to the [Explorers Hub](https://discuss.newrelic.com) where our community members collaborate on solutions and new ideas.
>[Option 2 - thread in Community]
>New Relic hosts and moderates an online forum where customers can interact with New Relic employees as well as other customers to get help and share best practices. Like all official New Relic open source projects, there's a related Community topic in the New Relic Explorers Hub.
>You can find this project's topic/threads here: [URL for Community thread]
## Contributing

We encourage your contributions to improve [Project Name]! Keep in mind when you submit your pull request, you'll need to sign the CLA via the click-through using CLA-Assistant. You only have to sign the CLA one time per project. If you have any questions, or to execute our corporate CLA, required if your contribution is on behalf of a company, please drop us an email at opensource@newrelic.com.
We encourage your contributions to improve Salesforce Commerce Cloud for New Relic Browser! Keep in mind when you submit your pull request, you'll need to sign the CLA via the click-through using CLA-Assistant. You only have to sign the CLA one time per project. If you have any questions, or to execute our corporate CLA, required if your contribution is on behalf of a company, please drop us an email at opensource@newrelic.com.

**A note about vulnerabilities**

Expand All @@ -82,6 +68,7 @@ If you believe you have found a security vulnerability in this project or any of

## License

[Project Name] is licensed under the [Apache 2.0](http://apache.org/licenses/LICENSE-2.0.txt) License.
New Relic Java Instrumentation for RMI is licensed under the [Apache 2.0](http://apache.org/licenses/LICENSE-2.0.txt) License.

>[If applicable: [Project Name] also uses source code from third-party libraries. You can find full details on which libraries are used and the terms under which they are licensed in the third-party notices document.]
33 changes: 33 additions & 0 deletions rmi-stubs/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

// Build.gradle generated for instrumentation module rmi-stubs

apply plugin: 'java'

dependencies {
// Declare a dependency on each JAR you want to instrument
// Example:
// implementation 'javax.servlet:servlet-api:2.5'

// New Relic Java Agent dependencies
implementation 'com.newrelic.agent.java:newrelic-agent:6.4.0'
implementation 'com.newrelic.agent.java:newrelic-api:6.4.0'
implementation fileTree(include: ['*.jar'], dir: '../libs')
implementation fileTree(include: ['*.jar'], dir: '../test-lib')
}

jar {
manifest {
attributes 'Implementation-Title': 'com.newrelic.instrumentation.rmi-stubs'
attributes 'Implementation-Vendor': 'New Relic'
attributes 'Implementation-Vendor-Id': 'com.newrelic'
attributes 'Implementation-Version': 1.0
}
}

verifyInstrumentation {
// Verifier plugin documentation:
// https://github.com/newrelic/newrelic-gradle-verify-instrumentation
// Example:
// passes 'javax.servlet:servlet-api:[2.2,2.5]'
// exclude 'javax.servlet:servlet-api:2.4.public_draft'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.newrelic.instrumentation.rmi.stubs;

import com.newrelic.agent.deps.org.objectweb.asm.ClassReader;
import com.newrelic.agent.instrumentation.classmatchers.ChildClassMatcher;

public class RMIStubsClassMatcher extends ChildClassMatcher {

public RMIStubsClassMatcher() {
super("java.rmi.server.RemoteStub");
}

@Override
public boolean isMatch(ClassLoader loader, ClassReader cr) {
boolean isChild = super.isMatch(loader, cr);
String tmp = cr.getClassName().replace('/', '.');
boolean isSystem = tmp.startsWith("java.rmi") || tmp.startsWith("sun.rmi");
return isChild && !isSystem;
}

@Override
public boolean isMatch(Class<?> clazz) {
boolean isChild = super.isMatch(clazz);
String classname = clazz.getName();
boolean isSystem = classname.startsWith("java.rmi") || classname.startsWith("sun.rmi");

return isChild && !isSystem;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.newrelic.instrumentation.rmi.stubs;

import com.newrelic.agent.instrumentation.classmatchers.ClassAndMethodMatcher;
import com.newrelic.agent.instrumentation.classmatchers.ClassMatcher;
import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher;

public class RMIStubsClassMethodMatcher implements ClassAndMethodMatcher {

private ClassMatcher classMatcher = new RMIStubsClassMatcher();
private MethodMatcher methodMatcher = new RMIStubsMethodMatcher();

@Override
public ClassMatcher getClassMatcher() {
return classMatcher;
}

@Override
public MethodMatcher getMethodMatcher() {
return methodMatcher;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.newrelic.instrumentation.rmi.stubs;

import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Map;

import com.newrelic.agent.InstrumentationProxy;
import com.newrelic.agent.deps.org.objectweb.asm.commons.Method;
import com.newrelic.agent.instrumentation.classmatchers.ClassAndMethodMatcher;
import com.newrelic.agent.instrumentation.classmatchers.OptimizedClassMatcher.Match;
import com.newrelic.agent.instrumentation.classmatchers.OptimizedClassMatcherBuilder;
import com.newrelic.agent.instrumentation.context.ClassMatchVisitorFactory;
import com.newrelic.agent.instrumentation.context.ContextClassTransformer;
import com.newrelic.agent.instrumentation.context.InstrumentationContext;
import com.newrelic.agent.instrumentation.context.InstrumentationContextManager;
import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher;
import com.newrelic.agent.instrumentation.tracing.TraceDetailsBuilder;

public class RMIStubsClassTransformer implements ContextClassTransformer {

private final InstrumentationContextManager contextManager;
private final Map<String, ClassMatchVisitorFactory> matchers = new HashMap<String, ClassMatchVisitorFactory>();

public RMIStubsClassTransformer(InstrumentationContextManager mgr,InstrumentationProxy pInstrumentation) {
contextManager = mgr;
}

protected ClassMatchVisitorFactory addMatcher(ClassAndMethodMatcher matcher) {
OptimizedClassMatcherBuilder builder = OptimizedClassMatcherBuilder.newBuilder();
builder.addClassMethodMatcher(matcher);
ClassMatchVisitorFactory matchVisitor = builder.build();
matchers.put(matcher.getClass().getSimpleName(), matchVisitor);
contextManager.addContextClassTransformer(matchVisitor, this);
return matchVisitor;
}

protected void removeMatcher(ClassAndMethodMatcher matcher) {
ClassMatchVisitorFactory matchVisitor = matchers.get(matcher.getClass().getSimpleName());
if(matchVisitor != null) {
contextManager.removeMatchVisitor(matchVisitor);
}
}

@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer, InstrumentationContext context, Match match)
throws IllegalClassFormatException {
for (Method method : match.getMethods()) {
for (ClassAndMethodMatcher matcher : match.getClassMatches().keySet()) {
if (matcher.getMethodMatcher().matches(MethodMatcher.UNSPECIFIED_ACCESS, method.getName(),
method.getDescriptor(), match.getMethodAnnotations(method))) {
int index = className.lastIndexOf('/');
if(index == -1) {
index = className.lastIndexOf('.');
}
String simpleClass = index > -1 ? className.substring(index+1) : className;
simpleClass = simpleClass.replace("_Stub", "");
String metricName = "Custom/RMI/Stub/" + simpleClass + "/" + method;
context.putTraceAnnotation(method, TraceDetailsBuilder.newBuilder().setDispatcher(true).setMetricName(metricName).build());
}
}

}

return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.newrelic.instrumentation.rmi.stubs;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.newrelic.agent.deps.org.objectweb.asm.commons.Method;
import com.newrelic.agent.instrumentation.methodmatchers.MethodMatcher;

public class RMIStubsMethodMatcher implements MethodMatcher {

private static final List<String> methodsToSkipped = new ArrayList<>();

static {
methodsToSkipped.add("getRef");
methodsToSkipped.add("equals");
methodsToSkipped.add("hashcode");
methodsToSkipped.add("toString");
methodsToSkipped.add("toStub");
methodsToSkipped.add("<init>");
}

@Override
public boolean matches(int access, String name, String desc, Set<String> annotations) {
boolean isPublic = 1 == access || -1 == access;
boolean b = isPublic && !methodsToSkipped.contains(name);
return b;
}

@Override
public Method[] getExactMethods() {
return null;
}

}
Loading

0 comments on commit 58e999e

Please sign in to comment.