Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Replaced Macaron logger with custom logger enabling query statistics #1634

Merged
merged 8 commits into from
Feb 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ func (s *Server) BindPrioritySetter(p PrioritySetter) {
func NewServer() (*Server, error) {

m := macaron.New()
m.Use(macaron.Logger())
m.Use(macaron.Recovery())
// route pprof to where it belongs, except for our own extensions
m.Use(func(ctx *macaron.Context) {
Expand Down
2 changes: 2 additions & 0 deletions api/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/grafana/globalconf"
"github.com/grafana/metrictank/api/middleware"
"github.com/grafana/metrictank/expr"
log "github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -53,6 +54,7 @@ func ConfigSetup() {
apiCfg.Float64Var(&speculationThreshold, "speculation-threshold", 1, "ratio of peer responses after which speculation is used. Set to 1 to disable.")
apiCfg.BoolVar(&optimizations.PreNormalization, "pre-normalization", true, "enable pre-normalization optimization")
apiCfg.BoolVar(&optimizations.MDP, "mdp-optimization", false, "enable MaxDataPoints optimization (experimental)")
apiCfg.BoolVar(&middleware.LogHeaders, "log-headers", false, "output query headers in logs")
globalconf.Register("http", apiCfg, flag.ExitOnError)
}

Expand Down
123 changes: 123 additions & 0 deletions api/middleware/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package middleware

import (
"bytes"
"context"
"fmt"
"net/http"
"net/url"
"strings"
"time"

opentracing "github.com/opentracing/opentracing-go"
log "github.com/sirupsen/logrus"
jaeger "github.com/uber/jaeger-client-go"
macaron "gopkg.in/macaron.v1"
)

var (
LogHeaders = false
)

type LoggingResponseWriter struct {
macaron.ResponseWriter
errBody []byte // the body in case it is an error
}

func (rw *LoggingResponseWriter) Write(b []byte) (int, error) {
if rw.ResponseWriter.Status() >= 400 {
rw.errBody = make([]byte, len(b))
copy(rw.errBody, b)
}
return rw.ResponseWriter.Write(b)
}

func Logger() macaron.Handler {
return func(ctx *Context) {
start := time.Now()
rw := &LoggingResponseWriter{
ResponseWriter: ctx.Resp,
}
ctx.Resp = rw
ctx.MapTo(ctx.Resp, (*http.ResponseWriter)(nil))
ctx.Next()

// Only log:
// - requests that resulted in errors
// - requests on /render path
if rw.Status() >= 200 && rw.Status() < 300 && !strings.HasPrefix(ctx.Req.URL.Path, "/render") {
return
}

var content strings.Builder
fmt.Fprintf(&content, "ts=%s", time.Now().Format(time.RFC3339Nano))

traceID, _ := extractTraceID(ctx.Req.Context())
if traceID != "" {
fmt.Fprintf(&content, " traceID=%s", traceID)
}

err := ctx.Req.ParseForm()
if err != nil {
log.Errorf("Could not parse http request: %v", err)
}
paramsAsString := ""
if len(ctx.Req.Form) > 0 {
paramsAsString += "?"
paramsAsString += ctx.Req.Form.Encode()
}
fmt.Fprintf(&content, " msg=\"%s %s%s (%v) %v\" orgID=%d", ctx.Req.Method, ctx.Req.URL.Path, paramsAsString, rw.Status(), time.Since(start), ctx.OrgId)

referer := ctx.Req.Referer()
if referer != "" {
fmt.Fprintf(&content, " referer=%s", referer)
}
sourceIP := ctx.RemoteAddr()
if sourceIP != "" {
fmt.Fprintf(&content, " sourceIP=\"%s\"", sourceIP)
}

if rw.Status() < 200 || rw.Status() >= 300 {
errorMsg := url.PathEscape(string(rw.errBody))
fmt.Fprintf(&content, " error=\"%s\"", errorMsg)
}

if LogHeaders {
headers, err := extractHeaders(ctx.Req.Request)
if err != nil {
log.Errorf("Could not extract request headers: %v", err)
}
fmt.Fprintf(&content, " headers=\"%s\"", string(headers))
}

log.Println(content.String())
}
}

func extractHeaders(req *http.Request) (string, error) {
var b bytes.Buffer

// Exclude some headers for security, or just that we don't need them when debugging
err := req.Header.WriteSubset(&b, map[string]bool{
"Cookie": true,
"X-Csrf-Token": true,
"Authorization": true,
})
if err != nil {
return "", err
}
return url.PathEscape(string(b.Bytes())), nil
}

func extractTraceID(ctx context.Context) (string, bool) {
sp := opentracing.SpanFromContext(ctx)
if sp == nil {
return "", false
}
sctx, ok := sp.Context().(jaeger.SpanContext)
if !ok {
return "", false
}

return sctx.TraceID().String(), true
}
1 change: 1 addition & 0 deletions api/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func (s *Server) RegisterRoutes() {
r.Use(middleware.Tracer(s.Tracer))
r.Use(macaron.Renderer())
r.Use(middleware.OrgMiddleware(multiTenant))
r.Use(middleware.Logger())
r.Use(middleware.CorsHandler())
bind := binding.Bind
withOrg := middleware.RequireOrg()
Expand Down
2 changes: 2 additions & 0 deletions docker/docker-chaos/metrictank.ini
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down
2 changes: 2 additions & 0 deletions docker/docker-cluster-query/metrictank.ini
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down
2 changes: 2 additions & 0 deletions docker/docker-cluster/metrictank.ini
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down
2 changes: 2 additions & 0 deletions docker/docker-dev-custom-cfg-kafka/metrictank.ini
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down
2 changes: 2 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false
```

## metric data inputs ##
Expand Down
2 changes: 2 additions & 0 deletions metrictank-sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down
2 changes: 2 additions & 0 deletions scripts/config/metrictank-docker.ini
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down
2 changes: 2 additions & 0 deletions scripts/config/metrictank-package.ini
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ speculation-threshold = 1
pre-normalization = true
# enable MaxDataPoints optimization (experimental)
mdp-optimization = false
# output query headers in logs
log-headers = false

## metric data inputs ##

Expand Down