Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
import org.springframework.boot.actuate.metrics.AutoTimer;
import org.springframework.lang.Nullable;

/**
* Micrometer-based {@link SimpleInstrumentation}.
*
* @author Brian Clozel
* @since 2.7.0
*/
public class GraphQlMetricsInstrumentation extends SimpleInstrumentation {

private final MeterRegistry registry;
Expand Down Expand Up @@ -127,7 +133,7 @@ static class RequestMetricsInstrumentationState implements InstrumentationState

private Timer.Sample sample;

private AtomicLong dataFetchingCount = new AtomicLong(0L);
private final AtomicLong dataFetchingCount = new AtomicLong();

RequestMetricsInstrumentationState(AutoTimer autoTimer, MeterRegistry registry) {
this.timer = autoTimer.builder("graphql.request");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* Factory methods for Tags associated with a GraphQL request.
*
* @author Brian Clozel
* @since 1.0.0
* @since 2.7.0
*/
public final class GraphQlTags {

Expand Down Expand Up @@ -72,7 +72,7 @@ public static Tag errorPath(GraphQLError error) {
builder.append('$');
for (Object segment : pathSegments) {
try {
int index = Integer.parseUnsignedInt(segment.toString());
Integer.parseUnsignedInt(segment.toString());
builder.append("[*]");
}
catch (NumberFormatException exc) {
Expand All @@ -90,13 +90,13 @@ public static Tag dataFetchingOutcome(@Nullable Throwable exception) {

public static Tag dataFetchingPath(InstrumentationFieldFetchParameters parameters) {
ExecutionStepInfo executionStepInfo = parameters.getExecutionStepInfo();
StringBuilder dataFetchingType = new StringBuilder();
StringBuilder dataFetchingPath = new StringBuilder();
if (executionStepInfo.hasParent() && executionStepInfo.getParent().getType() instanceof GraphQLObjectType) {
dataFetchingType.append(((GraphQLObjectType) executionStepInfo.getParent().getType()).getName());
dataFetchingType.append('.');
dataFetchingPath.append(((GraphQLObjectType) executionStepInfo.getParent().getType()).getName());
dataFetchingPath.append('.');
}
dataFetchingType.append(executionStepInfo.getPath().getSegmentName());
return Tag.of("path", dataFetchingType.toString());
dataFetchingPath.append(executionStepInfo.getPath().getSegmentName());
return Tag.of("path", dataFetchingPath.toString());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ void shouldRecordTimerWhenResult() {

Timer timer = this.registry.find("graphql.request").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}

@Test
Expand Down Expand Up @@ -120,7 +120,7 @@ void shouldRecordDataFetchingMetricWhenSuccess() throws Exception {

Timer timer = this.registry.find("graphql.datafetcher").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}

@Test
Expand All @@ -135,7 +135,7 @@ void shouldRecordDataFetchingMetricWhenSuccessCompletionStage() throws Exception

Timer timer = this.registry.find("graphql.datafetcher").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}

@Test
Expand All @@ -150,7 +150,7 @@ void shouldRecordDataFetchingMetricWhenError() throws Exception {

Timer timer = this.registry.find("graphql.datafetcher").timer();
assertThat(timer).isNotNull();
assertThat(timer.takeSnapshot().count()).isEqualTo(1);
assertThat(timer.count()).isEqualTo(1);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Except
}

@Bean
static InMemoryUserDetailsManager userDetailsService() {
InMemoryUserDetailsManager userDetailsService() {
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER", "ADMIN").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ A single GraphQL query can involve many `DataFetcher` calls, so there is a dedic


The `graphql.request.datafetch.count` https://micrometer.io/docs/concepts#_distribution_summaries[distribution summary] counts the number of non-trivial `DataFetcher` calls made per request.
This metric is useful for detecting "N+1" data fetching issues and consider batch loading; it provides the `"TOTAL"` number of data fetcher calls made over the `"COUNT"` of recorded requests, as well as the `"MAX"` calls made for a single request over the considered period.
This metric is useful for detecting "N+1" data fetching issues and considering batch loading; it provides the `"TOTAL"` number of data fetcher calls made over the `"COUNT"` of recorded requests, as well as the `"MAX"` calls made for a single request over the considered period.
More options are available for <<application-properties#application-properties.actuator.management.metrics.distribution.maximum-expected-value, configuring distributions with application properties>>.

A single response can contain many GraphQL errors, counted by the `graphql.error` counter:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ You can declare `RuntimeWiringConfigurer` beans in your Spring config to get acc
Spring Boot detects such beans and adds them to the {spring-graphql-docs}#execution-graphqlsource[GraphQlSource builder].

Typically, however, applications will not implement `DataFetcher` directly and will instead create {spring-graphql-docs}#controllers[annotated controllers].
Spring Boot will automatically register `@Controller` classes with annotated handler methods and registers those as `DataFetcher`s.
Spring Boot will automatically detect `@Controller` classes with annotated handler methods and register those as `DataFetcher`s.
Here's a sample implementation for our greeting query with a `@Controller` class:

[source,java,indent=0,subs="verbatim"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
import org.springframework.stereotype.Controller;

@Controller
public class ProjectsController {
public class ProjectController {

private final List<Project> projects;

public ProjectsController() {
public ProjectController() {
this.projects = Arrays.asList(new Project("spring-boot", "Spring Boot"),
new Project("spring-graphql", "Spring GraphQL"), new Project("spring-framework", "Spring Framework"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

@Bean
DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Exception {
public DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Exception {
return http.csrf((csrf) -> csrf.disable())
// Demonstrate that method security works
// Best practice to use both for defense in depth
Expand All @@ -43,7 +43,7 @@ DefaultSecurityFilterChain springWebFilterChain(HttpSecurity http) throws Except

@Bean
@SuppressWarnings("deprecation")
public static InMemoryUserDetailsManager userDetailsService() {
public InMemoryUserDetailsManager userDetailsService() {
User.UserBuilder userBuilder = User.withDefaultPasswordEncoder();
UserDetails rob = userBuilder.username("rob").password("rob").roles("USER").build();
UserDetails admin = userBuilder.username("admin").password("admin").roles("USER", "ADMIN").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import org.springframework.boot.test.autoconfigure.graphql.GraphQlTest;
import org.springframework.graphql.test.tester.GraphQlTester;

@GraphQlTest(ProjectsController.class)
@GraphQlTest(ProjectController.class)
class ProjectControllerTests {

@Autowired
Expand Down