feat: log 404 requests with traceid (#1554)
This commit is contained in:
@@ -1,15 +1,14 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||
"github.com/zeromicro/go-zero/rest/token"
|
||||
)
|
||||
|
||||
@@ -105,7 +104,7 @@ func detailAuthLog(r *http.Request, reason string) {
|
||||
}
|
||||
|
||||
func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback UnauthorizedCallback) {
|
||||
writer := newGuardedResponseWriter(w)
|
||||
writer := response.NewHeaderOnceResponseWriter(w)
|
||||
|
||||
if err != nil {
|
||||
detailAuthLog(r, err.Error())
|
||||
@@ -121,47 +120,3 @@ func unauthorized(w http.ResponseWriter, r *http.Request, err error, callback Un
|
||||
// if user not setting HTTP header, we set header with 401
|
||||
writer.WriteHeader(http.StatusUnauthorized)
|
||||
}
|
||||
|
||||
type guardedResponseWriter struct {
|
||||
writer http.ResponseWriter
|
||||
wroteHeader bool
|
||||
}
|
||||
|
||||
func newGuardedResponseWriter(w http.ResponseWriter) *guardedResponseWriter {
|
||||
return &guardedResponseWriter{
|
||||
writer: w,
|
||||
}
|
||||
}
|
||||
|
||||
func (grw *guardedResponseWriter) Flush() {
|
||||
if flusher, ok := grw.writer.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
}
|
||||
|
||||
func (grw *guardedResponseWriter) Header() http.Header {
|
||||
return grw.writer.Header()
|
||||
}
|
||||
|
||||
// Hijack implements the http.Hijacker interface.
|
||||
// This expands the Response to fulfill http.Hijacker if the underlying http.ResponseWriter supports it.
|
||||
func (grw *guardedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
if hijacked, ok := grw.writer.(http.Hijacker); ok {
|
||||
return hijacked.Hijack()
|
||||
}
|
||||
|
||||
return nil, nil, errors.New("server doesn't support hijacking")
|
||||
}
|
||||
|
||||
func (grw *guardedResponseWriter) Write(body []byte) (int, error) {
|
||||
return grw.writer.Write(body)
|
||||
}
|
||||
|
||||
func (grw *guardedResponseWriter) WriteHeader(statusCode int) {
|
||||
if grw.wroteHeader {
|
||||
return
|
||||
}
|
||||
|
||||
grw.wroteHeader = true
|
||||
grw.writer.WriteHeader(statusCode)
|
||||
}
|
||||
|
||||
@@ -90,26 +90,6 @@ func TestAuthHandler_NilError(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthHandler_Flush(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
handler := newGuardedResponseWriter(resp)
|
||||
handler.Flush()
|
||||
assert.True(t, resp.Flushed)
|
||||
}
|
||||
|
||||
func TestAuthHandler_Hijack(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
writer := newGuardedResponseWriter(resp)
|
||||
assert.NotPanics(t, func() {
|
||||
writer.Hijack()
|
||||
})
|
||||
|
||||
writer = newGuardedResponseWriter(mockedHijackable{resp})
|
||||
assert.NotPanics(t, func() {
|
||||
writer.Hijack()
|
||||
})
|
||||
}
|
||||
|
||||
func buildToken(secretKey string, payloads map[string]interface{}, seconds int64) (string, error) {
|
||||
now := time.Now().Unix()
|
||||
claims := make(jwt.MapClaims)
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stat"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/internal/security"
|
||||
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||
)
|
||||
|
||||
const breakerSeparator = "://"
|
||||
@@ -28,7 +28,7 @@ func BreakerHandler(method, path string, metrics *stat.Metrics) func(http.Handle
|
||||
return
|
||||
}
|
||||
|
||||
cw := &security.WithCodeResponseWriter{Writer: w}
|
||||
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||
defer func() {
|
||||
if cw.Code < http.StatusInternalServerError {
|
||||
promise.Accept()
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/metric"
|
||||
"github.com/zeromicro/go-zero/core/prometheus"
|
||||
"github.com/zeromicro/go-zero/core/timex"
|
||||
"github.com/zeromicro/go-zero/rest/internal/security"
|
||||
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||
)
|
||||
|
||||
const serverNamespace = "http_server"
|
||||
@@ -41,7 +41,7 @@ func PrometheusHandler(path string) func(http.Handler) http.Handler {
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
startTime := timex.Now()
|
||||
cw := &security.WithCodeResponseWriter{Writer: w}
|
||||
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||
defer func() {
|
||||
metricServerReqDur.Observe(int64(timex.Since(startTime)/time.Millisecond), path)
|
||||
metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code))
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stat"
|
||||
"github.com/zeromicro/go-zero/rest/httpx"
|
||||
"github.com/zeromicro/go-zero/rest/internal/security"
|
||||
"github.com/zeromicro/go-zero/rest/internal/response"
|
||||
)
|
||||
|
||||
const serviceType = "api"
|
||||
@@ -41,7 +41,7 @@ func SheddingHandler(shedder load.Shedder, metrics *stat.Metrics) func(http.Hand
|
||||
return
|
||||
}
|
||||
|
||||
cw := &security.WithCodeResponseWriter{Writer: w}
|
||||
cw := &response.WithCodeResponseWriter{Writer: w}
|
||||
defer func() {
|
||||
if cw.Code == http.StatusServiceUnavailable {
|
||||
promise.Fail()
|
||||
|
||||
@@ -18,12 +18,16 @@ func TracingHandler(serviceName, path string) func(http.Handler) http.Handler {
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
spanName := path
|
||||
if len(spanName) == 0 {
|
||||
spanName = r.URL.Path
|
||||
}
|
||||
spanCtx, span := tracer.Start(
|
||||
ctx,
|
||||
path,
|
||||
spanName,
|
||||
oteltrace.WithSpanKind(oteltrace.SpanKindServer),
|
||||
oteltrace.WithAttributes(semconv.HTTPServerAttributesFromHTTPRequest(
|
||||
serviceName, path, r)...),
|
||||
serviceName, spanName, r)...),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/justinas/alice"
|
||||
"github.com/stretchr/testify/assert"
|
||||
ztrace "github.com/zeromicro/go-zero/core/trace"
|
||||
"go.opentelemetry.io/otel"
|
||||
@@ -21,28 +22,31 @@ func TestOtelHandler(t *testing.T) {
|
||||
Sampler: 1.0,
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
spanCtx := trace.SpanContextFromContext(ctx)
|
||||
assert.Equal(t, true, spanCtx.IsValid())
|
||||
}),
|
||||
)
|
||||
defer ts.Close()
|
||||
for _, test := range []string{"", "bar"} {
|
||||
t.Run(test, func(t *testing.T) {
|
||||
h := alice.New(TracingHandler("foo", test)).Then(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := otel.GetTextMapPropagator().Extract(r.Context(), propagation.HeaderCarrier(r.Header))
|
||||
spanCtx := trace.SpanContextFromContext(ctx)
|
||||
assert.True(t, spanCtx.IsValid())
|
||||
}))
|
||||
ts := httptest.NewServer(h)
|
||||
defer ts.Close()
|
||||
|
||||
client := ts.Client()
|
||||
err := func(ctx context.Context) error {
|
||||
ctx, span := otel.Tracer("httptrace/client").Start(ctx, "test")
|
||||
defer span.End()
|
||||
client := ts.Client()
|
||||
err := func(ctx context.Context) error {
|
||||
ctx, span := otel.Tracer("httptrace/client").Start(ctx, "test")
|
||||
defer span.End()
|
||||
|
||||
req, _ := http.NewRequest("GET", ts.URL, nil)
|
||||
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
|
||||
req, _ := http.NewRequest("GET", ts.URL, nil)
|
||||
otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
|
||||
|
||||
res, err := client.Do(req)
|
||||
assert.Equal(t, err, nil)
|
||||
_ = res.Body.Close()
|
||||
return nil
|
||||
}(context.Background())
|
||||
res, err := client.Do(req)
|
||||
assert.Nil(t, err)
|
||||
return res.Body.Close()
|
||||
}(context.Background())
|
||||
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user