Skip to content

Instantly share code, notes, and snippets.

@schleumer
Created March 5, 2020 01:02
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save schleumer/b6340b3c3c997ddff427689e3177eaa3 to your computer and use it in GitHub Desktop.
Tracing.scala
import java.time.Instant
import java.time.format.DateTimeFormatter
import java.util.concurrent.ConcurrentLinkedQueue
import sangria.ast._
import sangria.execution._
import sangria.marshalling.queryAst._
import sangria.renderer.SchemaRenderer
import sangria.schema.Context
import scala.jdk.CollectionConverters._
object TracingExtension
extends Middleware[Any] with MiddlewareExtension[Any] with MiddlewareAfterField[Any] with MiddlewareErrorField[Any] {
type QueryVal = QueryTrace
type FieldVal = Long
def beforeQuery(context: MiddlewareQueryContext[Any, _, _]) =
QueryTrace(Instant.now(), System.nanoTime(), new ConcurrentLinkedQueue)
def afterQuery(queryVal: QueryVal, context: MiddlewareQueryContext[Any, _, _]) = ()
def beforeField(queryVal: QueryVal, mctx: MiddlewareQueryContext[Any, _, _], ctx: Context[Any, _]) =
continue(System.nanoTime())
def afterField(
queryVal: QueryVal,
fieldVal: FieldVal,
value: Any,
mctx: MiddlewareQueryContext[Any, _, _],
ctx: Context[Any, _]
) = {
updateMetric(queryVal, fieldVal, ctx)
None
}
def fieldError(
queryVal: QueryVal,
fieldVal: FieldVal,
error: Throwable,
mctx: MiddlewareQueryContext[Any, _, _],
ctx: Context[Any, _]
) =
updateMetric(queryVal, fieldVal, ctx)
def updateMetric(queryVal: QueryVal, fieldVal: FieldVal, ctx: Context[Any, _]): Unit = {
queryVal.fieldData.add(ObjectValue(
"path" -> ListValue(ctx.path.path.map(queryAstResultMarshaller.scalarNode(_, "Any", Set.empty))),
"fieldName" -> StringValue(ctx.field.name),
"parentType" -> StringValue(ctx.parentType.name),
"returnType" -> StringValue(SchemaRenderer.renderTypeName(ctx.field.fieldType)),
"startOffset" -> BigIntValue(fieldVal - queryVal.startNanos),
"duration" -> BigIntValue(System.nanoTime() - fieldVal)))
()
}
def afterQueryExtensions(queryVal: QueryVal, context: MiddlewareQueryContext[Any, _, _]): Vector[Extension[_]] =
Vector(Extension(ObjectValue(
"tracing" -> ObjectValue(
"version" -> IntValue(1),
"startTime" -> StringValue(DateTimeFormatter.ISO_INSTANT.format(queryVal.startTime)),
"endTime" -> StringValue(DateTimeFormatter.ISO_INSTANT.format(Instant.now())),
"duration" -> BigIntValue(System.nanoTime() - queryVal.startNanos),
"execution" -> ObjectValue(
"resolvers" -> ListValue(queryVal.fieldData.asScala.toVector)))): Value))
case class QueryTrace(startTime: Instant, startNanos: Long, fieldData: ConcurrentLinkedQueue[Value])
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment