Skip to content

Commit 5a6f389

Browse files
authored
added support to jakartaee for scheduled annotation plugin (elastic#2250)
* added support to jakartaee for scheduled annotation plugin * added entry to changelog. updated supported technologies * added license headers * updated supported techonologies for jax-ws
1 parent c075409 commit 5a6f389

File tree

11 files changed

+352
-131
lines changed

11 files changed

+352
-131
lines changed

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ by the agent may be different. This was done in order to improve the integration
5050
The difference is that the new option has more intuitive semantics for negative values (never collect stack trace) and zero (always collect stack trace). - {pull}2220[#2220]
5151
* Add support to Jakarta EE for JAX-WS - {pull}2247[#2247]
5252
* Add support to Jakarta EE for JAX-RS - {pull}2248[#2248]
53+
* Add support for Jakarta EE EJB annotations `@Schedule`, `@Schedules` - {pull}2250[#2250]
5354
5455
[float]
5556
===== Performance improvements
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>apm-agent-plugins</artifactId>
7+
<groupId>co.elastic.apm</groupId>
8+
<version>1.26.1-SNAPSHOT</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>apm-scheduled-annotation-plugin-jakartaee-test</artifactId>
13+
<name>${project.groupId}:${project.artifactId}</name>
14+
15+
<properties>
16+
<apm-agent-parent.base.dir>${project.basedir}/../..</apm-agent-parent.base.dir>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>jakarta.platform</groupId>
22+
<artifactId>jakarta.jakartaee-api</artifactId>
23+
<version>9.0.0</version>
24+
<scope>test</scope>
25+
</dependency>
26+
<dependency>
27+
<groupId>${project.groupId}</groupId>
28+
<artifactId>apm-scheduled-annotation-plugin</artifactId>
29+
<version>${project.version}</version>
30+
<scope>test</scope>
31+
</dependency>
32+
<dependency>
33+
<groupId>${project.groupId}</groupId>
34+
<artifactId>apm-scheduled-annotation-plugin</artifactId>
35+
<version>${project.version}</version>
36+
<type>test-jar</type>
37+
<scope>test</scope>
38+
</dependency>
39+
</dependencies>
40+
41+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package co.elastic.apm.agent.scheduled;
20+
21+
import jakarta.ejb.Schedule;
22+
23+
24+
public class JakartaeeScheduledTransactionNameInstrumentationTest extends AbstractScheduledTransactionNameInstrumentationTest {
25+
@Override
26+
JeeCounter createJeeCounterImpl() {
27+
return new JeeCounterImpl();
28+
}
29+
30+
@Override
31+
ThrowingCounter createThrowingCounterImpl() {
32+
return new ThrowingCounterImpl();
33+
}
34+
35+
protected static class JeeCounterImpl extends JeeCounter {
36+
37+
@Schedule(minute = "5")
38+
public void scheduled() {
39+
this.count.incrementAndGet();
40+
}
41+
42+
@jakarta.ejb.Schedules({
43+
@Schedule(minute = "5"),
44+
@Schedule(minute = "10")
45+
})
46+
public void scheduledJava7Repeatable() {
47+
this.count.incrementAndGet();
48+
}
49+
}
50+
51+
protected static class ThrowingCounterImpl extends ThrowingCounter {
52+
53+
@Schedule(minute = "5") // whatever the used annotation here, the behavior should be the same
54+
public void throwingException() {
55+
count.incrementAndGet();
56+
throw new RuntimeException("intentional exception");
57+
}
58+
}
59+
}

apm-agent-plugins/apm-scheduled-annotation-plugin/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,19 @@
3030
</dependency>
3131
</dependencies>
3232

33+
<build>
34+
<plugins>
35+
<plugin>
36+
<artifactId>maven-jar-plugin</artifactId>
37+
<executions>
38+
<execution>
39+
<goals>
40+
<goal>test-jar</goal>
41+
</goals>
42+
</execution>
43+
</executions>
44+
</plugin>
45+
</plugins>
46+
</build>
47+
3348
</project>

apm-agent-plugins/apm-scheduled-annotation-plugin/src/main/java/co/elastic/apm/agent/scheduled/ScheduledTransactionNameInstrumentation.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import static co.elastic.apm.agent.bci.bytebuddy.CustomElementMatchers.isInAnyPackage;
4242
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
4343
import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith;
44-
import static net.bytebuddy.matcher.ElementMatchers.named;
44+
import static net.bytebuddy.matcher.ElementMatchers.namedOneOf;
4545

4646
public class ScheduledTransactionNameInstrumentation extends TracerAwareInstrumentation {
4747

@@ -57,7 +57,7 @@ public static class ScheduledTransactionNameAdvice {
5757
@Nullable
5858
@Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
5959
public static Object setTransactionName(@SimpleMethodSignature String signature,
60-
@Advice.Origin Class<?> clazz) {
60+
@Advice.Origin Class<?> clazz) {
6161
AbstractSpan<?> active = tracer.getActive();
6262
if (active == null) {
6363
Transaction transaction = tracer.startRootTransaction(clazz.getClassLoader());
@@ -95,11 +95,8 @@ public ElementMatcher<? super TypeDescription> getTypeMatcher() {
9595
@Override
9696
public ElementMatcher<? super MethodDescription> getMethodMatcher() {
9797
return isAnnotatedWith(
98-
named("org.springframework.scheduling.annotation.Scheduled")
99-
.or(named("org.springframework.scheduling.annotation.Schedules"))
100-
.or(named("javax.ejb.Schedule"))
101-
.or(named("javax.ejb.Schedules"))
102-
);
98+
namedOneOf("org.springframework.scheduling.annotation.Scheduled", "org.springframework.scheduling.annotation.Schedules",
99+
"javax.ejb.Schedule", "javax.ejb.Schedules", "jakarta.ejb.Schedule", "jakarta.ejb.Schedules"));
103100
}
104101

105102
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package co.elastic.apm.agent.scheduled;
20+
21+
import co.elastic.apm.agent.AbstractInstrumentationTest;
22+
import co.elastic.apm.agent.impl.transaction.AbstractSpan;
23+
import co.elastic.apm.agent.impl.transaction.Outcome;
24+
import co.elastic.apm.agent.impl.transaction.Transaction;
25+
26+
import java.util.List;
27+
import java.util.concurrent.atomic.AtomicInteger;
28+
import java.util.stream.Collectors;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
public abstract class AbstractScheduledInstrumentationTest extends AbstractInstrumentationTest {
33+
34+
protected static List<Transaction> checkTransactions(AbstractCounter counter, int expectedCount, String expectedName) {
35+
List<Transaction> transactions = reporter.getTransactions();
36+
assertThat(transactions).hasSize(counter.getInvocationCount()).hasSize(expectedCount);
37+
transactions.forEach(t -> {
38+
assertThat(t.getNameAsString()).isEqualTo(expectedName);
39+
});
40+
return transactions;
41+
}
42+
43+
protected static void checkOutcome(List<Transaction> transactions, Outcome outcome) {
44+
assertThat(transactions.stream()
45+
.map(AbstractSpan::getOutcome)
46+
.collect(Collectors.toSet()))
47+
.containsExactly(outcome);
48+
}
49+
50+
protected static abstract class AbstractCounter {
51+
protected final AtomicInteger count = new AtomicInteger(0);
52+
53+
public final int getInvocationCount() {
54+
return this.count.get();
55+
}
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Licensed to Elasticsearch B.V. under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch B.V. licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package co.elastic.apm.agent.scheduled;
20+
21+
import co.elastic.apm.agent.impl.transaction.Outcome;
22+
import co.elastic.apm.agent.impl.transaction.Transaction;
23+
import org.junit.jupiter.api.Test;
24+
25+
import java.util.List;
26+
27+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
28+
29+
30+
abstract class AbstractScheduledTransactionNameInstrumentationTest extends AbstractScheduledInstrumentationTest {
31+
32+
@Test
33+
void testJeeScheduledAnnotatedMethodsAreTraced() {
34+
JeeCounter jeeCounter = createJeeCounterImpl();
35+
jeeCounter.scheduled();
36+
jeeCounter.scheduled();
37+
jeeCounter.scheduled();
38+
List<Transaction> transactions = checkTransactions(jeeCounter, 3, "JeeCounterImpl#scheduled");
39+
checkOutcome(transactions, Outcome.SUCCESS);
40+
}
41+
42+
@Test
43+
void testJeeJ7RepeatableScheduledAnnotatedMethodsAreTraced() {
44+
JeeCounter jeeCounter = createJeeCounterImpl();
45+
jeeCounter.scheduledJava7Repeatable();
46+
jeeCounter.scheduledJava7Repeatable();
47+
List<Transaction> transactions = checkTransactions(jeeCounter, 2, "JeeCounterImpl#scheduledJava7Repeatable");
48+
checkOutcome(transactions, Outcome.SUCCESS);
49+
}
50+
51+
@Test
52+
void testThrownErrorOutcomes() {
53+
ThrowingCounter throwCounter = createThrowingCounterImpl();
54+
55+
assertThatThrownBy(throwCounter::throwingException);
56+
57+
List<Transaction> transactions = checkTransactions(throwCounter, 1, "ThrowingCounterImpl#throwingException");
58+
checkOutcome(transactions, Outcome.FAILURE);
59+
}
60+
61+
abstract JeeCounter createJeeCounterImpl();
62+
63+
abstract ThrowingCounter createThrowingCounterImpl();
64+
65+
protected static abstract class JeeCounter extends AbstractCounter {
66+
67+
public abstract void scheduled();
68+
69+
public abstract void scheduledJava7Repeatable();
70+
}
71+
72+
protected static abstract class ThrowingCounter extends AbstractCounter {
73+
74+
public abstract void throwingException();
75+
}
76+
77+
}

0 commit comments

Comments
 (0)