trace.go 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package trace
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/graph-gophers/graphql-go/errors"
  6. "github.com/graph-gophers/graphql-go/introspection"
  7. opentracing "github.com/opentracing/opentracing-go"
  8. "github.com/opentracing/opentracing-go/ext"
  9. "github.com/opentracing/opentracing-go/log"
  10. )
  11. type TraceQueryFinishFunc func([]*errors.QueryError)
  12. type TraceFieldFinishFunc func(*errors.QueryError)
  13. type Tracer interface {
  14. TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, TraceQueryFinishFunc)
  15. TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, TraceFieldFinishFunc)
  16. }
  17. type OpenTracingTracer struct{}
  18. func (OpenTracingTracer) TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, TraceQueryFinishFunc) {
  19. span, spanCtx := opentracing.StartSpanFromContext(ctx, "GraphQL request")
  20. span.SetTag("graphql.query", queryString)
  21. if operationName != "" {
  22. span.SetTag("graphql.operationName", operationName)
  23. }
  24. if len(variables) != 0 {
  25. span.LogFields(log.Object("graphql.variables", variables))
  26. }
  27. return spanCtx, func(errs []*errors.QueryError) {
  28. if len(errs) > 0 {
  29. msg := errs[0].Error()
  30. if len(errs) > 1 {
  31. msg += fmt.Sprintf(" (and %d more errors)", len(errs)-1)
  32. }
  33. ext.Error.Set(span, true)
  34. span.SetTag("graphql.error", msg)
  35. }
  36. span.Finish()
  37. }
  38. }
  39. func (OpenTracingTracer) TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, TraceFieldFinishFunc) {
  40. if trivial {
  41. return ctx, noop
  42. }
  43. span, spanCtx := opentracing.StartSpanFromContext(ctx, label)
  44. span.SetTag("graphql.type", typeName)
  45. span.SetTag("graphql.field", fieldName)
  46. for name, value := range args {
  47. span.SetTag("graphql.args."+name, value)
  48. }
  49. return spanCtx, func(err *errors.QueryError) {
  50. if err != nil {
  51. ext.Error.Set(span, true)
  52. span.SetTag("graphql.error", err.Error())
  53. }
  54. span.Finish()
  55. }
  56. }
  57. func noop(*errors.QueryError) {}
  58. type NoopTracer struct{}
  59. func (NoopTracer) TraceQuery(ctx context.Context, queryString string, operationName string, variables map[string]interface{}, varTypes map[string]*introspection.Type) (context.Context, TraceQueryFinishFunc) {
  60. return ctx, func(errs []*errors.QueryError) {}
  61. }
  62. func (NoopTracer) TraceField(ctx context.Context, label, typeName, fieldName string, trivial bool, args map[string]interface{}) (context.Context, TraceFieldFinishFunc) {
  63. return ctx, func(err *errors.QueryError) {}
  64. }