Conversation
|
Play 2.4 is the first version to require Java 8. Before that required Java 6: https://www.playframework.com/documentation/2.6.x/Highlights24#Java-8-support Play 2.5 was the one that discontinued Scala 2.10: https://www.playframework.com/documentation/2.5.x/Migration25#Scala-2.10-support-discontinued Though the biggest change between 2.5 and 2.6 is the change from using Netty to Akka HTTP: If we want to support 2.5, we'd certainly want independent tests for both 2.5 and 2.6. Though if we want 2.4, we'd need to specify the supported Scala version too. |
tylerbenson
left a comment
There was a problem hiding this comment.
Looks good. I don't think that we can merge this until we solve the Java 7 compile issue. What do you think?
|
|
||
| @Override | ||
| protected boolean defaultEnabled() { | ||
| return false; |
There was a problem hiding this comment.
Do we want to somehow chain this to if the scala/akka instrumentation is enabled? Might be funny if this is enabled, but the others aren't.
There was a problem hiding this comment.
I think it's okay to leave the options separate. The play instrumentation will still apply and trace controller actions without the concurrent instrumentation, but it won't capture async work created by the controllers.
| @Advice.Thrown final Throwable throwable, | ||
| @Advice.Argument(0) final Request req, | ||
| @Advice.Return(readOnly = false) Future<Result> responseFuture) { | ||
| // more about routes here: https://github.com/playframework/playframework/blob/master/documentation/manual/releases/release26/migration26/Migration26.md |
There was a problem hiding this comment.
This won't work if we want to support lower versions.
| @Advice.Return(readOnly = false) Future<Result> responseFuture) { | ||
| // more about routes here: https://github.com/playframework/playframework/blob/master/documentation/manual/releases/release26/migration26/Migration26.md | ||
| final Option handlerOption = req.attrs().get(Router.Attrs.HANDLER_DEF.underlying()); | ||
| if (!handlerOption.isEmpty()) { |
There was a problem hiding this comment.
This also has the Java 7 incompatibility problem...
| } | ||
| scope.span().setTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER); | ||
| scope.span().setTag(Tags.HTTP_METHOD.getKey(), req.method()); | ||
| scope.span().setTag(DDTags.SPAN_TYPE, DDSpanTypes.WEB_SERVLET); |
There was a problem hiding this comment.
Awkward.... guess that could have been named better ;-)
| final Map<String, Object> errorLogs = new HashMap<>(4); | ||
| errorLogs.put("event", Tags.ERROR.getKey()); | ||
| errorLogs.put("error.kind", throwable.getClass().getName()); | ||
| errorLogs.put("error.object", throwable); |
There was a problem hiding this comment.
This is the only element required to be logged... the rest are already implicitly done in DDSpan.setErrorMeta().
I usually just call:
span.log(Collections.singletonMap("error.object", throwable));
| try { | ||
| Tags.HTTP_STATUS.set(span, result.header().status()); | ||
| } catch (Throwable t) { | ||
| LoggerFactory.getLogger(RequestCallback.class).debug("error in play instrumentation", t); |
There was a problem hiding this comment.
Since this isn't advice, I think you could also add the @Slf4j annotation to the class.
| TestServer testServer | ||
|
|
||
| def setupSpec() { | ||
| testServer = Helpers.testServer(9080, PlayTestUtils.buildTestApp()) |
There was a problem hiding this comment.
You can do something like this to get a random open port each time you run the test.
There was a problem hiding this comment.
👍Cool. I added randomOpenPort to TestUtils.
| object PlayTestUtils { | ||
| def buildTestApp(): play.Application = { | ||
| // build play.api.Application with desired setting and pass into play.Application for testing | ||
| val apiApp :play.api.Application = new play.api.inject.guice.GuiceApplicationBuilder() |
|
Addressed some of the feedback. To work with Java 7, I'll try compiling against an earlier version of play, and move 2.6 into a separate test-only subproject. |
Simplify error collecting. Use slf4j to log. randomOpenPort util.
41e1553 to
589aed4
Compare
|
@tylerbenson Pushed up a few changes for play 2.4 compatibility.
Testing is not compatible with Java 7 because the play test dependencies require java 8. However, the instrumentation is compiled to Java 7, so it is safe to ship this instrumentation on a java 7 jvm. It won't apply, but it won't cause any issues. Additionally, there are still two |
| @@ -0,0 +1,26 @@ | |||
| apply from: "${rootDir}/gradle/java.gradle" | |||
| apply from: "${rootDir}/gradle/test-with-scala.gradle" | |||
There was a problem hiding this comment.
Do you want a version scan block here?
There was a problem hiding this comment.
I'm running into some problems setting that up.
I'm trying to use this configuration:
versionScan {
group = "com.typesafe.play"
module = "play_2.11"
versions = "[2.4.0,)"
verifyPresent = [
'akka.japi.JavaPartialFunction' : null,
'play.api.mvc.Action' : null,
'play.api.mvc.Result' : null,
'play.api.mvc.Request' : null,
'scala.Option' : null,
'scala.Tuple2' : null,
'scala.concurrent.Future' : null
]
}
I'm getting an error that I don't understand.
keyPresent: 1841->88
keyMissing: 1687->85
:dd-java-agent:instrumentation:play-2.4:verifyVersionScanError for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: akka.japi.JavaPartialFunction
Error for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: play.api.mvc.Action
Error for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: play.api.mvc.Result
Error for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: play.api.mvc.Request
Error for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: scala.Option
Error for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: scala.Tuple2
Error for com.typesafe.play:play_2.11 - not a 'keyPresent' identifier: scala.concurrent.Future
Also, it seems like the versionScan plugin only expects one module at a time to test. Because play bundles many different modules it's useful to check for transitive deps (scala, akka). Is there a way to check for those?
There was a problem hiding this comment.
I believe the transitive dependencies are included in the scan.
The error for something not being a key identifier means it can't be used to uniquely fingerprint that version range.
This isn't intended to be a list of classes we use in our instrumentation. This is strictly for trying to figure out what version of a library is currently being loaded.
|
|
||
| test { | ||
| if (JavaVersion.current().isJava8Compatible()) { | ||
| exclude '*Play*Test*' |
There was a problem hiding this comment.
so you're excluding the test for Java 8+?
| @@ -0,0 +1,27 @@ | |||
| apply from: "${rootDir}/gradle/java.gradle" | |||
| apply from: "${rootDir}/gradle/test-with-scala.gradle" | |||
There was a problem hiding this comment.
Instead of specifying a separate project, you might be able to just use a separate configuration. Try using this plugin: https://github.com/unbroken-dome/gradle-testsets-plugin. You can see an example of it being used in dd-trace-ot to specify integration tests. The main downside is the tests wouldn't run automatically with gradle test unless you do something else.
There was a problem hiding this comment.
Neat. I'll check it out.
| if (JavaVersion.current().isJava8Compatible()) { | ||
| // java 8 only instrumentation | ||
| include ':dd-java-agent:instrumentation:play-2.4' | ||
| include ':dd-java-agent:instrumentation:play-2.4:play-2.6-testing' |
There was a problem hiding this comment.
I don't like the idea of putting core agent stuff in here...
There was a problem hiding this comment.
I want to skip these modules when built by a 1.7 VM because the play dependencies are 1.8 and won't pass the compilation task. Is there a better approach to that?
| "scala.Option", | ||
| "scala.Tuple2", | ||
| "scala.concurrent.Future") | ||
| .and(classLoaderHasClassWithMethod("play.api.mvc.Request", "tags"))) |
There was a problem hiding this comment.
All these classes/methods are used by the instrumentation. The tags method in particular is likely to go away in future play versions, so I want to be sure it's there before I apply the instrumentation.
| @Advice.Argument(0) final Request req, | ||
| @Advice.Return(readOnly = false) Future<Result> responseFuture) { | ||
| // more about routes here: https://github.com/playframework/playframework/blob/master/documentation/manual/releases/release26/migration26/Migration26.md | ||
| final Option pathOption = req.tags().get("ROUTE_PATTERN"); |
There was a problem hiding this comment.
Does this work across 2.4 - 2.6? I thought they had a different API in 2.6.
There was a problem hiding this comment.
2.6 has a new api, but they still support the old tags api. Likely this will go away in 2.7.
This reverts commit 2a42f7d.
|
@tylerbenson I can't get the testset plugin to work with Java9. I've reverted those changes for now. Any ideas? |
|
That's odd... I'm not sure what might be the problem in CI. I'm fine leaving it as is. Just thought that would be a nice way to clean things up. |
tylerbenson
left a comment
There was a problem hiding this comment.
This isn't really following the original intent for classLoaderHasClasses and the versionScan plugin, but it'll do.
First phase of play instrumentation tested against play 2.4 - 2.6.
Remaining work
I can either continue pushing work to this branch, or if you want to review and merge into master (behind a feature flag) that works for me too. Whatever is easier.