Skip to content
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

Add Scala concurrent plugin #1048

Merged
merged 43 commits into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
404f6fb
WIP
Feb 16, 2020
9ce7f3f
Add initial scala instrumentation for Future
milanvdm Feb 22, 2020
e0a4335
Remove test-dependency
milanvdm Feb 24, 2020
e57e2d8
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm Mar 29, 2020
3ef57c0
Add first test approach
milanvdm Mar 29, 2020
2dd336d
Use Java for method matching
milanvdm Apr 9, 2020
167ecde
Add dummy test using Scala
milanvdm Apr 14, 2020
90d0b6f
Add java-version
milanvdm Apr 14, 2020
1b5b369
Add first matching instrumentation test
milanvdm Apr 14, 2020
f20a929
WIP
milanvdm Apr 18, 2020
b2d2bb7
Use MUnit
milanvdm Apr 20, 2020
2feb98f
Cleanup pom
milanvdm Apr 22, 2020
0af62ce
Add Future instrumentation
milanvdm Apr 22, 2020
f97b0b1
Add tests
milanvdm Apr 22, 2020
649207b
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm Apr 23, 2020
324ce67
Add plugin to release process
milanvdm Apr 23, 2020
9d0eb39
Instrument ExecutionContext
milanvdm Apr 24, 2020
7ab2834
Merge branch 'master' into add-scala-executor-apm
milanvdm May 8, 2020
ee6da7d
Add onStream instrumentation on AsyncHandler
milanvdm May 8, 2020
ec2b7eb
Add StreamHandler tests
milanvdm May 8, 2020
d9e0762
Merge branch 'keep-spans-active-on-stream-async-http' into add-scala-…
milanvdm May 8, 2020
84417b0
Add Promise instrumentation
milanvdm May 13, 2020
199e514
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm May 13, 2020
ad42993
Cleanup
milanvdm May 15, 2020
49bca5f
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm May 15, 2020
e41f63c
Fix versions
milanvdm May 15, 2020
a0375b7
Make sure spans are not recycled
milanvdm May 16, 2020
accd469
Cleanup Java 9 compilers
milanvdm May 19, 2020
7843966
Add docs
milanvdm May 19, 2020
0f7b257
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm May 19, 2020
f9b8e56
Fix merge
milanvdm May 19, 2020
063ed39
Remove Java version
milanvdm May 27, 2020
6c638d9
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm May 27, 2020
40033fa
Improve testing for edge cases
milanvdm May 29, 2020
5ee2b3b
Simplify failing test
milanvdm May 29, 2020
1721794
Add extra failing test on Future.sequence
milanvdm May 29, 2020
737bb0e
Merge branch 'master' into add-scala-executor-apm
felixbarny Jun 15, 2020
1885c8e
Add java apm dependency to test
milanvdm Jun 15, 2020
c893ac0
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm Jun 17, 2020
f844049
Bump to new snapshot version
milanvdm Jun 17, 2020
0f530a0
Start tracer
milanvdm Jun 23, 2020
c6a6581
Merge remote-tracking branch 'upstream/master' into add-scala-executo…
milanvdm Jun 23, 2020
b68d3d2
Merge branch 'master' into add-scala-executor-apm
felixbarny Jun 25, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ The latter uses https://github.com/elastic/ecs-logging-java[ecs-logging-java] to
* Exposing <<config-classes-excluded-from-instrumentation>> config - {pull}1187[#1187]
* Add support for naming transactions based on Grails controllers. Supports Grails 3+ - {pull}1171[#1171]
* Add support for the Apache/Alibaba Dubbo RPC framework
* Add experimental support for Scala Futures

[float]
===== Bug fixes
Expand Down
56 changes: 56 additions & 0 deletions apm-agent-plugins/apm-scala-concurrent-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<artifactId>apm-agent-plugins</artifactId>
<groupId>co.elastic.apm</groupId>
<version>1.16.1-SNAPSHOT</version>
</parent>

<artifactId>apm-scala-concurrent-plugin</artifactId>
<name>${project.groupId}:${project.artifactId}</name>

<properties>
<apm-agent-parent.base.dir>${project.basedir}/../..</apm-agent-parent.base.dir>
</properties>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>apm-java-concurrent-plugin</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.scalameta</groupId>
<artifactId>munit_2.13</artifactId>
<version>0.7.2</version>
<scope>test</scope>
</dependency>
felixbarny marked this conversation as resolved.
Show resolved Hide resolved
</dependencies>

<build>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.3.1</version>
<configuration>
<scalaVersion>2.13.2</scalaVersion>
</configuration>
<executions>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

milanvdm marked this conversation as resolved.
Show resolved Hide resolved
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*-
* #%L
* Elastic APM Java agent
* %%
* Copyright (C) 2018 - 2020 Elastic and contributors
* %%
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* #L%
*/
package co.elastic.apm.agent.scala.concurrent;

import co.elastic.apm.agent.bci.ElasticApmInstrumentation;
import co.elastic.apm.agent.bci.VisibleForAdvice;
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
import com.blogspot.mydailyjava.weaklockfree.WeakConcurrentMap;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Collection;

import static net.bytebuddy.matcher.ElementMatchers.*;

public abstract class FutureInstrumentation extends ElasticApmInstrumentation {

@VisibleForAdvice
@SuppressWarnings("WeakerAccess")
public static final WeakConcurrentMap<Object, AbstractSpan<?>> promisesToContext =
new WeakConcurrentMap.WithInlinedExpunction<>();

@Nonnull
@Override
public Collection<String> getInstrumentationGroupNames() {
return Arrays.asList("scala-future", "experimental");
}

public static class ConstructorInstrumentation extends FutureInstrumentation {

@Override
public ElementMatcher<? super TypeDescription> getTypeMatcher() {
return named("scala.concurrent.impl.Promise$Transformation");
}

@Override
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
return isConstructor();
felixbarny marked this conversation as resolved.
Show resolved Hide resolved
}

@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Advice.This Object thiz) {
final AbstractSpan<?> context = getActive();
if (context != null) {
promisesToContext.put(thiz, context);
milanvdm marked this conversation as resolved.
Show resolved Hide resolved
// this span might be ended before the Promise$Transformation#run method starts
// we have to avoid that this span gets recycled, even in the above mentioned case
context.incrementReferences();
}
}

}

public static class RunInstrumentation extends FutureInstrumentation {

@Override
public ElementMatcher<? super TypeDescription> getTypeMatcher() {
return named("scala.concurrent.impl.Promise$Transformation");
}

@Override
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
return named("run").and(returns(void.class));
}

@VisibleForAdvice
@Advice.OnMethodEnter(suppress = Throwable.class)
public static void onEnter(@Advice.This Object thiz, @Nullable @Advice.Local("context") AbstractSpan<?> context) {
context = promisesToContext.remove(thiz);
if (tracer != null && context != null) {
tracer.activate(context);
milanvdm marked this conversation as resolved.
Show resolved Hide resolved
// decrements the reference we incremented to avoid that the parent context gets recycled before the promise is run
// because we have activated it, we can be sure it doesn't get recycled until we deactivate in the OnMethodExit advice
context.decrementReferences();
}
}

@Advice.OnMethodExit(suppress = Throwable.class)
public static void onExit(@Nullable @Advice.Local("context") AbstractSpan<?> context) {
if (tracer != null && context != null) {
tracer.deactivate(context);
}
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
co.elastic.apm.agent.scala.concurrent.FutureInstrumentation$ConstructorInstrumentation
co.elastic.apm.agent.scala.concurrent.FutureInstrumentation$RunInstrumentation
Loading