feat: complete API-driven projects with infrastructure and business acceptance
This commit is contained in:
@@ -2,6 +2,7 @@ package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
@@ -37,6 +38,7 @@ func Recovery() httpx.Middleware {
|
||||
return func(ctx *httpx.Context) (err error) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
logx.ErrorContext(ctx.Context(), "http.panic", "panic", recovered, "stack", string(debug.Stack()), "method", ctx.Request().Method, "route", httpx.RoutePattern(ctx.Context()))
|
||||
err = apierrors.Internal(fmt.Errorf("panic recovered: %v", recovered))
|
||||
}
|
||||
}()
|
||||
@@ -48,7 +50,25 @@ func Recovery() httpx.Middleware {
|
||||
// AccessLog records one structured event after each request. It deliberately
|
||||
// lives in GoOmni instead of using a router-specific logger so business
|
||||
// applications get the same log format with every transport adapter.
|
||||
func AccessLog() httpx.Middleware {
|
||||
type AccessLogOption func(*accessLogConfig)
|
||||
type accessLogConfig struct{ slowThreshold time.Duration }
|
||||
|
||||
// WithSlowRequestThreshold logs slow requests at WARN. Zero disables detection.
|
||||
func WithSlowRequestThreshold(threshold time.Duration) AccessLogOption {
|
||||
return func(c *accessLogConfig) {
|
||||
if threshold >= 0 {
|
||||
c.slowThreshold = threshold
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AccessLog(options ...AccessLogOption) httpx.Middleware {
|
||||
settings := accessLogConfig{}
|
||||
for _, option := range options {
|
||||
if option != nil {
|
||||
option(&settings)
|
||||
}
|
||||
}
|
||||
return func(next httpx.Handler) httpx.Handler {
|
||||
return func(ctx *httpx.Context) error {
|
||||
started := time.Now()
|
||||
@@ -57,14 +77,30 @@ func AccessLog() httpx.Middleware {
|
||||
if err != nil && !ctx.Responded() {
|
||||
status = apierrors.From(err).Status
|
||||
}
|
||||
logx.InfoContext(ctx.Context(), "http.request",
|
||||
duration := time.Since(started)
|
||||
slow := settings.slowThreshold > 0 && duration >= settings.slowThreshold
|
||||
attrs := []any{
|
||||
"method", ctx.Request().Method,
|
||||
"path", ctx.Request().URL.Path,
|
||||
"route", httpx.RoutePattern(ctx.Context()),
|
||||
"status", status,
|
||||
"durationMs", time.Since(started).Seconds()*1000,
|
||||
"durationMs", duration.Seconds() * 1000,
|
||||
"clientIp", ctx.ClientIP(),
|
||||
)
|
||||
}
|
||||
if slow {
|
||||
attrs = append(attrs, "slow", true)
|
||||
}
|
||||
if err != nil {
|
||||
attrs = append(attrs, "error", err)
|
||||
}
|
||||
switch {
|
||||
case status >= 500:
|
||||
logx.ErrorContext(ctx.Context(), "http.request", attrs...)
|
||||
case slow:
|
||||
logx.WarnContext(ctx.Context(), "http.request", attrs...)
|
||||
default:
|
||||
logx.InfoContext(ctx.Context(), "http.request", attrs...)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user