diff --git a/graphql.go b/graphql.go index 39d23a56b..29b60bd00 100644 --- a/graphql.go +++ b/graphql.go @@ -223,8 +223,8 @@ func (s *Schema) exec(ctx context.Context, queryString string, operationName str varTypes[v.Name.Name] = introspection.WrapType(t) } traceCtx, finish := s.tracer.TraceQuery(ctx, queryString, operationName, variables, varTypes) - queryInfo := fmt.Sprintf("Query: %s\nVariables: %+v\n\n", queryString, variables) - data, errs := r.Execute(traceCtx, res, op, queryInfo) + r.QInfo = fmt.Sprintf("Query: %s\nVariables: %+v\n", queryString, variables) + data, errs := r.Execute(traceCtx, res, op) finish(errs) return &Response{ diff --git a/internal/exec/exec.go b/internal/exec/exec.go index 641b25daa..9820c5502 100644 --- a/internal/exec/exec.go +++ b/internal/exec/exec.go @@ -24,12 +24,13 @@ type Request struct { Limiter chan struct{} Tracer trace.Tracer Logger log.Logger + QInfo string } -func (r *Request) handlePanic(ctx context.Context, queryString string) { +func (r *Request) handlePanic(ctx context.Context) { if value := recover(); value != nil { - r.Logger.LogPanic(ctx, value) - r.AddError(makePanicError(value, queryString)) + r.Logger.LogPanic(ctx, value, r.QInfo) + r.AddError(makePanicError(value)) } } @@ -37,14 +38,14 @@ type extensionser interface { Extensions() map[string]interface{} } -func makePanicError(value interface{}, info string) *errors.QueryError { - return errors.Errorf("graphql: panic occurred: %v\n%s\n\n", value, info) +func makePanicError(value interface{}) *errors.QueryError { + return errors.Errorf("graphql: panic occurred: %v", value) } -func (r *Request) Execute(ctx context.Context, s *resolvable.Schema, op *query.Operation, queryInfo string) ([]byte, []*errors.QueryError) { +func (r *Request) Execute(ctx context.Context, s *resolvable.Schema, op *query.Operation) ([]byte, []*errors.QueryError) { var out bytes.Buffer func() { - defer r.handlePanic(ctx, queryInfo) + defer r.handlePanic(ctx) sels := selected.ApplyOperation(&r.Request, s, op) r.execSelections(ctx, sels, nil, s, s.Resolver, &out, op.Type == query.Mutation) }() @@ -79,7 +80,7 @@ func (r *Request) execSelections(ctx context.Context, sels []selected.Selection, for _, f := range fields { go func(f *fieldToExec) { defer wg.Done() - defer r.handlePanic(ctx, "") + defer r.handlePanic(ctx) f.out = new(bytes.Buffer) execFieldSelection(ctx, r, s, f, &pathSegment{path, f.field.Alias}, true) }(f) @@ -177,8 +178,8 @@ func execFieldSelection(ctx context.Context, r *Request, s *resolvable.Schema, f err = func() (err *errors.QueryError) { defer func() { if panicValue := recover(); panicValue != nil { - r.Logger.LogPanic(ctx, panicValue) - err = makePanicError(panicValue, "") + r.Logger.LogPanic(ctx, panicValue, r.QInfo) + err = makePanicError(panicValue) err.Path = path.toSlice() } }() @@ -324,7 +325,7 @@ func (r *Request) execList(ctx context.Context, sels []selected.Selection, typ * for i := 0; i < l; i++ { go func(i int) { defer wg.Done() - defer r.handlePanic(ctx, "") + defer r.handlePanic(ctx) r.execSelectionSet(ctx, sels, typ.OfType, &pathSegment{path, i}, s, resolver.Index(i), &entryouts[i]) }(i) } diff --git a/internal/exec/subscribe.go b/internal/exec/subscribe.go index f1e3e3303..10d8aede0 100644 --- a/internal/exec/subscribe.go +++ b/internal/exec/subscribe.go @@ -25,7 +25,7 @@ func (r *Request) Subscribe(ctx context.Context, s *resolvable.Schema, op *query var f *fieldToExec var err *errors.QueryError func() { - defer r.handlePanic(ctx, "") + defer r.handlePanic(ctx) sels := selected.ApplyOperation(&r.Request, s, op) var fields []*fieldToExec @@ -117,7 +117,7 @@ func (r *Request) Subscribe(ctx context.Context, s *resolvable.Schema, op *query // resolve response func() { - defer subR.handlePanic(subCtx, "") + defer subR.handlePanic(subCtx) var buf bytes.Buffer subR.execSelectionSet(subCtx, f.sels, f.field.Type, &pathSegment{nil, f.field.Alias}, s, resp, &buf) diff --git a/log/log.go b/log/log.go index 25569af7c..581697ea1 100644 --- a/log/log.go +++ b/log/log.go @@ -8,16 +8,16 @@ import ( // Logger is the interface used to log panics that occur during query execution. It is settable via graphql.ParseSchema type Logger interface { - LogPanic(ctx context.Context, value interface{}) + LogPanic(ctx context.Context, value interface{}, info string) } // DefaultLogger is the default logger used to log panics that occur during query execution type DefaultLogger struct{} // LogPanic is used to log recovered panic values that occur during query execution -func (l *DefaultLogger) LogPanic(_ context.Context, value interface{}) { +func (l *DefaultLogger) LogPanic(_ context.Context, value interface{}, info string) { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] - log.Printf("graphql: panic occurred: %v\n%s", value, buf) + log.Printf("graphql: panic occurred: %v\n%s\n\n%s", value, buf, info) } diff --git a/subscriptions.go b/subscriptions.go index 9a62195fd..bf7733430 100644 --- a/subscriptions.go +++ b/subscriptions.go @@ -65,7 +65,7 @@ func (s *Schema) subscribe(ctx context.Context, queryString string, operationNam } if op.Type == query.Query || op.Type == query.Mutation { - data, errs := r.Execute(ctx, res, op, "") + data, errs := r.Execute(ctx, res, op) return sendAndReturnClosed(&Response{Data: data, Errors: errs}) }