Skip to content
Snippets Groups Projects
log.go 1.42 KiB
Newer Older
gbe's avatar
gbe committed
package log

import (
	"context"
	"net/http"
	"time"

	"github.com/kjk/betterguid"
	"github.com/sirupsen/logrus"
)

type contextKey string

// Request wraps the given HTTP handler with a log entry that logs how long it has been running. It also
// makes a preconfigured logger for the request available as part of the request context.
func Request(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		remote := r.Header.Get("X-Forwarded-For")
		if remote == "" {
			remote = r.RemoteAddr
		}

		log := logrus.WithFields(logrus.Fields{
			"method": r.Method,
			"url":    r.URL,
			"remote": remote,
			"id":     betterguid.New(),
		})

		start := time.Now()
		defer func() {
			d := time.Since(start)

			log.WithField("duration", d).Info("request handled")
		}()

		key := contextKey("logger")
		ctx := context.WithValue(r.Context(), key, log)

		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// Get returns the logger for the given HTTP request. If r has no logger, a usable logger without fields is returned.
func Get(r *http.Request) *logrus.Entry {
	return GetContext(r.Context())
}

// GetContext returns the logger for the given context. If ctx has no logger, a usable logger without fields is returned.
func GetContext(ctx context.Context) *logrus.Entry {
	val := ctx.Value(contextKey("logger"))
	if val == nil {
		return logrus.NewEntry(logrus.New())
	}

	return val.(*logrus.Entry)

}