From 4c5598cedfcd40c2dffab31e45f38d692b2c3741 Mon Sep 17 00:00:00 2001 From: schroda <50052685+schroda@users.noreply.github.com> Date: Sun, 23 Mar 2025 00:35:16 +0100 Subject: [PATCH] Feature/graphql log execution exceptions (#1319) * Log exceptions during graphql execution Exceptions got swallowed by graphql * Add stack trace to error in graphql response Depending on the exceptions error message, the error in the response might be quite useless (e.g. "Stub!" error in android classes) --- .../graphql/server/TachideskGraphQLServer.kt | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt index 6fd65c12..a643e4c6 100644 --- a/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt +++ b/server/src/main/kotlin/suwayomi/tachidesk/graphql/server/TachideskGraphQLServer.kt @@ -11,8 +11,12 @@ import com.expediagroup.graphql.generator.execution.FlowSubscriptionExecutionStr import com.expediagroup.graphql.server.execution.GraphQLRequestHandler import com.expediagroup.graphql.server.execution.GraphQLServer import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import graphql.ExceptionWhileDataFetching import graphql.GraphQL import graphql.execution.AsyncExecutionStrategy +import graphql.execution.DataFetcherExceptionHandler +import graphql.execution.DataFetcherExceptionHandlerResult +import io.github.oshai.kotlinlogging.KotlinLogging import io.javalin.http.Context import io.javalin.websocket.WsCloseContext import io.javalin.websocket.WsMessageContext @@ -21,6 +25,7 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map import suwayomi.tachidesk.graphql.server.subscriptions.ApolloSubscriptionProtocolHandler +import suwayomi.tachidesk.server.JavalinSetup.future class TachideskGraphQLServer( requestParser: JavalinGraphQLRequestParser, @@ -44,11 +49,34 @@ class TachideskGraphQLServer( } companion object { + private val logger = KotlinLogging.logger {} + + private val exceptionHandler = + DataFetcherExceptionHandler { handlerParameters -> + future { + val exception = handlerParameters.exception + val sourceLocation = handlerParameters.sourceLocation + val path = handlerParameters.path + + logger.error(exception) { "GraphQL execution failed due to" } + + val error = + ExceptionWhileDataFetching( + path, + Throwable(exception.message + "\r\n\r\n" + exception.stackTraceToString(), exception), + sourceLocation, + ) + + DataFetcherExceptionHandlerResult.newResult().error(error).build() + } + } + private fun getGraphQLObject(): GraphQL = GraphQL .newGraphQL(schema) - .subscriptionExecutionStrategy(FlowSubscriptionExecutionStrategy()) - .mutationExecutionStrategy(AsyncExecutionStrategy()) + .queryExecutionStrategy(AsyncExecutionStrategy(exceptionHandler)) + .mutationExecutionStrategy(AsyncExecutionStrategy(exceptionHandler)) + .subscriptionExecutionStrategy(FlowSubscriptionExecutionStrategy(exceptionHandler)) .build() fun create(): TachideskGraphQLServer {