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

Report affected rows for DML statements #883

Merged
merged 5 commits into from
Oct 24, 2019

Conversation

SylvainJuge
Copy link
Member

@SylvainJuge SylvainJuge commented Oct 11, 2019

Fixes #707

Reports the number of rows affected by a DML statement (INSERT,DELETE,UPDATE) in database span.

Checklist

@codecov-io
Copy link

codecov-io commented Oct 11, 2019

Codecov Report

Merging #883 into master will decrease coverage by 0.41%.
The diff coverage is n/a.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #883      +/-   ##
============================================
- Coverage     65.13%   64.71%   -0.42%     
  Complexity       85       85              
============================================
  Files           232      231       -1     
  Lines          9878     9662     -216     
  Branches       1326     1282      -44     
============================================
- Hits           6434     6253     -181     
+ Misses         3050     3025      -25     
+ Partials        394      384      -10
Impacted Files Coverage Δ Complexity Δ
...ava/co/elastic/apm/agent/jmx/JmxMetricTracker.java 77.33% <0%> (-9%) 0% <0%> (ø)
...m/agent/util/DependencyInjectingServiceLoader.java 77.77% <0%> (-7.41%) 0% <0%> (ø)
...lastic/apm/agent/impl/ElasticApmTracerBuilder.java 79.01% <0%> (-2.19%) 0% <0%> (ø)
...va/co/elastic/apm/agent/impl/ElasticApmTracer.java 72.14% <0%> (-2.1%) 0% <0%> (ø)
...c/apm/agent/context/AbstractLifecycleListener.java
...co/elastic/apm/agent/report/ApmServerReporter.java 60.95% <0%> (+3.8%) 0% <0%> (ø) ⬇️
...va/co/elastic/apm/agent/report/ReportingEvent.java 96.66% <0%> (+10%) 0% <0%> (ø) ⬇️

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 c8309f8...763a4a3. Read the comment docs.

Copy link
Member

@felixbarny felixbarny left a comment

Choose a reason for hiding this comment

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

Looks good overall. Some minor comments. Also, please format the code you added.

for (int i = 0; i < array.length; i++) {
affectedCount += array[i];
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Extract public static method, annotate with @VisibleForAdvice and reuse in ExecuteWithoutQueryInstrumentation. As only Java core types are used, there are no classloader issues.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get that- those APIs return either int or long, not arrays...
When fixing, you will need to create two separate advices.

Copy link
Member Author

Choose a reason for hiding this comment

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

should be fixed now

@Advice.Thrown @Nullable Throwable t) throws SQLException {
if (span != null) {
if( t == null){
span.getContext().getDb().withAffectedRowsCount(statement.getUpdateCount());
Copy link
Contributor

Choose a reason for hiding this comment

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

The javadoc for getUpdateCount says: "This method should be called only once per result". I believe this means we cannot call it here.

Db db = reporter.getFirstSpan().getContext().getDb();
assertThat(db.getStatement()).isEqualTo(insert);
assertThat(db.getAffectedRowsCount())
.isEqualTo(statement.getUpdateCount())
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, it seems all drivers DO support multiple invocations of getUpdateCount despite the javadoc. Still not sure if it is safe enough to use it...

for (int i = 0; i < array.length; i++) {
affectedCount += array[i];
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't get that- those APIs return either int or long, not arrays...
When fixing, you will need to create two separate advices.

@eyalkoren
Copy link
Contributor

Also - this new value should be serialized into DB span events as part of the implementation of elastic/apm#112

Adding a label for each datasource provider makes it easier to know
which datasource connection pool is being tested
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!! Well done!
Only not 100% about invoking getUpdateCount() in the instrumentation...
Otherwise LGTM, so approving and leave that to you.


long expectedAffected = 2;
if (isKnownDatabase("MySQL", "10.")) {
// for an unknown reason mariadb 10 has unexpected but somehow consistent behavior here
Copy link
Contributor

Choose a reason for hiding this comment

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

The javadoc says:

     * <LI>A value of <code>SUCCESS_NO_INFO</code> -- indicates that the command was
     * processed successfully but that the number of rows affected is
     * unknown

where the constant java.sql.Statement#SUCCESS_NO_INFO is -2.

span.getContext()
.getDb()
// getUpdateCount javadoc indicates that this method should be called only once
// however in practice adding this extra call seem to not have noticeable side effects
Copy link
Contributor

Choose a reason for hiding this comment

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

I am still not sure about that. On the one hand, the testMultipleRowsModifiedStatement passes, so should be OK for at least most of the cases. On the other hand, breaking the application in the other rare cases is embarrassing...
@felixbarny WDYT? Does the added value of this field worth the risk?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, with ResulstSets that hold open cursors, concurrent usages can be very unpleasant. It would even make sense to enforce not allowing multiple invocations of this API.
However, the update count can be easily cached and I assume that's what most drivers do, so not sure why it has the same limitation.

@SylvainJuge SylvainJuge merged commit b258d29 into elastic:master Oct 24, 2019
@SylvainJuge SylvainJuge deleted the jdbc-capture-modified-records branch October 24, 2019 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Include "number of rows affected" in the data captured for SQL DML commands
5 participants