From 47731c7f0f87276f7484cbe7125d4ce42dd7c272 Mon Sep 17 00:00:00 2001 From: Ken Gullaksen Date: Fri, 20 Dec 2024 10:56:21 +0100 Subject: [PATCH] =?UTF-8?q?legg=20til=20metrikk=20p=C3=A5=20graphql=20kall?= =?UTF-8?q?=20med=20tag=20for=20success/error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infrastruktur/graphql/GraphQL.kt | 37 +++++++++++++++---- .../infrastruktur/http/HttpServer.kt | 19 ++++------ 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/graphql/GraphQL.kt b/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/graphql/GraphQL.kt index f8fd3dfea..cf4ff1bd5 100644 --- a/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/graphql/GraphQL.kt +++ b/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/graphql/GraphQL.kt @@ -3,11 +3,8 @@ package no.nav.arbeidsgiver.notifikasjon.infrastruktur.graphql import com.fasterxml.jackson.annotation.JsonTypeName import com.fasterxml.jackson.module.kotlin.convertValue import com.symbaloo.graphqlmicrometer.MicrometerInstrumentation -import graphql.ExecutionInput -import graphql.GraphQL +import graphql.* import graphql.GraphQL.newGraphQL -import graphql.GraphQLError -import graphql.GraphqlErrorException import graphql.execution.DataFetcherResult import graphql.schema.DataFetchingEnvironment import graphql.schema.idl.RuntimeWiring @@ -21,8 +18,10 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.future.future import no.nav.arbeidsgiver.notifikasjon.infrastruktur.Metrics.meterRegistry import no.nav.arbeidsgiver.notifikasjon.infrastruktur.coRecord +import no.nav.arbeidsgiver.notifikasjon.infrastruktur.getTimer import no.nav.arbeidsgiver.notifikasjon.infrastruktur.json.laxObjectMapper import no.nav.arbeidsgiver.notifikasjon.infrastruktur.logger +import no.nav.arbeidsgiver.notifikasjon.produsent.api.ProdusentAPI import org.intellij.lang.annotations.Language inline fun DataFetchingEnvironment.getTypedArgument(name: String): T { @@ -134,7 +133,13 @@ data class GraphQLRequest( @Language("GraphQL") val query: String, val operationName: String? = null, val variables: Map? = null, -) +) { + val queryNameRegex = Regex("\\b(mutation|query).*\\{\\s*(\\w+)") + val queryName: String + get() { + return queryNameRegex.find(query)?.groups?.get(2)?.value ?: "unknown" + } +} inline fun requireGraphql(check: Boolean, message: () -> String) { if (!check) { @@ -151,10 +156,9 @@ fun DataFetchingEnvironment.notifikasjonContext(): T = class TypedGraphQL( private val graphQL: GraphQL ) { - fun execute(request: GraphQLRequest, context: T): Any { + fun execute(request: GraphQLRequest, context: T): ExecutionResult { val executionInput = executionInput(request, context) - val result = graphQL.execute(executionInput) - return result.toSpecification() + return graphQL.execute(executionInput) } private fun executionInput( @@ -177,3 +181,20 @@ class TypedGraphQL( }.build() } } + +fun TypedGraphQL.timedExecute( + request: GraphQLRequest, + context: T +): ExecutionResult = with(Timer.start(meterRegistry)) { + execute(request, context).also { result -> + if (result.errors.isNotEmpty()) { + GraphQLLogger.log.error("graphql request failed: {}", result.errors) + } + val tags = mutableSetOf( + "queryName" to (request.queryName), + "result" to if (result.errors.isEmpty()) "success" else "error" + ) + if (context is ProdusentAPI.Context) tags.add("produsent" to context.appName) + stop(getTimer("graphql.timer", tags, "graphql request")) + } +} diff --git a/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/http/HttpServer.kt b/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/http/HttpServer.kt index d4bfbca49..0ba2a018f 100644 --- a/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/http/HttpServer.kt +++ b/app/src/main/kotlin/no/nav/arbeidsgiver/notifikasjon/infrastruktur/http/HttpServer.kt @@ -25,17 +25,14 @@ import io.micrometer.core.instrument.binder.jvm.JvmThreadMetrics import io.micrometer.core.instrument.binder.logging.LogbackMetrics import io.micrometer.core.instrument.binder.system.ProcessorMetrics import io.micrometer.core.instrument.distribution.DistributionStatisticConfig -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Deferred -import kotlinx.coroutines.asCoroutineDispatcher -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* import no.nav.arbeidsgiver.notifikasjon.bruker.BrukerAPI import no.nav.arbeidsgiver.notifikasjon.infrastruktur.Health import no.nav.arbeidsgiver.notifikasjon.infrastruktur.Metrics import no.nav.arbeidsgiver.notifikasjon.infrastruktur.graphql.GraphQLRequest import no.nav.arbeidsgiver.notifikasjon.infrastruktur.graphql.TypedGraphQL import no.nav.arbeidsgiver.notifikasjon.infrastruktur.graphql.WithCoroutineScope +import no.nav.arbeidsgiver.notifikasjon.infrastruktur.graphql.timedExecute import no.nav.arbeidsgiver.notifikasjon.infrastruktur.json.laxObjectMapper import no.nav.arbeidsgiver.notifikasjon.infrastruktur.produceMetrics import no.nav.arbeidsgiver.notifikasjon.infrastruktur.produsenter.ProdusentRegister @@ -109,8 +106,8 @@ fun Application.graphqlSetup( withContext(this.coroutineContext + graphQLDispatcher) { val context = extractContext() val request = call.receive() - val result = graphql.await().execute(request, context) - call.respond(result) + val result = graphql.await().timedExecute(request, context) + call.respond(result.toSpecification()) } } } @@ -166,6 +163,10 @@ fun Application.baseSetup( replyToHeader(HttpHeaders.XCorrelationId) } + install(Authentication) { + configureProviders(authProviders) + } + install(CallLogging) { disableDefaultColors() level = Level.INFO @@ -224,10 +225,6 @@ fun Application.baseSetup( register(ContentType.Application.Json, TimedContentConverter(JacksonConverter(laxObjectMapper))) } - install(Authentication) { - configureProviders(authProviders) - } - routing { trace { application.log.trace(it.buildText()) }