Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0651b82
adding Profiler
andimarek May 19, 2025
cc1de5e
progress
andimarek May 19, 2025
eef80ec
track running time
andimarek May 20, 2025
15cf642
tracking datafetcher result types
andimarek May 20, 2025
b7379ef
operation details
andimarek May 20, 2025
275eaac
wip
andimarek May 21, 2025
cd002c0
dataloader tracking
andimarek May 21, 2025
b75a14d
Merge branch 'master' into profiler-2
andimarek May 26, 2025
450a9fc
track dataloader dispatch
andimarek May 26, 2025
5e9e713
track dataloader dispatch
andimarek May 27, 2025
b3515b7
Merge branch 'master' into profiler-2
andimarek Jun 3, 2025
1800f77
Merge branch 'master' into profiler-2
andimarek Jun 30, 2025
221b416
non nullable handling
andimarek Jul 1, 2025
2ba4123
Merge branch 'master' into profiler-2
andimarek Jul 8, 2025
4008c11
master merging
andimarek Jul 9, 2025
f7e31e6
wip
andimarek Jul 16, 2025
3e29da4
Merge branch 'master' into profiler-2
andimarek Jul 16, 2025
999bb2f
handle non null case
andimarek Jul 16, 2025
5dde0e3
handle non null case
andimarek Jul 16, 2025
4a47b9d
add Map specific summary methods
andimarek Jul 17, 2025
0b7c15b
collect instrumentations
andimarek Jul 17, 2025
e6faa18
manual dispatch collected
andimarek Jul 18, 2025
0ab88da
wip
andimarek Jul 18, 2025
8bcdef8
wip
andimarek Jul 18, 2025
62f1e84
improve naming
andimarek Jul 18, 2025
76cdbc1
stabilize test
andimarek Jul 18, 2025
ca618b4
wip
andimarek Jul 18, 2025
535eb8e
counting wrapped trivial data fetchers
andimarek Jul 18, 2025
a04f5cb
introspection fields
andimarek Jul 19, 2025
572090e
data fetcher type statistics
andimarek Jul 19, 2025
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
9 changes: 7 additions & 2 deletions src/main/java/graphql/EngineRunningState.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,18 @@ public class EngineRunningState {

private final AtomicInteger isRunning = new AtomicInteger(0);

public EngineRunningState(ExecutionInput executionInput) {

public EngineRunningState(ExecutionInput executionInput, Profiler profiler) {
EngineRunningObserver engineRunningObserver = executionInput.getGraphQLContext().get(EngineRunningObserver.ENGINE_RUNNING_OBSERVER_KEY);
EngineRunningObserver wrappedObserver = profiler.wrapEngineRunningObserver(engineRunningObserver);
this.engineRunningObserver = wrappedObserver;
this.executionInput = executionInput;
this.graphQLContext = executionInput.getGraphQLContext();
this.executionId = executionInput.getExecutionId();
this.engineRunningObserver = executionInput.getGraphQLContext().get(EngineRunningObserver.ENGINE_RUNNING_OBSERVER_KEY);
}



public <U, T> CompletableFuture<U> handle(CompletableFuture<T> src, BiFunction<? super T, Throwable, ? extends U> fn) {
if (engineRunningObserver == null) {
return src.handle(fn);
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/graphql/ExecutionInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class ExecutionInput {
private final ExecutionId executionId;
private final Locale locale;
private final AtomicBoolean cancelled;
private final boolean profileExecution;


@Internal
Expand All @@ -50,6 +51,7 @@ private ExecutionInput(Builder builder) {
this.localContext = builder.localContext;
this.extensions = builder.extensions;
this.cancelled = builder.cancelled;
this.profileExecution = builder.profileExecution;
}

/**
Expand Down Expand Up @@ -186,6 +188,11 @@ public void cancel() {
cancelled.set(true);
}


public boolean isProfileExecution() {
return profileExecution;
}

/**
* This helps you transform the current ExecutionInput object into another one by starting a builder with all
* the current values and allows you to transform it how you want.
Expand Down Expand Up @@ -266,6 +273,7 @@ public static class Builder {
private Locale locale = Locale.getDefault();
private ExecutionId executionId;
private AtomicBoolean cancelled = new AtomicBoolean(false);
private boolean profileExecution;

/**
* Package level access to the graphql context
Expand Down Expand Up @@ -414,6 +422,11 @@ public Builder dataLoaderRegistry(DataLoaderRegistry dataLoaderRegistry) {
return this;
}

public Builder profileExecution(boolean profileExecution) {
this.profileExecution = profileExecution;
return this;
}
Copy link
Member

Choose a reason for hiding this comment

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

For another PR, not this one

Can you add the toggle to GraphQLUnusualConfiguration instead?

Copy link
Member

Choose a reason for hiding this comment

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

To be discussed!

Copy link
Member

Choose a reason for hiding this comment

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

Can be considered in another PR


public ExecutionInput build() {
return new ExecutionInput(this);
}
Expand Down
29 changes: 17 additions & 12 deletions src/main/java/graphql/GraphQL.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import graphql.execution.ExecutionId;
import graphql.execution.ExecutionIdProvider;
import graphql.execution.ExecutionStrategy;
import graphql.execution.ResponseMapFactory;
import graphql.execution.SimpleDataFetcherExceptionHandler;
import graphql.execution.SubscriptionExecutionStrategy;
import graphql.execution.ValueUnboxer;
Expand All @@ -27,10 +26,11 @@
import graphql.language.Document;
import graphql.schema.GraphQLSchema;
import graphql.validation.ValidationError;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.NullUnmarked;

import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.atomic.AtomicReference;
Expand Down Expand Up @@ -83,6 +83,7 @@
*/
@SuppressWarnings("Duplicates")
@PublicApi
@NullMarked
public class GraphQL {

/**
Expand Down Expand Up @@ -259,16 +260,17 @@ public GraphQL transform(Consumer<GraphQL.Builder> builderConsumer) {
.queryExecutionStrategy(this.queryStrategy)
.mutationExecutionStrategy(this.mutationStrategy)
.subscriptionExecutionStrategy(this.subscriptionStrategy)
.executionIdProvider(Optional.ofNullable(this.idProvider).orElse(builder.idProvider))
.instrumentation(Optional.ofNullable(this.instrumentation).orElse(builder.instrumentation))
.preparsedDocumentProvider(Optional.ofNullable(this.preparsedDocumentProvider).orElse(builder.preparsedDocumentProvider));
.executionIdProvider(this.idProvider)
.instrumentation(this.instrumentation)
.preparsedDocumentProvider(this.preparsedDocumentProvider);

builderConsumer.accept(builder);

return builder.build();
}

@PublicApi
@NullUnmarked
public static class Builder {
private GraphQLSchema graphQLSchema;
private ExecutionStrategy queryExecutionStrategy;
Expand Down Expand Up @@ -478,9 +480,11 @@ public CompletableFuture<ExecutionResult> executeAsync(UnaryOperator<ExecutionIn
* @return a promise to an {@link ExecutionResult} which can include errors
*/
public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionInput) {
EngineRunningState engineRunningState = new EngineRunningState(executionInput);
Profiler profiler = executionInput.isProfileExecution() ? new ProfilerImpl(executionInput.getGraphQLContext()) : Profiler.NO_OP;
EngineRunningState engineRunningState = new EngineRunningState(executionInput, profiler);
return engineRunningState.engineRun(() -> {
ExecutionInput executionInputWithId = ensureInputHasId(executionInput);
profiler.setExecutionInputAndInstrumentation(executionInputWithId, instrumentation);
engineRunningState.updateExecutionInput(executionInputWithId);

CompletableFuture<InstrumentationState> instrumentationStateCF = instrumentation.createStateAsync(new InstrumentationCreateStateParameters(this.graphQLSchema, executionInputWithId));
Expand All @@ -497,7 +501,7 @@ public CompletableFuture<ExecutionResult> executeAsync(ExecutionInput executionI

GraphQLSchema graphQLSchema = instrumentation.instrumentSchema(this.graphQLSchema, instrumentationParameters, instrumentationState);

CompletableFuture<ExecutionResult> executionResult = parseValidateAndExecute(instrumentedExecutionInput, graphQLSchema, instrumentationState, engineRunningState);
CompletableFuture<ExecutionResult> executionResult = parseValidateAndExecute(instrumentedExecutionInput, graphQLSchema, instrumentationState, engineRunningState, profiler);
//
// finish up instrumentation
executionResult = executionResult.whenComplete(completeInstrumentationCtxCF(executionInstrumentation));
Expand Down Expand Up @@ -529,7 +533,7 @@ private ExecutionInput ensureInputHasId(ExecutionInput executionInput) {
}


private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInput executionInput, GraphQLSchema graphQLSchema, InstrumentationState instrumentationState, EngineRunningState engineRunningState) {
private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInput executionInput, GraphQLSchema graphQLSchema, InstrumentationState instrumentationState, EngineRunningState engineRunningState, Profiler profiler) {
AtomicReference<ExecutionInput> executionInputRef = new AtomicReference<>(executionInput);
Function<ExecutionInput, PreparsedDocumentEntry> computeFunction = transformedInput -> {
// if they change the original query in the pre-parser, then we want to see it downstream from then on
Expand All @@ -542,7 +546,7 @@ private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInpu
return CompletableFuture.completedFuture(new ExecutionResultImpl(preparsedDocumentEntry.getErrors()));
}
try {
return execute(executionInputRef.get(), preparsedDocumentEntry.getDocument(), graphQLSchema, instrumentationState, engineRunningState);
return execute(Assert.assertNotNull(executionInputRef.get()), preparsedDocumentEntry.getDocument(), graphQLSchema, instrumentationState, engineRunningState, profiler);
} catch (AbortExecutionException e) {
return CompletableFuture.completedFuture(e.toExecutionResult());
}
Expand All @@ -551,7 +555,7 @@ private CompletableFuture<ExecutionResult> parseValidateAndExecute(ExecutionInpu

private PreparsedDocumentEntry parseAndValidate(AtomicReference<ExecutionInput> executionInputRef, GraphQLSchema graphQLSchema, InstrumentationState instrumentationState) {

ExecutionInput executionInput = executionInputRef.get();
ExecutionInput executionInput = assertNotNull(executionInputRef.get());

ParseAndValidateResult parseResult = parse(executionInput, graphQLSchema, instrumentationState);
if (parseResult.isFailure()) {
Expand Down Expand Up @@ -606,13 +610,14 @@ private CompletableFuture<ExecutionResult> execute(ExecutionInput executionInput
Document document,
GraphQLSchema graphQLSchema,
InstrumentationState instrumentationState,
EngineRunningState engineRunningState
EngineRunningState engineRunningState,
Profiler profiler
) {

Execution execution = new Execution(queryStrategy, mutationStrategy, subscriptionStrategy, instrumentation, valueUnboxer, doNotAutomaticallyDispatchDataLoader);
ExecutionId executionId = executionInput.getExecutionId();

return execution.execute(document, graphQLSchema, executionId, executionInput, instrumentationState, engineRunningState);
return execution.execute(document, graphQLSchema, executionId, executionInput, instrumentationState, engineRunningState, profiler);
}

}
59 changes: 59 additions & 0 deletions src/main/java/graphql/Profiler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package graphql;

import graphql.execution.EngineRunningObserver;
import graphql.execution.ResultPath;
import graphql.execution.instrumentation.Instrumentation;
import graphql.language.OperationDefinition;
import graphql.schema.DataFetcher;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLOutputType;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

@Internal
@NullMarked
public interface Profiler {
Copy link
Member

Choose a reason for hiding this comment

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

Add a quick JavaDoc explaining what this does

A Profiler monitors important execution timings and counters. Enable this via ExecutionInput/new Unusual Configuration method

Of course 1 sentence isn't enough, let's add a documentation link here when it's written

Copy link
Member Author

Choose a reason for hiding this comment

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

This is an internal class btw



Profiler NO_OP = new Profiler() {
};


default void setExecutionInputAndInstrumentation(ExecutionInput executionInput, Instrumentation instrumentation) {

}

default void dataLoaderUsed(String dataLoaderName) {


}

default void fieldFetched(Object fetchedObject, DataFetcher<?> originalDataFetcher, DataFetcher<?> dataFetcher, ResultPath path, GraphQLFieldDefinition fieldDef, GraphQLOutputType parentType) {

}

default @Nullable EngineRunningObserver wrapEngineRunningObserver(@Nullable EngineRunningObserver engineRunningObserver) {
return engineRunningObserver;
}

default void operationDefinition(OperationDefinition operationDefinition) {

}

default void oldStrategyDispatchingAll(int level) {

}

default void batchLoadedOldStrategy(String name, int level, int count) {


}

default void batchLoadedNewStrategy(String dataLoaderName, @Nullable Integer level, int count) {

}

default <V> void manualDispatch(String dataLoaderName, int level, int count) {
Copy link
Member

Choose a reason for hiding this comment

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

Nice


}
}
Loading