Skip to content
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
22 changes: 14 additions & 8 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
version: "2"
run:
timeout: 5m
tests: false
#tests: false
linters:
default: all
disable:
- depguard
- gochecknoglobals
- noinlineerr
- nlreturn
- paralleltest
- testpackage
- wsl
- wsl_v5
settings:
errcheck:
exclude-functions:
- io.WriteString
- (net/http.ResponseWriter).Write
exhaustruct:
allow-empty: true
exclude:
- net/http.Server
goconst:
ignore-string-values:
- "default router"
varnamelen:
ignore-decls:
- w http.ResponseWriter
- r *http.Request
errcheck:
exclude-functions:
- io.WriteString
- (net/http.ResponseWriter).Write
- w http.ResponseWriter
- w *httptest.ResponseRecorder
exclusions:
generated: lax
warn-unused: true
presets:
# - comments
# - common-false-positives
- legacy
# - std-error-handling
- std-error-handling
formatters:
enable:
- gofumpt
Expand Down
3 changes: 1 addition & 2 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package main
import (
"io"
"log"
"log/slog"
"net/http"
"net/http/pprof"

Expand All @@ -14,7 +13,7 @@ import (
func main() {
log.SetFlags(log.Lshortfile)

router := mux.NewRouter(slog.Default(), mux.Logger)
router := mux.NewRouter(mux.Logger)
router.NotFound(notFound).NotAllowed(notAllowed)
// router.Use(mux.Logger)
router.Get("/{$}", page)
Expand Down
12 changes: 5 additions & 7 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ import (
"fmt"
"log/slog"
"net/http"
"strings"
"time"
)

var logger *slog.Logger

type statusRecorder struct {
http.ResponseWriter

Expand All @@ -28,20 +25,21 @@ func Logger(next http.Handler) http.Handler {
now := time.Now()
rec := statusRecorder{w, http.StatusOK}
next.ServeHTTP(&rec, r)
remote := strings.Split(r.RemoteAddr, ":")[0]
// remote := strings.Split(r.RemoteAddr, ":")[0]
remote := r.RemoteAddr
if r.Header.Get("X-Forwarded-For") != "" {
remote = r.Header.Get("X-Forwarded-For")
}
details := fmt.Sprintf(
"%s %s %s %s %d %s %s",
"%s %s%s %d %s %s %s",
r.Method,
r.Host,
r.URL.Path,
remote,
rec.status,
remote,
time.Since(now).String(),
r.UserAgent(),
)
logger.Info(details)
slog.Info(details)
})
}
22 changes: 7 additions & 15 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@ type Middleware func(http.Handler) http.Handler
// Router provides a chain of middlewares and routes.
type Router struct {
*http.ServeMux
*slog.Logger

chain http.Handler
methods []string
notFound func(http.ResponseWriter, *http.Request)
notAllowed func(http.ResponseWriter, string, int)
}

// DefaultRouter creates a new Router using the default ServeMux.
func DefaultRouter() *Router {
// defaultRouter creates a new Router using the default ServeMux.
func defaultRouter() *Router {
mux := http.NewServeMux()
router := &Router{
ServeMux: mux,
Logger: slog.New(slog.DiscardHandler),
chain: mux,
methods: []string{},
notFound: http.NotFound,
Expand All @@ -55,7 +53,6 @@ func DefaultRouter() *Router {
if len(allowed) != 0 {
w.Header().Set("Allow", strings.Join(allowed, ", "))
router.notAllowed(w, "Method Not Allowed", http.StatusMethodNotAllowed)
// http.Error(w, "Custom Method Not Allowed", http.StatusMethodNotAllowed)
return
}
// http.Error(w, "Custom Not Found", http.StatusNotFound)
Expand All @@ -65,12 +62,8 @@ func DefaultRouter() *Router {
}

// NewRouter creates a new Router with the given middleware applied.
func NewRouter(l *slog.Logger, middleware ...Middleware) *Router {
router := DefaultRouter()
if l != nil {
router.Logger = l
logger = l
}
func NewRouter(middleware ...Middleware) *Router {
router := defaultRouter()
router.Use(middleware...)
return router
}
Expand All @@ -95,10 +88,9 @@ func (router *Router) Group(prefix string, middlewares ...Middleware) *Router {
}
}

subRouter := DefaultRouter()
subRouter := defaultRouter()
subRouter.notFound = router.notFound
subRouter.notAllowed = router.notAllowed
subRouter.Logger = router.Logger
subRouter.Use(middlewares...)
router.Handle(prefix+"/", http.StripPrefix(prefix, subRouter))
return subRouter
Expand Down Expand Up @@ -203,9 +195,9 @@ func (router *Router) Run(addr string) {
ReadHeaderTimeout: time.Second,
Handler: router,
}
router.Info("Starting server:", "Address", addr)
slog.Info("Starting server:", "Address", addr)
if err := server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
router.Error("Router.Run: failed to start server: ", "error", err)
slog.Error("Router.Run: failed to start server: ", "error", err)
}
}

Expand Down
27 changes: 13 additions & 14 deletions router_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ package mux

import (
"io"
"log/slog"
"net/http"
"net/http/httptest"
"testing"
)

func dummyHandler(w http.ResponseWriter, r *http.Request) {
func dummyHandler(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "ok")
}

Expand All @@ -23,10 +22,10 @@ func makeMiddleware(tag string) Middleware {
}

func BenchmarkRouterBase(b *testing.B) {
router := DefaultRouter()
router := defaultRouter()
router.HandleFunc("/bench", dummyHandler)

req := httptest.NewRequest("GET", "/bench", nil)
req := httptest.NewRequest(http.MethodGet, "/bench", nil)
w := httptest.NewRecorder()

for b.Loop() {
Expand All @@ -35,14 +34,14 @@ func BenchmarkRouterBase(b *testing.B) {
}

func Benchmark5Routes(b *testing.B) {
router := DefaultRouter()
router := defaultRouter()
router.HandleFunc("/bench1", dummyHandler)
router.HandleFunc("/bench2", dummyHandler)
router.HandleFunc("/bench3", dummyHandler)
router.HandleFunc("/bench4", dummyHandler)
router.HandleFunc("/bench5", dummyHandler)

req := httptest.NewRequest("GET", "/bench2", nil)
req := httptest.NewRequest(http.MethodGet, "/bench2", nil)
w := httptest.NewRecorder()

for b.Loop() {
Expand All @@ -51,10 +50,10 @@ func Benchmark5Routes(b *testing.B) {
}

func BenchmarkRouterWithOneMiddleware(b *testing.B) {
router := NewRouter(nil, makeMiddleware("m1"))
router := NewRouter(makeMiddleware("m1"))
router.HandleFunc("/bench", dummyHandler)

req := httptest.NewRequest("GET", "/bench", nil)
req := httptest.NewRequest(http.MethodGet, "/bench", nil)
w := httptest.NewRecorder()

for b.Loop() {
Expand All @@ -63,7 +62,7 @@ func BenchmarkRouterWithOneMiddleware(b *testing.B) {
}

func BenchmarkRouterWithFiveMiddlewares(b *testing.B) {
router := DefaultRouter()
router := defaultRouter()
router.Use(
makeMiddleware("m1"),
makeMiddleware("m2"),
Expand All @@ -73,21 +72,21 @@ func BenchmarkRouterWithFiveMiddlewares(b *testing.B) {
)
router.HandleFunc("/bench", dummyHandler)

req := httptest.NewRequest("GET", "/bench", nil)
req := httptest.NewRequest(http.MethodGet, "/bench", nil)
w := httptest.NewRecorder()

for i := 0; i < b.N; i++ {
for b.Loop() {
router.ServeHTTP(w, req)
}
}

func BenchmarkRouterGroup(b *testing.B) {
mainRouter := DefaultRouter()
mainRouter := defaultRouter()
group := mainRouter.Group("/api", makeMiddleware("group"))

group.HandleFunc("/bench", dummyHandler)

req := httptest.NewRequest("GET", "/api/bench", nil)
req := httptest.NewRequest(http.MethodGet, "/api/bench", nil)
w := httptest.NewRecorder()

for b.Loop() {
Expand All @@ -96,7 +95,7 @@ func BenchmarkRouterGroup(b *testing.B) {
}

func BenchmarkLogginMiddleWare(b *testing.B) {
router := NewRouter(slog.New(slog.DiscardHandler), Logger)
router := NewRouter(Logger)
router.HandleFunc("/bench", dummyHandler)
req := httptest.NewRequest(http.MethodGet, "/bench", nil)
w := httptest.NewRecorder()
Expand Down
Loading
Loading