Ratpack instrumentation support#276
Conversation
|
@jonmort Awesome work! I'll get back to you about that contributors agreement and the rest of your questions early next week. One blocker is this instrumentation is compiled against java 8. We have to support java 1.7, and attempting to load java 8 bytecode crashes the app. We'll put out a solution for this next week so we can unblock this PR and #254. |
tylerbenson
left a comment
There was a problem hiding this comment.
Nice job. Certainly more thorough in some aspects than what we normally do, and something for us to aspire to.
I added a lot of questions and comments, mainly for discussion. The main things that need to be resolved are:
- Resource Naming - This is rather datadog specific, so let us know if you need more explanation about this.
- Proper JVM Handling - You can add the test specific handling as mentioned in the comments, but we either need to change the way the project builds, or change the instrumentation back to JVM 7 compatible bytecode. Do you have any ideas for how we could handle this?
One other question to consider... in the future, if/when we add Netty support, how would we need to change this instrumentation?
There was a problem hiding this comment.
I don’t think it is safe for advice to reference this method. It should be moved to a utility class that is injected into the class loader.
There was a problem hiding this comment.
Oops, yes. Looks sketchy
There was a problem hiding this comment.
A lot of this is done automatically when setting the error object, so you don’t need to do it again here.
There was a problem hiding this comment.
How much of it? I copied this from the AWS implementation
There was a problem hiding this comment.
We usually name the project after the earliest version supported by the instrumentation. So this should be ratpack-1.4.6. Is this the earliest version the instrumentation can work with?
There was a problem hiding this comment.
Earliest tested with, I can try with 1.3 too
There was a problem hiding this comment.
Nice strategy for sharing the span between classes.
There was a problem hiding this comment.
This was inspired from the ratpack tracing for zipkin
There was a problem hiding this comment.
Since this isn’t the actual span, can you rename consistently to spanRef (like you did in other places) to avoid confusion?
There was a problem hiding this comment.
No, only 5XX status should be errors.
There was a problem hiding this comment.
Can you expand on why that is? 4xx responses are, by definition, also errors...
There was a problem hiding this comment.
@jdbevan 4xx errors are generally client side errors and thus not something you'd usually want to page someone for. In certain cases where it is something you consider more critical, you can add a TraceInterceptor to change it.
There was a problem hiding this comment.
This is not needed. The super class has a tracer you can reference directly that already uses ListWriter.
There was a problem hiding this comment.
Please add a test that uses path variables.
You should also set the resource name in the instrumentation and assert on it here.
Resource names should be based on the PathBinding which should be available on the context.
There was a problem hiding this comment.
I hadn't worked out how to do this when i first looked at it, now I see we can do this beforeSend and pull the path bindings then. I wasn't quite sure what the resource name was in ratpack, but the path binding description appears to be perfectly good
There was a problem hiding this comment.
If you feel it complicates the tests too much, you can remove this so okhttp doesn’t get instrumented.
There was a problem hiding this comment.
I'll take a look. Again I think I copied from servlet
There was a problem hiding this comment.
This is how we’ve been restricting the tests from running specific JVM versions for Ratpack.
https://github.com/DataDog/dd-trace-java/blob/master/dd-java-agent/instrumentation/okhttp-3/okhttp-3.gradle
This won’t help the need to compile the instrumentation with Java 8 though.
As Andrew said. Let us figure out a strategy for that.
|
Looks like this is something we could potentially do with custom Maybe instead, we could save the artifacts from the java 8 compile, then use them in the java 7 test run. Changing the JVM might invalidate the gradle |
There was a problem hiding this comment.
Earliest tested with, I can try with 1.3 too
There was a problem hiding this comment.
I need datadog.opentracing.scopemanager.ContextualScopeManager to be able to call addScopeContext
There was a problem hiding this comment.
I'll take a look. Again I think I copied from servlet
There was a problem hiding this comment.
Oops, yes. Looks sketchy
There was a problem hiding this comment.
How much of it? I copied this from the AWS implementation
There was a problem hiding this comment.
This was inspired from the ratpack tracing for zipkin
There was a problem hiding this comment.
Actually it won't. It will add to anything else already there so when calling execution.getAll it will return all RatpackScopes. I'll modify to clear it out first
There was a problem hiding this comment.
I hadn't worked out how to do this when i first looked at it, now I see we can do this beforeSend and pull the path bindings then. I wasn't quite sure what the resource name was in ratpack, but the path binding description appears to be perfectly good
|
I have addressed all the comments. I'm waiting on a solution for Java 7. I realised there was a Java 8 method reference in the instrumentation which i have replaced with a new class to ensure Java 7 byte code compatibility for the instrumentation class. The other classes have significant use of Java 8 language features. Regarding Netty, I think it might be possible to integrate this instrumentation, but mostly when using Ratpack you don't want Netty details as the abstractions Ratpack provides are more functional |
tylerbenson
left a comment
There was a problem hiding this comment.
Please see new comments below.
As for the Java 7 issue, we are looking into how to fix that. Thanks for your patience.
There was a problem hiding this comment.
Sorry I had you move this to a utility class... This whole method can be replaced with a simple call to:
span.log(Collections.singletonMap(ERROR_OBJECT, throwable));
We do all the rest inside the tracer.
There was a problem hiding this comment.
I think ratpack.request would be better.
There was a problem hiding this comment.
@jdbevan 4xx errors are generally client side errors and thus not something you'd usually want to page someone for. In certain cases where it is something you consider more critical, you can add a TraceInterceptor to change it.
There was a problem hiding this comment.
The reason is spans are added to the front of the list as they complete: https://github.com/DataDog/dd-trace-java/blob/master/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java#L87
This means the first span is usually the root span.
There was a problem hiding this comment.
Any idea in what cases this would happen?
There was a problem hiding this comment.
This will happen when there is no handler bound to the path (I think the response will be 404 or 405).
There was a problem hiding this comment.
Sorry I didn't mention this before, but the resource name should ideally be prefixed with the HTTP verb, so in this case, the resource name would be GET /:foo/:bar?/baz. Is that possible?
There was a problem hiding this comment.
Yes that makes sense. I'm also missing the leading slash. I'll put that in too
There was a problem hiding this comment.
These classes should mirror what is listed in the versionScan.verifyPresent block. This is how we ensure we don't try to instrument something in 1.3
There was a problem hiding this comment.
I'm ok restricting it to 1.4 as long as it doesn't try to inadvertently instrument any unsupported classes. We ensure this by including the below verifyPresent classes in the classLoaderHasClasses list in the instrumentation.
There was a problem hiding this comment.
So this is where it gets complex! The reason 1.3 isn't supported is because the interfaces have different methods, they are the same classes but method signatures changed. Specifically it is the RequestSpec that has the changes. I could rely on a class that is only in 1.4 to force this, but one that isn't instrumented
There was a problem hiding this comment.
Yeah, that is ok. The classes in that list aren't the ones we're explicitly instrumenting. They're intended as a "fingerprint" to identify the supported versions.
There was a problem hiding this comment.
I've sorted out the fingerprint now. It is pretty much just that method on that class that identifies 1.4 from 1.3
There was a problem hiding this comment.
Please re-order alphabetically.
There was a problem hiding this comment.
This method (getDescription) is only available on Ratpack 1.4+. I don't instrument PathBinding but do the getDescription method on it. I couln't see a way to express that in the agent builder. Any suggestions?
There was a problem hiding this comment.
The only classes in this list should be the ones that are unique to version 1.4+. In some cases, just class name isn't enough to uniquely identify. That's why we also have the optional method name in there.
There was a problem hiding this comment.
@tylerbenson I went out on a limb here and added a way to check for a class that has a particular method as I could not see a way to do it otherwise. I looked at using classLoaderHasClassWithField but it felt too fragile to use on a Ratpack internal class.
There was a problem hiding this comment.
@tylerbenson this is where I use the new ClassLoader Matcher, which gets reused for all the instrumentation
|
@jonmort Thanks for your patience while we work on unblocking you. We're still working on a solution for Java 8 instrumentation, but we'll let you know as soon as we can get this merged. |
|
I notice that |
|
Good point... @realark you may want to reconsider this^ |
|
Thanks @jonmort That's a good point. I'm adding that fix to my next play pr. |
c080a1a to
1d2f28b
Compare
1d2f28b to
fa90af7
Compare
|
@tylerbenson I've isolated the Java 8 code now and we have green builds. Is there anything further that needs doing here? |
tylerbenson
left a comment
There was a problem hiding this comment.
I think this looks great. You did a nice job and resolved all the comments I had. I'm ok merging this as-is. I left a few questions, but nothing blocking. Sorry for the delay in review. Let me know if you have anything else you want to do, otherwise I'll merge it.
| Here we introduce a sourceSet for the java 8 code which needs to be compiled with a source and target of 1.8 | ||
| The instrumentation classes must be compiled with java 7 and do nothing when ratpack is not on the classpath. The | ||
| java 8 classes are used lazily so there is no direct linking between the 1.7 and 1.8 bytecode. | ||
| */ |
There was a problem hiding this comment.
Thanks for the nice comment.
|
|
||
| @Override | ||
| public void execute(RequestSpec requestSpec) throws Exception { | ||
| requestAction.execute( |
There was a problem hiding this comment.
Do we need any logic to prevent double-wrapping here?
There was a problem hiding this comment.
The scenario in which requestSpec could have already been wrapped happens only if the client has some fancy logic to re-use requests, or chain the actions, this is quite unlikely but possible so the wise thing would be to guard against double wrapping
| /* | ||
| This test is somewhat convoluted and it raises some questions about how this is supposed to work | ||
| */ | ||
| setup: |
There was a problem hiding this comment.
Do you think there are potential problems that still need to be resolved?
There was a problem hiding this comment.
I should probably remove this comment. In a previous iteration there was some more setup code.
My concern about this test is the length of it. It has close to 100 lines of assertions but I think each assertion is necessary and I'd rather verbose tests than hiding them in a helper method
|
Ready to merge now? |
|
Yes ready to merge |
I've been working on this for quite a while and been round and round on it. This is finally ready for some feedback so please provide it.
There are several areas I'm not sure about
classLoaderHasClasses()calls are supposed to be usedHttpClient, what I have works but it would be much cleaner whenHttpClientinterceptors are availableAlso, is there a contributors agreement I need to sign?