-
Notifications
You must be signed in to change notification settings - Fork 327
Add support for JAX-RS-based transaction names #224
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
Conversation
Codecov Report
@@ Coverage Diff @@
## master #224 +/- ##
============================================
+ Coverage 74.58% 74.59% +0.01%
- Complexity 1190 1217 +27
============================================
Files 123 127 +4
Lines 4391 4488 +97
Branches 437 451 +14
============================================
+ Hits 3275 3348 +73
- Misses 917 935 +18
- Partials 199 205 +6
Continue to review full report at Codecov.
|
eyalkoren
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some issues I commented about that maybe are due to some misunderstanding.
Regardless, I assumed that the support for JAX-RS would actually be a combination of the path and the HTTP method. I think these are much more meaningful than class and method name. For sure that's the case to someone monitoring the application and not familiar with the code. I think the path is ALWAYS better than code, and I understand we are reluctant to rely on it due to path params, but the support for JAX-RS can rely on the @Path and @PathParams in order to avoid that, can't it?
| private static boolean canLoadClass(ClassLoader target, String className) { | ||
| boolean result; | ||
| try { | ||
| target.loadClass(className); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a very "intrusive" thing to do just to check something. It may cause premature class loading, which may or may not have side effects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What side effects are you thinking about? What could be an alternative to this approach?
I think a slightly better way would be trying to load the class via java.lang.Class#forName(java.lang.String, boolean, java.lang.ClassLoader) and setting the initialize flag to false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have direct control over which classes are affected. In this case, it is just the javax.ws.rs.Path class, which is also just an annotation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so at least you should add an ALL CAPITALS warning that this check should be used with caution and only for classes that have no dependencies (like a small interface or annotation)
|
|
||
| @Override | ||
| public ElementMatcher<? super TypeDescription> getTypeMatcher() { | ||
| return isInAnyPackage(applicationPackages, any()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you think it is likely that there are frameworks that use JAX-RS? I am not sure what we want to do if there are, but this means we will miss them, right?
...apm-jaxrs-plugin/src/main/java/co/elastic/apm/jaxrs/JaxRsTransactionNameInstrumentation.java
Show resolved
Hide resolved
apm-agent-core/src/main/java/co/elastic/apm/bci/bytebuddy/CustomElementMatchers.java
Outdated
Show resolved
Hide resolved
| @Override | ||
| public ElementMatcher<? super TypeDescription> getTypeMatcher() { | ||
| // setting application_packages makes this matcher more performant but is not required | ||
| return isInAnyPackage(applicationPackages, ElementMatchers.<TypeDescription>any()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you think it is likely that there are frameworks that use JAX-RS? I am not sure what we want to do if there are, but this means we will miss them, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Not sure if that is a likely case. The use case would be when importing a 3rd party library which also contains JAX-RS resources, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that what I meant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if this check provides any value and it is an expensive one. I think it better be removed, but in any case the order of the checks should probably be reversed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite the contrary. This isInAnyPackage matcher is a really cheap one because the class file does not have to be parsed at all. In general, the matchers which match based on the class names are the cheapest ones. Without this check, each and every class has to be parsed to see if it is annotated with @Path. Prepending the isInAnyPackage matcher considerably limits the amount classes which have to be checked with a more expensive matcher :). Also, typically, application_packages is only set to one or a handful of packages.
In the case you are importing a 3rd party library containing JAX-RS resources, it probably makes sense to add that to the application_packages namespace anyway. Because then stack traces also highlight those classes. But I can see that this may be confusing for users which wonder why some endpoints are not picked up. It's a tradeoff but I think with proper documentation (right at the supported technologies page), this would be the tradeoff I prefer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this check, each and every class has to be parsed to see if it is annotated with
@Path. Prepending theisInAnyPackagematcher considerably limits the amount classes which have to be checked with a more expensive matcher :)
Right, my mistake, I confused with the CL matcher that use caches...
| public ElementMatcher<? super TypeDescription> getTypeMatcher() { | ||
| // setting application_packages makes this matcher more performant but is not required | ||
| return isInAnyPackage(applicationPackages, ElementMatchers.<TypeDescription>any()) | ||
| .and(isAnnotatedWith(named("javax.ws.rs.Path"))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure the class must be annotated with javax.ws.rs.Path? Isn't it allowed to only annotate methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some answers on Stack Overflow suggested@Path is required on the class level.
But this quote from the JAX-RS 2.0 spec lets me doubt this:
A resource class is a Java class that uses JAX-RS annotations to implement a corresponding Web resource.
Resource classes are POJOs that have at least one method annotated with@Pathor a request method designator.
I'll investigate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you have a test app maybe just testing would be fastest
|
Some additional minor notes about the filtering. |
Well, I guess it depends on who is viewing the data and also how the controllers and methods are named. The verb and method don't always convey the semantics of an operation Example: Maybe we can discuss this in today's agent meeting and see what other agents are doing. Also for Spring MVC, we already use
Sure, we would not have problems with transaction name explosions when relying on the value of |
|
When I designed a RESTful server, I put a lot of thought in the paths structure, as they are really the API for the system, even though I am a developer. Of course I named classes and methods with proper names, but they had no real importance. Think about it this way - you can easily refactor your server changing the class and method names and then upgrade without affecting the system. That's because they are not part of the API. |
|
Another important quote from the spec (http://download.oracle.com/otn-pub/jcp/jaxrs-2_0-fr-eval-spec/jsr339-jaxrs-2.0-final-spec.pdf section 3.6 Annotation Inheritance):
So it seems that the
|
JAX-RS annotations may be used on the methods and method parameters of a super-class or an implemented interface.
|
Added annotation search on the method hierarchy to satisfy
I feel like we should probably have a type pool cache before merging... |
|
The performance of matching annotations of a specific type does not seem to be great :/ The good news is that if users specify their
I gathered these metrics by executing the |
|
We concluded we should log a warning if the user did not configure the |
|
Jenkins retest this please |
closes #67