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

GraphQL Instrumentation #396

Merged
merged 97 commits into from
Sep 2, 2021
Merged

GraphQL Instrumentation #396

merged 97 commits into from
Sep 2, 2021

Conversation

twcrone
Copy link
Contributor

@twcrone twcrone commented Aug 31, 2021

Overview

GraphQL Instrumentation

Related Github Issue

For every metric created, the agent creates a scoped and unscoped version. An unscoped metric could get filtered out from being sent by the agent if it doesn't meet certain criteria. This prevents the GraphQL metrics from being filtered.

Checks

[X] Are your contributions backwards compatible with relevant frameworks and APIs?
[] Does your code contain any breaking changes? Please describe.
[X] Does your code introduce any new dependencies? Please describe.

@XiXiaPdx
Copy link
Contributor

Manual testing of NetFlix DGS example jav app - looks good. https://staging.onenr.io/0mMRNAKLAwn

@twcrone
Copy link
Contributor Author

twcrone commented Aug 31, 2021

So not really 50+ files of code. We have our GraphQL test files in separate *.gql files under src/test/resources

@twcrone
Copy link
Contributor Author

twcrone commented Aug 31, 2021

We are totally fine squashing or whatever team wants to do.

Copy link
Contributor

@jasonjkeller jasonjkeller left a comment

Choose a reason for hiding this comment

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

A few minor nits but overall looks good!

@@ -25,4 +27,6 @@
String getHttpComponent();

String getTransactionId();

Map<String, Object> getAgentAttributes();
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this? Looks like testing only?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, so that we can get the attributes from span event through introspector. (channeling Xi Xia)

List<Selection> selection = selections.stream()
.filter(namedNode -> notFederatedFieldName(getNameFrom(namedNode)))
.collect(Collectors.toList());
// there can be only one, or we stop digging into query
Copy link
Contributor

Choose a reason for hiding this comment

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

Highlander

Copy link
Contributor

@meiao meiao left a comment

Choose a reason for hiding this comment

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

Mostly nit picking.

Comment on lines 15 to 17
public static void reportResolverThrowableToNR(Throwable e) {
NewRelic.noticeError(e);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you foresee this method doing something else?
In the place that this is called, it gives the impression that it would do something else besides calling noticeError.
Same question for reportGraphQLException.

Though I do see the value in reportGraphQLError.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok

Comment on lines 61 to 63
private static <T> T getValueOrDefault(T value, T defaultValue) {
return value == null ? defaultValue : value;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a great method that we could use in other places.
Do we have a Util class where it could live?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I don't know. I'm not sure where something like this goes.

Comment on lines 143 to 145
private static boolean isNullOrEmpty(final Collection<?> c) {
return c == null || c.isEmpty();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This too should be in a Util class

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My rule is, if you use it twice, copy paste is fine. But if you go to use it in a third place, pull it out. But I can pull it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Typically I use a Collection Utils class that exists in latter versions of Java

return null;
}
List<Selection> selections = selectionSet.getSelections();
if (selections == null || selections.isEmpty()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Util method I mentioned below could be reused here.

}

protected void handleFetchingException(ExecutionContext executionContext, DataFetchingEnvironment environment, Throwable e) {
reportResolverThrowableToNR(e);
Copy link
Contributor

Choose a reason for hiding this comment

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

Following up on my comment on GraphQLErrorHandler.
I think that calling NewRelic.notifyError(e); here is less surprising for the reader without loss of the context given by the method name.


@ParameterizedTest
@CsvFileSource(resources = "/obfuscateQueryTestData/obfuscate-query-test-data.csv", delimiter = '|', numLinesToSkip = 2)
public void testObfuscateQuery(String queryToObfuscateFile, String expectedObfuscatedQueryFile) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just nit picking, but the File in the var name is odd.

dependencies {
implementation(project(":agent-bridge"))

implementation 'com.graphql-java:graphql-java:16.2'
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to add something to the THIRD_PARTY_NOTICES.md file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

??? this is the library we are instrumenting. I don't know about this type of file.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not for dependencies used in instrumentation modules.

Copy link
Contributor

Choose a reason for hiding this comment

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

Typically it's just libraries that we directly use in development of the agent that need to be declared.

@twcrone twcrone force-pushed the graphql-java branch 2 times, most recently from 495c2ea to 3ac30c1 Compare September 1, 2021 23:13
- Add copyright statements
- Refactor out a couple utility methods
- Remove a couple unnecessary passthru methods
- Fix a couple unit test parameter names for clarity
@twcrone twcrone merged commit 1be967c into main Sep 2, 2021
@twcrone twcrone deleted the graphql-java branch September 2, 2021 13: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.

4 participants