Skip to content

Commit

Permalink
add basic metrics and tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcel Ludwig committed Aug 30, 2021
1 parent f598b5b commit 8a9defa
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 17 deletions.
23 changes: 10 additions & 13 deletions server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import (
"time"

"github.com/sirupsen/logrus"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"

ac "github.com/avenga/couper/accesscontrol"
"github.com/avenga/couper/config"
Expand All @@ -21,6 +22,7 @@ import (
"github.com/avenga/couper/handler"
"github.com/avenga/couper/logging"
"github.com/avenga/couper/server/writer"
"github.com/avenga/couper/telemetry"
)

type muxers map[string]*Mux
Expand All @@ -38,7 +40,6 @@ type HTTPServer struct {
shutdownCh chan struct{}
srv *http.Server
timings *runtime.HTTPTimings
tracer trace.Tracer
uidFn uidFunc
}

Expand Down Expand Up @@ -90,13 +91,12 @@ func New(cmdCtx, evalCtx context.Context, log logrus.FieldLogger, settings *conf
settings: settings,
shutdownCh: shutdownCh,
timings: timings,
tracer: otel.Tracer("couper/server"),
uidFn: uidFn,
}

srv := &http.Server{
Addr: ":" + p.String(),
Handler: httpSrv,
Handler: telemetry.NewTraceHandler("couper")(httpSrv),
IdleTimeout: timings.IdleTimeout,
ReadHeaderTimeout: timings.ReadHeaderTimeout,
}
Expand Down Expand Up @@ -172,10 +172,12 @@ func (s *HTTPServer) listenForCtx() {

func (s *HTTPServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
startTime := time.Now()
ctx, span := s.tracer.Start(req.Context(), "serve")
defer span.End()

ctx = context.WithValue(ctx, request.XFF, req.Header.Get("X-Forwarded-For"))
meter := global.Meter("couper/server")
counter := metric.Must(meter).NewInt64Counter("request")
meter.RecordBatch(req.Context(), []attribute.KeyValue{}, counter.Measurement(1))

ctx := context.WithValue(req.Context(), request.XFF, req.Header.Get("X-Forwarded-For"))
ctx = context.WithValue(ctx, request.LogEntry, s.log)
*req = *req.WithContext(ctx)

Expand Down Expand Up @@ -255,11 +257,6 @@ func (s *HTTPServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
}

func (s *HTTPServer) setGetBody(h http.Handler, req *http.Request) error {
ctx, span := s.tracer.Start(req.Context(), "serve/readBody")
defer span.End()

*req = *req.WithContext(ctx)

outer := h
if inner, protected := outer.(ac.ProtectedHandler); protected {
outer = inner.Child()
Expand Down
10 changes: 6 additions & 4 deletions telemetry/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"go.opentelemetry.io/otel/sdk/export/metric"

"github.com/avenga/couper/logging"
"github.com/avenga/couper/server/writer"
)

type Metrics struct {
Expand Down Expand Up @@ -57,11 +56,14 @@ func NewMetrics(opts *Options, log *logrus.Entry) (*Metrics, error) {
func (m *Metrics) ListenAndServe() {
accessLog := logging.NewAccessLog(nil, m.log)
serveHTTP := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
r := writer.NewResponseWriter(rw, "")
accessLog.ServeHTTP(r, req, m.promExporter, time.Now())
//r := writer.NewResponseWriter(rw, "")
accessLog.ServeHTTP(rw, req, m.promExporter, time.Now())
})
m.log.Info("couper is serving metrics: :9090")
m.server = &http.Server{Addr: ":9090", Handler: serveHTTP}
m.server = &http.Server{
Addr: ":9090",
Handler: serveHTTP,
}
err := m.server.ListenAndServe()
if err != nil {
m.log.WithError(err).Error()
Expand Down
82 changes: 82 additions & 0 deletions telemetry/tracer.go
Original file line number Diff line number Diff line change
@@ -1 +1,83 @@
package telemetry

import (
"log"
"net/http"

"github.com/avenga/couper/logging"

"go.opentelemetry.io/otel"
stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"

"github.com/avenga/couper/utils"
)

func init() {
initTracer()
}

var tracerName = "github.com/avenga/couper/telemetry"

type TraceHandler struct {
propagators propagation.TextMapPropagator
service string
tracer trace.Tracer
handler http.Handler
}

func NewTraceHandler(service string) func(http.Handler) http.Handler {
traceProvider := otel.GetTracerProvider()
tracer := traceProvider.Tracer(
tracerName,
trace.WithInstrumentationVersion(utils.VersionName),
)
propagators := otel.GetTextMapPropagator()

return func(handler http.Handler) http.Handler {
return &TraceHandler{
propagators: propagators,
service: service,
tracer: tracer,
handler: handler,
}
}
}

func (th *TraceHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
spanName := req.URL.EscapedPath()
opts := []trace.SpanStartOption{
trace.WithAttributes(semconv.NetAttributesFromHTTPRequest("tcp", req)...),
trace.WithAttributes(semconv.EndUserAttributesFromHTTPRequest(req)...),
trace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest(th.service, spanName, req)...),
trace.WithSpanKind(trace.SpanKindServer),
}
ctx, span := th.tracer.Start(req.Context(), spanName, opts...)
defer span.End()

if rsw, ok := rw.(logging.RecorderInfo); ok {
attrs := semconv.HTTPAttributesFromHTTPStatusCode(rsw.StatusCode())
spanStatus, spanMessage := semconv.SpanStatusFromHTTPStatusCode(rsw.StatusCode())
span.SetAttributes(attrs...)
span.SetStatus(spanStatus, spanMessage)
}

th.handler.ServeHTTP(rw, req.WithContext(ctx))
}

func initTracer() *sdktrace.TracerProvider {
exporter, err := stdout.New(stdout.WithPrettyPrint())
if err != nil {
log.Fatal(err)
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
return tp
}

0 comments on commit 8a9defa

Please sign in to comment.