add access log

master
bel 2022-05-26 20:03:35 -06:00
parent 0eea3e787c
commit 56a74a2767
1 changed files with 49 additions and 1 deletions

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"encoding/base64" "encoding/base64"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -17,9 +18,11 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
"strconv"
"strings" "strings"
"time" "time"
"github.com/google/uuid"
"golang.org/x/time/rate" "golang.org/x/time/rate"
) )
@ -263,16 +266,23 @@ func pipe(a, b net.Conn) {
func (s *Server) Pre(foo http.HandlerFunc) http.HandlerFunc { func (s *Server) Pre(foo http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
r, flush := withMeta(w, r)
defer flush()
ctx, can := context.WithTimeout(r.Context(), time.Duration(config.GetTimeout())) ctx, can := context.WithTimeout(r.Context(), time.Duration(config.GetTimeout()))
defer can() defer can()
if err := s.limiter.Wait(ctx); err != nil { if err := s.limiter.Wait(ctx); err != nil {
pushMeta(r, "explain", "limiter exceeded")
w.WriteHeader(http.StatusTooManyRequests) w.WriteHeader(http.StatusTooManyRequests)
return return
} }
w, did := doCORS(w, r) w, did := doCORS(w, r)
if did { if did {
pushMeta(r, "explain", "did cors")
return return
} }
if s.auth.BOAuthZ { if s.auth.BOAuthZ {
logb.Verbosef("doing boauthz for request to %s", r.URL.String()) logb.Verbosef("doing boauthz for request to %s", r.URL.String())
s.doBOAuthZ(foo)(w, r) s.doBOAuthZ(foo)(w, r)
@ -285,11 +295,44 @@ func (s *Server) Pre(foo http.HandlerFunc) http.HandlerFunc {
} }
} }
func withMeta(w http.ResponseWriter, r *http.Request) (*http.Request, func()) {
meta := map[string]string{
"ts": strconv.FormatInt(time.Now().Unix(), 10),
"method": r.Method,
"url": r.URL.String(),
"id": uuid.New().String(),
}
w.Header().Set("meta-id", meta["id"])
ctx := r.Context()
ctx = context.WithValue(ctx, "meta", meta)
r = r.WithContext(ctx)
return r, func() {
b, err := json.Marshal(meta)
if err != nil {
panic(err)
}
log.Printf("[access] %s", b)
}
}
func pushMeta(r *http.Request, k, v string) {
got := r.Context().Value("meta")
if got == nil {
return
}
meta, ok := got.(map[string]string)
if !ok || meta == nil {
return
}
meta[k] = v
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.Pre(s.Proxy)(w, r) s.Pre(s.Proxy)(w, r)
} }
type corsResponseWriter struct { type corsResponseWriter struct {
r *http.Request
http.ResponseWriter http.ResponseWriter
} }
@ -297,21 +340,26 @@ func (cb corsResponseWriter) WriteHeader(code int) {
cb.Header().Set("Access-Control-Allow-Origin", "*") cb.Header().Set("Access-Control-Allow-Origin", "*")
cb.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token, content-type, Content-Type") cb.Header().Set("Access-Control-Allow-Headers", "X-Auth-Token, content-type, Content-Type")
cb.ResponseWriter.WriteHeader(code) cb.ResponseWriter.WriteHeader(code)
pushMeta(cb.r, "cors", "wrote headers")
} }
func doCORS(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, bool) { func doCORS(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, bool) {
key := mapKey(r.Host) key := mapKey(r.Host)
if !config.GetCORS(key) { if !config.GetCORS(key) {
pushMeta(r, "do-cors", "not enabled for key")
return w, false return w, false
} }
pushMeta(r, "do-cors", "enabled for key")
return _doCORS(w, r) return _doCORS(w, r)
} }
func _doCORS(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, bool) { func _doCORS(w http.ResponseWriter, r *http.Request) (http.ResponseWriter, bool) {
w2 := corsResponseWriter{ResponseWriter: w} w2 := corsResponseWriter{r: r, ResponseWriter: w}
if r.Method != http.MethodOptions { if r.Method != http.MethodOptions {
pushMeta(r, "-do-cors", "not options")
return w2, false return w2, false
} }
pushMeta(r, "-do-cors", "options")
w2.Header().Set("Content-Length", "0") w2.Header().Set("Content-Length", "0")
w2.Header().Set("Content-Type", "text/plain") w2.Header().Set("Content-Type", "text/plain")
w2.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE") w2.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS, TRACE, PATCH, HEAD, DELETE")