Skip to content

Conversation

@felixbarny
Copy link
Member

@felixbarny felixbarny commented Mar 22, 2021

What does this PR do?

Checklist

  • I have updated CHANGELOG.asciidoc
  • My code follows the style guidelines of this project
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated supported-technologies.asciidoc
  • [ ] Added an API method or config option? Document in which version this will be introduced
  • Added an instrumentation plugin? Describe how you made sure that old, non-supported versions are not instrumented by accident.
    The type matcher excludes 1.x drivers
@ghost
Copy link

ghost commented Mar 22, 2021

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview

Expand to view the summary

Build stats

  • Build Cause: Started by user eyalkoren

  • Start Time: 2021-04-01T08:43:38.383+0000

  • Duration: 55 min 30 sec

  • Commit: 82426f3

Test stats 🧪

Test Results
Failed 0
Passed 1982
Skipped 19
Total 2001

Trends 🧪

Image of Build Times

Image of Tests

💚 Flaky test report

Tests succeeded.

Expand to view the summary

Test stats 🧪

Test Results
Failed 0
Passed 1982
Skipped 19
Total 2001

@AlexanderWert AlexanderWert added this to the 7.13 milestone Mar 29, 2021
Copy link
Contributor

@eyalkoren eyalkoren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome capability addition! ❤️

}
}

public void withInetAddress(InetAddress inetAddress) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not using getHostAddress() to prevent allocations? This implementation is IPv4-specific. But even better would be getHostName(), wouldn't it?
I see the value of being efficient here, as it will be called for each span, but I think the better option is to cache addresses per com.datastax.driver.core.Host instead in the Cassandra instrumentations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, I didn't consider IPv6.
getHostName will make a DNS lookup, I'm not sure we'd want to do this as it could introduce quite some overhead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getHostName will make a DNS lookup, I'm not sure we'd want to do this as it could introduce quite some overhead

That's right, but it is preferable than IP, so I suggested to cache the result based on the Host

Copy link
Contributor

@eyalkoren eyalkoren Mar 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably do the same in the RabbitMQ instrumentation -

(caching the address per com.rabbitmq.client.Connection).
Whether you implement this caching or not, please switch the RabbitMQ instrumentation to use your new co.elastic.apm.agent.impl.context.Destination#withInetAddress utility.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unified address handling, not only in RabbitMQ

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's the only other one relying on InetAddress

}
final Span span = (Span) spanObj;
span.captureException(thrown).deactivate();
Futures.addCallback(result, new FutureCallback<ResultSet>() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!
It relies on a non-explicit dependency that is marked with @com.google.common.annotations.Beta annotation, but not sure this means actual instability. Also, in addition to this FutureCallback allocation, there is an additional Runnable object allocation internally.
In Apache HTTP we wrap futures and pool these wrappers to maintain zero allocation.

Since this is so slick and simple, it may worth both "risks". I just wanted to point out and let you decide.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested with a bunch of versions and this was quite stable. However, there's no stable API to get the direct executor, so we'd have to implement that in the Cassandra module if we wanted to directly implement the Runnable. I tried to keep the complexity of this module low.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this simplicity is very appealing. I agree that implementing it is a worse option.
My suggested alternative was wrapping the Future with pooled futures. If it is simple enough, we can do that (and save two allocations per query), otherwise this is good enough.

private static void setDestination(Span span, ExecutionInfo info) {
Node coordinator = info.getCoordinator();
if (coordinator != null) {
span.getContext().getDestination().withSocketAddress(coordinator.getEndPoint().resolve());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above - if makes sense, we can cache destination based on Node or EndPoint.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we cache, we should probably do it based on the socket address in Destination so that it's not Cassandra-specific. I left it out for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I had in mind is provide the API with an Object to cache for, so it is not Cassandra-specific

@codecov-io
Copy link

Codecov Report

Merging #1712 (6cb9019) into master (1748259) will increase coverage by 0.56%.
The diff coverage is 40.62%.

Impacted file tree graph

@@ Coverage Diff @@ ## master #1712 +/- ## ============================================ + Coverage 61.30% 61.87% +0.56%  + Complexity 3621 3469 -152  ============================================ Files 401 381 -20 Lines 18250 17417 -833 Branches 2507 2406 -101 ============================================ - Hits 11188 10776 -412  + Misses 6278 5887 -391  + Partials 784 754 -30 
Impacted Files Coverage Δ Complexity Δ
...va/co/elastic/apm/agent/impl/ElasticApmTracer.java 65.85% <0.00%> (-0.82%) 83.00 <0.00> (ø)
...n/java/co/elastic/apm/agent/impl/GlobalTracer.java 41.46% <0.00%> (-1.04%) 11.00 <0.00> (ø)
...ain/java/co/elastic/apm/agent/impl/NoopTracer.java 5.26% <0.00%> (-0.30%) 1.00 <0.00> (ø)
...rc/main/java/co/elastic/apm/agent/impl/Tracer.java 100.00% <ø> (ø) 0.00 <0.00> (ø)
...co/elastic/apm/agent/impl/context/Destination.java 75.34% <0.00%> (-13.37%) 21.00 <0.00> (ø)
...astic/apm/agent/impl/transaction/AbstractSpan.java 75.26% <0.00%> (-0.82%) 63.00 <0.00> (ø)
...stic/apm/agent/jdbc/ConnectionInstrumentation.java 72.72% <0.00%> (ø) 4.00 <0.00> (ø)
...co/elastic/apm/agent/jdbc/JdbcInstrumentation.java 100.00% <ø> (+72.72%) 3.00 <0.00> (ø)
...astic/apm/agent/jdbc/StatementInstrumentation.java 36.63% <0.00%> (ø) 4.00 <0.00> (ø)
...a/co/elastic/apm/agent/jdbc/helper/JdbcHelper.java 0.00% <0.00%> (ø) 0.00 <0.00> (ø)
... and 34 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1748259...6cb9019. Read the comment docs.

Comment on lines +150 to +155
try {
Class.forName("com.datastax.driver.core.Host").getMethod("getSocketAddress");
delegate = localDelegate = (DestinationAddressSetter) Class.forName(DestinationAddressSetter.class.getName() + "$WithSocketAddress").getEnumConstants()[0];
} catch (ReflectiveOperationException | LinkageError ignore) {
delegate = localDelegate = WithInetAddress.INSTANCE;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks good!
Do you have some test app where this can be tested with class loading that better resembles real scenarios?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have manually tested with a standalone Spring Boot application:

Click to expand
@SpringBootApplication public class CassandraDemoApplication { public static void main(String[] args) { SpringApplication.run(CassandraDemoApplication.class, args); } @Bean public Cluster cluster(@Value("${cassandra.port}") int cassandraPort) { Cluster cluster = Cluster.builder() .addContactPoint("localhost") .withPort(cassandraPort) .withoutMetrics() .build(); try (Session s = cluster.connect()) { s.execute("CREATE KEYSPACE IF NOT EXISTS test WITH replication = {'class':'SimpleStrategy','replication_factor':'1'};"); } try (Session s = cluster.connect("test")) { s.execute("CREATE TABLE users (id UUID, name text, PRIMARY KEY(name, id))"); s.execute(s.prepare("INSERT INTO users (id, name) values (?, ?)").bind(UUID.randomUUID(), "alice")); } catch (Exception ignore) { } return cluster; } @RestController public static class HomeController { private final Cluster cluster; public HomeController(@Autowired Cluster cluster) { this.cluster = cluster; } @GetMapping("/") public String home() { return "ok"; } @GetMapping("/cassy") public String cassandra() { try (Session s = cluster.connect("test")) { return s.execute("SELECT * FROM users where name = 'alice' ALLOW FILTERING").one().getString("name"); } } } }

With version 2.0.1, it only records destination.address, and version 2.0.2 also records destination.port.

@felixbarny felixbarny merged commit 60ca9ca into elastic:master Apr 1, 2021
@felixbarny felixbarny deleted the cassandra branch April 1, 2021 13:46
v1v added a commit to v1v/apm-agent-java that referenced this pull request Apr 7, 2021
…va into feature/java-stable-tag * 'feature/java-stable-tag' of github.com:v1v/apm-agent-java: (534 commits) Added Support for JBoss Logging to the log correlation plugin (elastic#1737) Removing improper RabbitMQ reference from instrumentation class (elastic#1745) Loading Advice classes lazily when required (elastic#1736) add support for ibm JVMs (elastic#1739) Adds circuit breaker to app deployment in load pipeline (elastic#1731) Bump json-schema-validator from 1.0.50 to 1.0.51 (elastic#1732) Bump java-driver-core from 4.10.0 to 4.11.0 (elastic#1733) Cassandra instrumentation (elastic#1712) Build apm-agent-attach-cli before application-server-integration-tests (elastic#1729) Fix thread pool method matchers (elastic#1717) Always use English locale when formatting doubles (elastic#1727) (elastic#1728) feat: grab locust metrics on load tests (elastic#1724) log readonly msg errors only in debug (elastic#1715) feat: use metricbeat to grab host metrics (elastic#1718) Eliminate log4j shaders dependency in slf4j (elastic#1723) Fix log correlation for log4j2 (elastic#1720) Allowing more time for the test Bump json-schema-validator from 1.0.49 to 1.0.50 (elastic#1711) Fix master build and print URL on connection error Attacher improvements (elastic#1667) ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

4 participants