sync from project

This commit is contained in:
2025-06-18 10:12:19 +08:00
parent 61ffeeb3b8
commit fb579e8689
20 changed files with 1332 additions and 103 deletions

View File

@ -75,6 +75,10 @@ func (log Log) WrapHandler(next http.Handler) http.Handler {
})
}
// Logger retrieves the slog.Logger from the request context.
// If the logger is not found in the context (e.g., the httplog middleware is not used),
// it creates and returns a new logger with basic request information.
// Using the httplog middleware is recommended to ensure the configured logger is available.
func Logger(r *http.Request) *slog.Logger {
if logger, ok := r.Context().Value(loggerKey).(*slog.Logger); ok {
return logger.With("time", time.Now())

View File

@ -0,0 +1,85 @@
package httplog
import (
"bufio"
"bytes"
"log/slog"
"net"
"net/http"
"net/http/httptest"
"testing"
)
type mockHijacker struct {
*httptest.ResponseRecorder
hijacked bool
}
func (m *mockHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
m.hijacked = true
// Return dummy values, not used in this test
return nil, nil, nil
}
func TestResponseRecorder_Hijack(t *testing.T) {
recorder := &responseRecorder{
ResponseWriter: &mockHijacker{ResponseRecorder: httptest.NewRecorder()},
}
_, _, err := recorder.Hijack()
if err != nil {
t.Fatalf("Hijack failed: %v", err)
}
if recorder.ResponseWriter != nil {
t.Error("ResponseWriter should be nil after Hijack")
}
}
func TestLogger(t *testing.T) {
var buf bytes.Buffer
slog.SetDefault(slog.New(slog.NewTextHandler(&buf, nil)))
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
logger := Logger(r)
logger.Info("test message")
w.WriteHeader(http.StatusOK)
})
t.Run("with middleware", func(t *testing.T) {
buf.Reset()
logMiddleware := Log{LogStart: true, LogFinish: true}
wrappedHandler := logMiddleware.WrapHandler(handler)
req := httptest.NewRequest("GET", "/test", nil)
rr := httptest.NewRecorder()
wrappedHandler.ServeHTTP(rr, req)
if !bytes.Contains(buf.Bytes(), []byte("level=INFO msg=request")) {
t.Error("expected start log message, but not found")
}
if !bytes.Contains(buf.Bytes(), []byte("level=INFO msg=\"test message\"")) {
t.Error("expected handler log message, but not found")
}
if !bytes.Contains(buf.Bytes(), []byte("level=INFO msg=response")) {
t.Error("expected finish log message, but not found")
}
})
t.Run("without middleware", func(t *testing.T) {
buf.Reset()
req := httptest.NewRequest("GET", "/test", nil)
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
if !bytes.Contains(buf.Bytes(), []byte("level=INFO msg=\"test message\"")) {
t.Error("expected handler log message, but not found")
}
if bytes.Contains(buf.Bytes(), []byte("level=INFO msg=request")) {
t.Error("unexpected start log message found")
}
if bytes.Contains(buf.Bytes(), []byte("level=INFO msg=response")) {
t.Error("unexpected finish log message found")
}
})
}