Skip to content

Commit

Permalink
Move away from the deprecated GraphQL Java Instrumentation methods. (#…
Browse files Browse the repository at this point in the history
…1334)

This commit adopts the new GraphQL Java 19 Instrumentation methods.
In addition, we are adding metadata information about the properties
that can be used to customize the metrics, and tags associated with
those metrics, in DGS.
  • Loading branch information
berngp committed Nov 30, 2022
1 parent 97f6c4c commit 471dc4f
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 33 deletions.
Expand Up @@ -16,6 +16,7 @@ import graphql.analysis.QueryVisitorFieldEnvironment
import graphql.analysis.QueryVisitorStub
import graphql.execution.instrumentation.*
import graphql.execution.instrumentation.SimpleInstrumentationContext.whenCompleted
import graphql.execution.instrumentation.parameters.InstrumentationCreateStateParameters
import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters
import graphql.execution.instrumentation.parameters.InstrumentationExecutionParameters
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters
Expand Down Expand Up @@ -46,29 +47,24 @@ class DgsGraphQLMetricsInstrumentation(

companion object {
private val log: Logger = LoggerFactory.getLogger(DgsGraphQLMetricsInstrumentation::class.java)

private object DefaultExecutionStrategyInstrumentationContext : ExecutionStrategyInstrumentationContext {
override fun onDispatched(result: CompletableFuture<ExecutionResult>) {
}

override fun onCompleted(result: ExecutionResult?, t: Throwable?) {
}
}
}

override fun createState(): InstrumentationState {
override fun createState(parameters: InstrumentationCreateStateParameters): InstrumentationState {
return MetricsInstrumentationState(
registrySupplier.get(),
limitedTagMetricResolver
)
}

override fun beginExecution(parameters: InstrumentationExecutionParameters): InstrumentationContext<ExecutionResult> {
val state: MetricsInstrumentationState = parameters.getInstrumentationState()
state.startTimer()
override fun beginExecution(
parameters: InstrumentationExecutionParameters,
state: InstrumentationState
): InstrumentationContext<ExecutionResult> {
val miState: MetricsInstrumentationState = state as MetricsInstrumentationState
miState.startTimer()

state.operationName = Optional.ofNullable(parameters.operation)
state.isIntrospectionQuery = QueryUtils.isIntrospectionQuery(parameters.executionInput)
miState.operationName = Optional.ofNullable(parameters.operation)
miState.isIntrospectionQuery = QueryUtils.isIntrospectionQuery(parameters.executionInput)

return object : SimpleInstrumentationContext<ExecutionResult>() {

Expand All @@ -77,27 +73,28 @@ class DgsGraphQLMetricsInstrumentation(
}

override fun onCompleted(result: ExecutionResult, exc: Throwable?) {
state.stopTimer(
miState.stopTimer(
properties.autotime
.builder(GqlMetric.QUERY.key)
.tags(tagsProvider.getContextualTags())
.tags(tagsProvider.getExecutionTags(parameters, result, exc))
.tags(state.tags())
.tags(miState.tags())
)
}
}
}

override fun instrumentExecutionResult(
executionResult: ExecutionResult,
parameters: InstrumentationExecutionParameters
parameters: InstrumentationExecutionParameters,
state: InstrumentationState
): CompletableFuture<ExecutionResult> {
val state = parameters.getInstrumentationState<MetricsInstrumentationState>()
val miState: MetricsInstrumentationState = state as MetricsInstrumentationState
val tags =
Tags.empty()
.and(tagsProvider.getContextualTags())
.and(tagsProvider.getExecutionTags(parameters, executionResult, null))
.and(state.tags())
.and(miState.tags())

ErrorUtils
.sanitizeErrorPaths(executionResult)
Expand All @@ -117,13 +114,14 @@ class DgsGraphQLMetricsInstrumentation(

override fun instrumentDataFetcher(
dataFetcher: DataFetcher<*>,
parameters: InstrumentationFieldFetchParameters
parameters: InstrumentationFieldFetchParameters,
state: InstrumentationState
): DataFetcher<*> {
val state: MetricsInstrumentationState = parameters.getInstrumentationState()
val miState: MetricsInstrumentationState = state as MetricsInstrumentationState
val gqlField = TagUtils.resolveDataFetcherTagValue(parameters)

if (parameters.isTrivialDataFetcher ||
state.isIntrospectionQuery ||
miState.isIntrospectionQuery ||
TagUtils.shouldIgnoreTag(gqlField) ||
!schemaProvider.isFieldInstrumentationEnabled(gqlField)
) {
Expand All @@ -135,7 +133,7 @@ class DgsGraphQLMetricsInstrumentation(
val baseTags =
Tags.of(GqlTag.FIELD.key, gqlField)
.and(tagsProvider.getContextualTags())
.and(state.tags())
.and(miState.tags())

val sampler = Timer.start(registry)
try {
Expand Down Expand Up @@ -165,28 +163,34 @@ class DgsGraphQLMetricsInstrumentation(
* Port the implementation from MaxQueryComplexityInstrumentation in graphql-java and store the computed complexity
* in the MetricsInstrumentationState for access to add tags to metrics.
*/
override fun beginValidation(parameters: InstrumentationValidationParameters): InstrumentationContext<List<ValidationError>> {
override fun beginValidation(
parameters: InstrumentationValidationParameters,
state: InstrumentationState
): InstrumentationContext<List<ValidationError>> {
return whenCompleted { errors, throwable ->
if (errors != null && errors.isNotEmpty() || throwable != null) {
return@whenCompleted
}
val state: MetricsInstrumentationState = parameters.getInstrumentationState()
val miState: MetricsInstrumentationState = state as MetricsInstrumentationState
if (parameters.document != null) {
state.querySignature = optQuerySignatureRepository.flatMap { it.get(parameters.document, parameters) }
miState.querySignature = optQuerySignatureRepository.flatMap { it.get(parameters.document, parameters) }
}
}
}

override fun beginExecuteOperation(parameters: InstrumentationExecuteOperationParameters): InstrumentationContext<ExecutionResult> {
val state: MetricsInstrumentationState = parameters.getInstrumentationState()
override fun beginExecuteOperation(
parameters: InstrumentationExecuteOperationParameters,
state: InstrumentationState
): InstrumentationContext<ExecutionResult> {
val miState: MetricsInstrumentationState = state as MetricsInstrumentationState
if (parameters.executionContext.getRoot<Any>() == null) {
state.operation = Optional.of(parameters.executionContext.operationDefinition.operation.name.uppercase())
if (!state.operationName.isPresent) {
state.operationName = Optional.ofNullable(parameters.executionContext.operationDefinition?.name)
miState.operation = Optional.of(parameters.executionContext.operationDefinition.operation.name.uppercase())
if (!miState.operationName.isPresent) {
miState.operationName = Optional.ofNullable(parameters.executionContext.operationDefinition?.name)
}
}

state.queryComplexity = ComplexityUtils.resolveComplexity(parameters)
miState.queryComplexity = ComplexityUtils.resolveComplexity(parameters)
return super.beginExecuteOperation(parameters)
}

Expand Down
Expand Up @@ -13,6 +13,12 @@
"description": "Enables DGS' GraphQL metrics, via micrometer.",
"defaultValue": true
},
{
"name": "management.metrics.dgs-graphql.autotime",
"type": "org.springframework.boot.actuate.autoconfigure.metrics.AutoTimeProperties",
"description": "Enables DGS' GraphQL metrics, via micrometer.",
"defaultValue": true
},
{
"name": "management.metrics.dgs-graphql.tag-customizers.outcome.enabled",
"type": "java.lang.Boolean",
Expand Down Expand Up @@ -44,5 +50,27 @@
"defaultValue": true
}
],
"hints": []
"hints": [
{
"name": "management.metrics.dgs-graphql.autotime.percentiles",
"values": [
{
"value": ".50",
"description": "The 50% percentile, or median."
},
{
"value": ".90",
"description": "The 90% percentile."
},
{
"value": ".95",
"description": "The 95% percentile."
},
{
"value": ".99",
"description": "The 99% percentile."
}
]
}
]
}

0 comments on commit 471dc4f

Please sign in to comment.