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)
This commit is contained in:
schroda
2025-03-23 00:35:16 +01:00
committed by GitHub
parent c3347d94ab
commit 4c5598cedf

View File

@@ -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 {