- Notifications
You must be signed in to change notification settings - Fork 327
Cassandra instrumentation #1712
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
Conversation
💚 Build Succeeded
Expand to view the summary
Build stats
Test stats 🧪
Trends 🧪💚 Flaky test reportTests succeeded. Expand to view the summary
Test stats 🧪
|
eyalkoren left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome capability addition! ❤️
apm-agent-core/src/main/java/co/elastic/apm/agent/db/signature/SignatureParser.java Outdated Show resolved Hide resolved
| } | ||
| } | ||
| | ||
| public void withInetAddress(InetAddress inetAddress) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 -
Line 299 in 789406b
| destination.withAddress(connection.getAddress().getHostName()); |
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. There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
apm-agent-core/src/test/java/co/elastic/apm/agent/MockReporter.java Outdated Show resolved Hide resolved
...ssandra3-plugin/src/main/java/co/elastic/apm/agent/cassandra3/Cassandra3Instrumentation.java Outdated Show resolved Hide resolved
| } | ||
| final Span span = (Span) spanObj; | ||
| span.captureException(thrown).deactivate(); | ||
| Futures.addCallback(result, new FutureCallback<ResultSet>() { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
...sandra4-plugin/src/test/java/co/elastic/apm/agent/cassandra/Cassandra4InstrumentationIT.java Outdated Show resolved Hide resolved
...sandra3-plugin/src/test/java/co/elastic/apm/agent/cassandra/Cassandra3InstrumentationIT.java Outdated Show resolved Hide resolved
apm-agent-core/src/main/java/co/elastic/apm/agent/db/signature/SignatureParser.java Outdated Show resolved Hide resolved
removing destination checks, assuming that the generic validation that the fields are non-empty is good enough
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
| 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; | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
…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) ...
What does this PR do?
Checklist
[ ] Added an API method or config option? Document in which version this will be introducedThe type matcher excludes 1.x drivers