Skip to content

Fix exception cause logging in QueryResultPusher #14975

Merged
rohangarg merged 23 commits intoapache:masterfrom
kgyrtkirk:queryResultPusher-cause-fix
Sep 20, 2023
Merged

Fix exception cause logging in QueryResultPusher #14975
rohangarg merged 23 commits intoapache:masterfrom
kgyrtkirk:queryResultPusher-cause-fix

Conversation

@kgyrtkirk
Copy link
Copy Markdown
Member

QueryResultPusher started clipping exception causes since #14004 was merged

cfd07a9#diff-8af2383f47d5423babf455ad7ec503ea8196e88b8b664e1d1e179163a9931f9bR211

@pranavbhole
Copy link
Copy Markdown
Contributor

org.apache.druid.error.DruidException: null
	at org.apache.druid.error.DruidException$DruidExceptionBuilder.build(DruidException.java:454) ~[druid-processing-2023.08.0-iap.jar:2023.08.0-iap]
	at org.apache.druid.error.DruidException$DruidExceptionBuilder.build(DruidException.java:444) ~[druid-processing-2023.08.0-iap.jar:2023.08.0-iap]
	at org.apache.druid.error.QueryExceptionCompat.makeException(QueryExceptionCompat.java:50) ~[druid-processing-2023.08.0-iap.jar:2023.08.0-iap]
	at org.apache.druid.error.DruidException.fromFailure(DruidException.java:154) ~[druid-processing-2023.08.0-iap.jar:2023.08.0-iap]
	at org.apache.druid.server.QueryResultPusher.handleQueryException(QueryResultPusher.java:211) ~[druid-server-2023.08.0-iap.jar:2023.08.0-iap]
	at org.apache.druid.server.QueryResultPusher.push(QueryResultPusher.java:177) ~[druid-server-2023.08.0-iap.jar:2023.08.0-iap]
	at org.apache.druid.server.QueryResource.doPost(QueryResource.java:218) ~[druid-server-2023.08.0-iap.jar:2023.08.0-iap]
	at jdk.internal.reflect.GeneratedMethodAccessor207.invoke(Unknown Source) ~[?:?]
	at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
	at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
	at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60) ~[jersey-server-1.19.4.jar:1.19.4]
	at com.sun.jersey.server.impl.model.method.dispatch.AbstractResourceMethodDispatchProvider$ResponseOutInvoker._dispatch(AbstractResourceMethodDispatchProvider.java:205) ~[jersey-server-1.19.4.jar:1.19.4]
	at com.sun.jersey.server.impl.model.method.dispatch.ResourceJavaMethodDispatcher.dispatch(ResourceJavaMethodDispatcher.java:75) ~[jersey-server-1.19.4.jar:1.19.4]
	at com.sun.jersey.server.impl.uri.rules.HttpMethodRule.accept(HttpMethodRule.java:302) ~[jersey-server-1.19.4.jar:1.19.4]
	at com.sun.jersey.server.impl.uri.rules.ResourceClassRule.accept(ResourceClassRule.java:108) ~[jersey-server-1.19.4.jar:1.19.4]
	at com.sun.jersey.server.impl.uri.rules.RightHandPathRule.accept(RightHandPathRule.java:147) ~[jersey-server-1.19.4.jar:1.19.4]
	at 

@kgyrtkirk kgyrtkirk marked this pull request as ready for review September 13, 2023 17:50
if (!(e instanceof QueryException)) {
e = new QueryInterruptedException(e);
}
return DruidException.fromFailure(new QueryExceptionCompat((QueryException) e));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(QueryException) is it safe cast?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

QueryInterruptedException extends QueryException. So should be good

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yes - actually; I've changed the way this is fixed

I now think that it was not intentional that QueryExceptionCompat have not passed the exception ; only it's message

cc: @cheddar

@Override
public void writeException(Exception e, OutputStream out) throws IOException
{
throw new RuntimeException("Unimplemented!");
Copy link
Copy Markdown
Contributor

@somu-imply somu-imply Sep 13, 2023

Choose a reason for hiding this comment

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

maybe just do a
out.write(jsonMapper.writeValueABytes(e))
here

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

the test was not covering this method - as it was already pretty awkward to write a mocked test for this class...

I've extended the test to cover this method as well... I had to add 4 when-s/etc :)

@imply-cheddar
Copy link
Copy Markdown
Contributor

The QueryCompat stuff is a compatibility layer with the way that the old QueryException worked and an attempt to map it onto DruidException.

QueryExceptions are/were exceptions that are serialized across the wire, deserialized in the brokers and then converted back into exceptions. IIRC, they don't include the stack traces because the historical-side stacktrace doesn't make sense on the broker.

The correct approach to fix odd exception reporting here is to go to the source of the exception and turn it into a meaningful DruidException which will cause the higher stacks to use the DruidException handling code instead.

@imply-cheddar
Copy link
Copy Markdown
Contributor

Also, the ResultPusher classes are tested "through" QueryResourceTest and SqlQueryResourceTest respectively. QueryResultPusher is an abstract class that's just trying to make the logic of the Resources similar, but the thing that actually matters is that the Resources are operating according to the API contract. Anyway, switching around to trying to test through one of those tests will perhaps make it easier.

@imply-cheddar
Copy link
Copy Markdown
Contributor

That said, I just double checked and adding the cause shouldn't actually change anything with wire serialization. So that should be fine and having it log-able is good. Let me provide some comments on the tests.

Copy link
Copy Markdown
Contributor

@imply-cheddar imply-cheddar left a comment

Choose a reason for hiding this comment

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

The actual change is good. Please try to remove the mocks from the test.

Comment on lines +42 to +44
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Generally speaking, we try to use mocks sparingly. And, Mockito is the less-preferred of libraries versus EasyMock (we had a test once that used Mockito to mock a ByteBuffer which 4x'd the runtime of all tests because it ended up rewriting the byte code of ByteBuffer which slowed down all other tests in that JVM).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It was an interesting excercise to rewrite this test to use EasyMock instead; its definetly different.

Comment thread server/src/test/java/org/apache/druid/server/QueryResultPusherTest.java Outdated
Comment thread server/src/test/java/org/apache/druid/server/QueryResultPusherTest.java Outdated
Comment thread server/src/test/java/org/apache/druid/server/QueryResultPusherTest.java Outdated
ObjectMapper jsonMapper = new ObjectMapper();
ResponseContextConfig responseContextConfig = ResponseContextConfig.newConfig(true);
DruidNode selfNode = mock(DruidNode.class);
QueryResource.QueryMetricCounter counter = mock(QueryResource.QueryMetricCounter.class);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just make a local public static class NoopQueryMetricCounter and new that up. Your IDE should be able to generate it all with just a few keystrokes.

Copy link
Copy Markdown
Member Author

@kgyrtkirk kgyrtkirk Sep 14, 2023

Choose a reason for hiding this comment

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

all implementations of QueryMetricCounter are private - so I had to retain the mock here
there is SqlResource.QUERY_METRIC_COUNTER ; but that's in the sql module; so I can't use that here

Comment thread server/src/test/java/org/apache/druid/server/QueryResultPusherTest.java Outdated
Comment thread server/src/test/java/org/apache/druid/server/QueryResultPusherTest.java Outdated
Comment thread server/src/test/java/org/apache/druid/server/QueryResultPusherTest.java Outdated
@kgyrtkirk
Copy link
Copy Markdown
Member Author

I've also done a manual before/after check - to see if this fully fixes that the Exception is not clipped out from the historical logs - and that's fixed with this patch (no more ducks eating exceptions) :D

Copy link
Copy Markdown
Member

@rohangarg rohangarg left a comment

Choose a reason for hiding this comment

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

LGTM

@rohangarg rohangarg merged commit 79f882f into apache:master Sep 20, 2023
@rohangarg
Copy link
Copy Markdown
Member

The changes are good, the CI failures are due to some flakiness in the ITs. We re-triggered them multiple times but were unsuccessful in getting them passed. Merging on the basis that the build was green on a commit earlier, the newer commits are either changes to UTs which wouldn't affect the IT flow or master merges

@kgyrtkirk
Copy link
Copy Markdown
Member Author

thank you @rohangarg for the review and merging these changes!

@LakshSingla LakshSingla added this to the 28.0 milestone Oct 12, 2023
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.

6 participants