Skip to content

Instantly share code, notes, and snippets.

@OlegIlyenko
Last active May 15, 2018 20:35
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OlegIlyenko/124b55e58609ad45fcec276f15158d16 to your computer and use it in GitHub Desktop.
Save OlegIlyenko/124b55e58609ad45fcec276f15158d16 to your computer and use it in GitHub Desktop.
An example of the apollo tracing GraphQL extension with Sangria
import java.time.Instant
import java.time.format.DateTimeFormatter
import java.util.concurrent.ConcurrentLinkedQueue
import sangria.ast._
import sangria.execution._
import sangria.schema.Context
import sangria.marshalling.queryAst._
import sangria.renderer.SchemaRenderer
import scala.collection.JavaConverters._
object ApolloTracingExtension 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])
}
Executor.execute(schema, query, middleware = ApolloTracingExtension :: Nil)
{
human(id: "1000") {
name
friends {
name
}
}
}
{
"data": {
"human": {
"name": "Luke Skywalker",
"friends": [
{
"name": "Han Solo"
},
{
"name": "Leia Organa"
},
{
"name": "C-3PO"
},
{
"name": "R2-D2"
}
]
}
},
"extensions": {
"tracing": {
"version": 1,
"startTime": "2017-07-31T14:32:42.844Z",
"endTime": "2017-07-31T14:32:43.100Z",
"duration": 255216221,
"execution": {
"resolvers": [
{
"path": [
"human"
],
"fieldName": "human",
"parentType": "Query",
"returnType": "Human",
"startOffset": 311002,
"duration": 1968408
},
{
"path": [
"human",
"name"
],
"fieldName": "name",
"parentType": "Human",
"returnType": "String",
"startOffset": 2388537,
"duration": 151844
},
{
"path": [
"human",
"friends"
],
"fieldName": "friends",
"parentType": "Human",
"returnType": "[Character!]!",
"startOffset": 2657994,
"duration": 249770918
},
{
"path": [
"human",
"friends",
0,
"name"
],
"fieldName": "name",
"parentType": "Human",
"returnType": "String",
"startOffset": 253261565,
"duration": 21650
},
{
"path": [
"human",
"friends",
1,
"name"
],
"fieldName": "name",
"parentType": "Human",
"returnType": "String",
"startOffset": 253377422,
"duration": 9363
},
{
"path": [
"human",
"friends",
2,
"name"
],
"fieldName": "name",
"parentType": "Droid",
"returnType": "String",
"startOffset": 253456124,
"duration": 545641
},
{
"path": [
"human",
"friends",
3,
"name"
],
"fieldName": "name",
"parentType": "Droid",
"returnType": "String",
"startOffset": 253599190,
"duration": 420130
}
]
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment