You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
4.1 KiB
143 lines
4.1 KiB
package instrumentation
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/99designs/gqlgen/graphql"
|
|
prometheusclient "github.com/prometheus/client_golang/prometheus"
|
|
)
|
|
|
|
const (
|
|
existStatusFailure = "failure"
|
|
exitStatusSuccess = "success"
|
|
)
|
|
|
|
var (
|
|
requestStartedCounter prometheusclient.Counter
|
|
requestCompletedCounter prometheusclient.Counter
|
|
resolverStartedCounter *prometheusclient.CounterVec
|
|
resolverCompletedCounter *prometheusclient.CounterVec
|
|
timeToResolveField *prometheusclient.HistogramVec
|
|
timeToHandleRequest *prometheusclient.HistogramVec
|
|
)
|
|
|
|
// Register registers the prometheus metrics.
|
|
func Register() {
|
|
requestStartedCounter = prometheusclient.NewCounter(
|
|
prometheusclient.CounterOpts{
|
|
Name: "graphql_request_started_total",
|
|
Help: "Total number of requests started on the graphql server.",
|
|
},
|
|
)
|
|
|
|
requestCompletedCounter = prometheusclient.NewCounter(
|
|
prometheusclient.CounterOpts{
|
|
Name: "graphql_request_completed_total",
|
|
Help: "Total number of requests completed on the graphql server.",
|
|
},
|
|
)
|
|
|
|
resolverStartedCounter = prometheusclient.NewCounterVec(
|
|
prometheusclient.CounterOpts{
|
|
Name: "graphql_resolver_started_total",
|
|
Help: "Total number of resolver started on the graphql server.",
|
|
},
|
|
[]string{"object", "field"},
|
|
)
|
|
|
|
resolverCompletedCounter = prometheusclient.NewCounterVec(
|
|
prometheusclient.CounterOpts{
|
|
Name: "graphql_resolver_completed_total",
|
|
Help: "Total number of resolver completed on the graphql server.",
|
|
},
|
|
[]string{"object", "field"},
|
|
)
|
|
|
|
timeToResolveField = prometheusclient.NewHistogramVec(prometheusclient.HistogramOpts{
|
|
Name: "graphql_resolver_duration_ms",
|
|
Help: "The time taken to resolve a field by graphql server.",
|
|
Buckets: prometheusclient.ExponentialBuckets(1, 2, 11),
|
|
}, []string{"exitStatus"})
|
|
|
|
timeToHandleRequest = prometheusclient.NewHistogramVec(prometheusclient.HistogramOpts{
|
|
Name: "graphql_request_duration_ms",
|
|
Help: "The time taken to handle a request by graphql server.",
|
|
Buckets: prometheusclient.ExponentialBuckets(1, 2, 11),
|
|
}, []string{"exitStatus"})
|
|
|
|
prometheusclient.MustRegister(
|
|
requestStartedCounter,
|
|
requestCompletedCounter,
|
|
resolverStartedCounter,
|
|
resolverCompletedCounter,
|
|
timeToResolveField,
|
|
timeToHandleRequest,
|
|
)
|
|
}
|
|
|
|
// UnRegister unregisters
|
|
func UnRegister() {
|
|
prometheusclient.Unregister(requestStartedCounter)
|
|
prometheusclient.Unregister(requestCompletedCounter)
|
|
prometheusclient.Unregister(resolverStartedCounter)
|
|
prometheusclient.Unregister(resolverCompletedCounter)
|
|
prometheusclient.Unregister(timeToResolveField)
|
|
prometheusclient.Unregister(timeToHandleRequest)
|
|
}
|
|
|
|
// ResolverMiddleware is a resolver middleware that logs metrics for prometheus.
|
|
func ResolverMiddleware() graphql.FieldMiddleware {
|
|
return func(ctx context.Context, next graphql.Resolver) (interface{}, error) {
|
|
rctx := graphql.GetResolverContext(ctx)
|
|
|
|
resolverStartedCounter.WithLabelValues(rctx.Object, rctx.Field.Name).Inc()
|
|
|
|
observerStart := time.Now()
|
|
|
|
res, err := next(ctx)
|
|
|
|
var exitStatus string
|
|
if err != nil {
|
|
exitStatus = existStatusFailure
|
|
} else {
|
|
exitStatus = exitStatusSuccess
|
|
}
|
|
|
|
timeToResolveField.With(prometheusclient.Labels{"exitStatus": exitStatus}).
|
|
Observe(float64(time.Since(observerStart).Nanoseconds() / int64(time.Millisecond)))
|
|
|
|
resolverCompletedCounter.WithLabelValues(rctx.Object, rctx.Field.Name).Inc()
|
|
|
|
return res, err
|
|
}
|
|
}
|
|
|
|
// RequestMiddleware is a request middleware that logs metrics for prometheus.
|
|
func RequestMiddleware() graphql.RequestMiddleware {
|
|
return func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
|
requestStartedCounter.Inc()
|
|
|
|
observerStart := time.Now()
|
|
|
|
res := next(ctx)
|
|
|
|
rctx := graphql.GetResolverContext(ctx)
|
|
reqCtx := graphql.GetRequestContext(ctx)
|
|
errList := reqCtx.GetErrors(rctx)
|
|
|
|
var exitStatus string
|
|
if len(errList) > 0 {
|
|
exitStatus = existStatusFailure
|
|
} else {
|
|
exitStatus = exitStatusSuccess
|
|
}
|
|
|
|
timeToHandleRequest.With(prometheusclient.Labels{"exitStatus": exitStatus}).
|
|
Observe(float64(time.Since(observerStart).Nanoseconds() / int64(time.Millisecond)))
|
|
|
|
requestCompletedCounter.Inc()
|
|
|
|
return res
|
|
}
|
|
}
|