Skip to content

Commit bdbf401

Browse files
Drop unsampled transactions when connected to APM Server 8.0+ (elastic#2329)
1 parent db97e7e commit bdbf401

File tree

4 files changed

+122
-1
lines changed

4 files changed

+122
-1
lines changed

CHANGELOG.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ endif::[]
2727
===== Features
2828
* Exceptions that are logged using the fatal log level are now captured (log4j2 only) - {pull}2377[#2377]
2929
* Replaced `authorization` in the default value of `sanitize_field_names` with `*auth*` - {pull}2326[#2326]
30+
* Unsampled transactions are dropped and not sent to the APM-Server if the APM-Server version is 8.0+ - {pull}2329[#2329]
3031
3132
[float]
3233
===== Bug fixes

apm-agent-core/src/main/java/co/elastic/apm/agent/impl/ElasticApmTracer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,8 @@ public void endTransaction(Transaction transaction) {
368368
new RuntimeException("this exception is just used to record where the transaction has been ended from"));
369369
}
370370
}
371-
if (!transaction.isNoop()) {
371+
if (!transaction.isNoop() &&
372+
(transaction.isSampled() || apmServerClient.supportsKeepingUnsampledTransaction())) {
372373
// we do report non-sampled transactions (without the context)
373374
reporter.report(transaction);
374375
} else {

apm-agent-core/src/main/java/co/elastic/apm/agent/report/ApmServerClient.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class ApmServerClient {
7171
private static final Version VERSION_7_0 = Version.of("7.0.0");
7272
private static final Version VERSION_7_4 = Version.of("7.4.0");
7373
private static final Version VERSION_7_9 = Version.of("7.9.0");
74+
private static final Version VERSION_8_0 = Version.of("8.0.0");
7475

7576
private final ReporterConfiguration reporterConfiguration;
7677
@Nullable
@@ -338,6 +339,15 @@ public boolean supportsLogsEndpoint() {
338339
return isAtLeast(VERSION_7_9);
339340
}
340341

342+
public boolean supportsKeepingUnsampledTransaction() {
343+
// supportsKeepingUnsampledTransaction is called from application threads
344+
// return true instead of blocking the thread
345+
if (apmServerVersion != null && !apmServerVersion.isDone()) {
346+
return true;
347+
}
348+
return isLowerThan(VERSION_8_0);
349+
}
350+
341351
@Nullable
342352
Version getApmServerVersion(long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
343353
if (apmServerVersion != null) {
@@ -346,6 +356,10 @@ Version getApmServerVersion(long timeout, TimeUnit timeUnit) throws InterruptedE
346356
return null;
347357
}
348358

359+
public boolean isLowerThan(Version apmServerVersion) {
360+
return !isAtLeast(apmServerVersion);
361+
}
362+
349363
public boolean isAtLeast(Version apmServerVersion) {
350364
if (this.apmServerVersion == null) {
351365
throw new IllegalStateException("Called before init event");
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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.impl;
20+
21+
import co.elastic.apm.agent.AbstractInstrumentationTest;
22+
import co.elastic.apm.agent.MockReporter;
23+
import co.elastic.apm.agent.configuration.CoreConfiguration;
24+
import co.elastic.apm.agent.configuration.SpyConfiguration;
25+
import co.elastic.apm.agent.impl.metadata.MetaData;
26+
import co.elastic.apm.agent.objectpool.TestObjectPoolFactory;
27+
import co.elastic.apm.agent.report.ApmServerClient;
28+
import org.junit.jupiter.api.AfterAll;
29+
import org.junit.jupiter.api.AfterEach;
30+
import org.junit.jupiter.api.BeforeAll;
31+
import org.junit.jupiter.api.Test;
32+
import org.stagemonitor.configuration.ConfigurationRegistry;
33+
34+
35+
import java.io.IOException;
36+
37+
import static org.assertj.core.api.Assertions.assertThat;
38+
import static org.mockito.Mockito.mock;
39+
import static org.mockito.Mockito.when;
40+
41+
class DropUnsampledTransactionsTest extends AbstractInstrumentationTest {
42+
43+
private static ApmServerClient apmServerClient = mock(ApmServerClient.class);
44+
45+
private static MockReporter reporter = new MockReporter();
46+
47+
private static ElasticApmTracer tracer;
48+
49+
@BeforeAll
50+
static void startTracer() {
51+
ConfigurationRegistry configurationRegistry = SpyConfiguration.createSpyConfig();
52+
tracer = new ElasticApmTracer(configurationRegistry, reporter, new TestObjectPoolFactory(), apmServerClient, "ephemeralId", MetaData.create(configurationRegistry, "ephemeralId"));
53+
tracer.start(false);
54+
}
55+
56+
@AfterAll
57+
static void stopTracer() {
58+
tracer.stop();
59+
}
60+
61+
@AfterEach
62+
void resetReporter() {
63+
reporter.reset();
64+
}
65+
66+
@Test
67+
void whenTheAPMServerSupportsKeepingUnsampledTransactionsUnsampledTransactionsShouldBeReported() throws IOException {
68+
when(apmServerClient.supportsKeepingUnsampledTransaction()).thenReturn(true);
69+
tracer.getConfig(CoreConfiguration.class).getSampleRate().update(0.0, SpyConfiguration.CONFIG_SOURCE_NAME);
70+
71+
tracer.startRootTransaction(null).end();
72+
73+
assertThat(reporter.getTransactions().size()).isEqualTo(1);
74+
}
75+
76+
@Test
77+
void whenTheAPMServerSupportsKeepingUnsampledTransactionsSampledTransactionsShouldBeReported() throws IOException {
78+
when(apmServerClient.supportsKeepingUnsampledTransaction()).thenReturn(true);
79+
tracer.getConfig(CoreConfiguration.class).getSampleRate().update(1.0, SpyConfiguration.CONFIG_SOURCE_NAME);
80+
81+
tracer.startRootTransaction(null).end();
82+
83+
assertThat(reporter.getTransactions().size()).isEqualTo(1);
84+
}
85+
86+
@Test
87+
void whenTheAPMServerDoesNotSupportsKeepingUnsampledTransactionsUnsampledTransactionsShouldNotBeReported() throws IOException {
88+
when(apmServerClient.supportsKeepingUnsampledTransaction()).thenReturn(false);
89+
tracer.getConfig(CoreConfiguration.class).getSampleRate().update(0.0, SpyConfiguration.CONFIG_SOURCE_NAME);
90+
91+
tracer.startRootTransaction(null).end();
92+
93+
assertThat(reporter.getTransactions().size()).isEqualTo(0);
94+
}
95+
96+
@Test
97+
void whenTheAPMServerDoesNotSupportsKeepingUnsampledTransactionsSampledTransactionsShouldBeReported() throws IOException {
98+
when(apmServerClient.supportsKeepingUnsampledTransaction()).thenReturn(false);
99+
tracer.getConfig(CoreConfiguration.class).getSampleRate().update(1.0, SpyConfiguration.CONFIG_SOURCE_NAME);
100+
101+
tracer.startRootTransaction(null).end();
102+
103+
assertThat(reporter.getTransactions().size()).isEqualTo(1);
104+
}
105+
}

0 commit comments

Comments
 (0)