Skip to content

Commit

Permalink
refactor(webserver): split logging and recover into seperated package.
Browse files Browse the repository at this point in the history
  • Loading branch information
searKing committed Aug 29, 2024
1 parent adb2ae1 commit 45feee9
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 57 deletions.
3 changes: 2 additions & 1 deletion pkg/webserver/gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/gin-gonic/gin"
slices_ "github.com/searKing/golang/go/exp/slices"
"github.com/searKing/golang/pkg/webserver/healthz"
"github.com/searKing/golang/pkg/webserver/pkg/logging"
gin_ "github.com/searKing/golang/third_party/github.com/gin-gonic/gin"
)

Expand All @@ -31,7 +32,7 @@ func (mux *ginMuxer) Handle(pattern string, handler http.Handler) {
func GinLogFormatter(layout string) func(param gin.LogFormatterParams) string {
return gin_.LogFormatterWithExtra(layout, func(param gin.LogFormatterParams) string {
if param.Request != nil {
attrs := extractLoggingAttrs(param.Request.Context())
attrs := logging.Attrs(param.Request.Context())
if len(attrs) > 0 {
extra := strings.Join(slices_.MapFunc(attrs, func(e slog.Attr) string { return e.String() }), ", ")
return fmt.Sprintf(" | %v", extra)
Expand Down
16 changes: 8 additions & 8 deletions pkg/webserver/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ require (
github.com/searKing/golang/third_party/github.com/gin-gonic/gin v1.2.118
github.com/searKing/golang/third_party/github.com/grpc-ecosystem/grpc-gateway-v2 v1.2.118
github.com/searKing/golang/third_party/google.golang.org/grpc v1.2.118
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/sync v0.7.0
google.golang.org/grpc v1.64.1
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
golang.org/x/sync v0.8.0
google.golang.org/grpc v1.66.0
)

require (
Expand All @@ -28,7 +28,7 @@ require (
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
Expand All @@ -43,10 +43,10 @@ require (
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/time v0.6.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Expand Down
34 changes: 18 additions & 16 deletions pkg/webserver/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 h1:pRhl55Yx1eC7BZ1N+BBWwnKaMyD8uC+34TLdndZMAKk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
Expand Down Expand Up @@ -84,28 +84,30 @@ golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 h1:W5Xj/70xIA4x60O/IFyXivR5MGqblAb8R3w26pnD6No=
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8/go.mod h1:vPrPUTsDCYxXWjP7clS81mZ6/803D8K4iM9Ma27VKas=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 h1:Di6ANFilr+S60a4S61ZM00vLdw0IrQOSMS2/6mrnOU0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package webserver
package logging

import (
"context"
Expand All @@ -11,7 +11,7 @@ import (
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
)

func extractLoggingAttrs(ctx context.Context) []slog.Attr {
func Attrs(ctx context.Context) []slog.Attr {
return fieldsToAttrSlice(logging.ExtractFields(ctx))
}

Expand Down
58 changes: 58 additions & 0 deletions pkg/webserver/pkg/recovery/recovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2024 The searKing Author. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package recovery

import (
"context"
"fmt"
"log/slog"
"os"
"runtime/debug"

"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
slices_ "github.com/searKing/golang/go/exp/slices"
slog_ "github.com/searKing/golang/go/log/slog"
"github.com/searKing/golang/pkg/webserver/pkg/logging"
grpc_ "github.com/searKing/golang/third_party/github.com/grpc-ecosystem/grpc-gateway-v2/grpc"
)

// UnaryServerInterceptor returns a new unary server interceptor that performs recovering from a panic.
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
return grpcrecovery.UnaryServerInterceptor(grpcrecovery.WithRecoveryHandlerContext(recoveryLogHandler))
}

// StreamServerInterceptor returns a new stream server interceptor that performs recovering from a panic.
func StreamServerInterceptor() grpc.StreamServerInterceptor {
return grpcrecovery.StreamServerInterceptor(grpcrecovery.WithRecoveryHandlerContext(recoveryLogHandler))
}

// WrapRecovery returns a new unary server interceptor that performs recovering from a panic.
func WrapRecovery[REQ any, RESP any](handler grpc_.UnaryHandler[REQ, RESP]) grpc_.UnaryHandler[REQ, RESP] {
return func(ctx context.Context, req REQ) (_ RESP, err error) {
defer func() {
if r := recover(); r != nil {
err = recoveryLogHandler(ctx, r)
}
}()

resp, err := handler(ctx, req)
return resp, err
}
}

func recoveryLogHandler(ctx context.Context, p any) (err error) {
{
_, _ = os.Stderr.Write([]byte(fmt.Sprintf("panic: %s", p)))
debug.PrintStack()
_, _ = os.Stderr.Write([]byte(" [recovered]\n"))
}
logger := slog.With(slices_.MapFunc(logging.Attrs(ctx), func(e slog.Attr) any { return e })...)
logger.With(slog_.Error(status.Errorf(codes.Internal, "%s at %s", p, debug.Stack()))).Error("recovered in grpc")
return status.Errorf(codes.Internal, "%s", p)
}
35 changes: 5 additions & 30 deletions pkg/webserver/webserver.factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,21 @@ import (
"net/url"
"os"
"path/filepath"
"runtime/debug"
"strings"
"time"

"github.com/gin-gonic/gin"
grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
"github.com/rs/cors"
slices_ "github.com/searKing/golang/go/exp/slices"
"google.golang.org/grpc"

slog_ "github.com/searKing/golang/go/log/slog"
net_ "github.com/searKing/golang/go/net"
"github.com/searKing/golang/pkg/webserver/healthz"
"github.com/searKing/golang/pkg/webserver/pkg/recovery"
gin_ "github.com/searKing/golang/third_party/github.com/gin-gonic/gin"
grpc_ "github.com/searKing/golang/third_party/github.com/grpc-ecosystem/grpc-gateway-v2/grpc"
"github.com/searKing/golang/third_party/google.golang.org/grpc/interceptors/burstlimit"
"github.com/searKing/golang/third_party/google.golang.org/grpc/interceptors/timeoutlimit"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

// FactoryConfigFunc is an alias for a function that will take in a pointer to an FactoryConfig and modify it
Expand Down Expand Up @@ -176,30 +173,8 @@ func (f *Factory) New() (*WebServer, error) {
}
{
// recover
opts = append(opts, grpc_.WithGrpcUnaryServerChain(grpcrecovery.UnaryServerInterceptor(
grpcrecovery.WithRecoveryHandlerContext(func(ctx context.Context, p any) (err error) {
slog.With(slices_.MapFunc(extractLoggingAttrs(ctx), func(e slog.Attr) any { return e })...).
Error("recovered in grpc", slog_.Error(status.Errorf(codes.Internal, "%s at %s", p, debug.Stack())))
{
_, _ = os.Stderr.Write([]byte(fmt.Sprintf("panic: %s", p)))
debug.PrintStack()
_, _ = os.Stderr.Write([]byte(" [recovered]"))
_, _ = os.Stderr.Write([]byte("\n"))
}
return status.Errorf(codes.Internal, "%s", p)
}))))
opts = append(opts, grpc_.WithGrpcStreamServerChain(grpcrecovery.StreamServerInterceptor(
grpcrecovery.WithRecoveryHandlerContext(func(ctx context.Context, p any) (err error) {
slog.With(slices_.MapFunc(extractLoggingAttrs(ctx), func(e slog.Attr) any { return e })...).
Error("recovered in grpc", slog_.Error(status.Errorf(codes.Internal, "%s at %s", p, debug.Stack())))
{
_, _ = os.Stderr.Write([]byte(fmt.Sprintf("panic: %s", p)))
debug.PrintStack()
_, _ = os.Stderr.Write([]byte(" [recovered]"))
_, _ = os.Stderr.Write([]byte("\n"))
}
return status.Errorf(codes.Internal, "%s", p)
}))))
opts = append(opts, grpc_.WithGrpcUnaryServerChain(recovery.UnaryServerInterceptor()))
opts = append(opts, grpc_.WithGrpcStreamServerChain(recovery.StreamServerInterceptor()))
}
{
// handle request timeout
Expand Down

0 comments on commit 45feee9

Please sign in to comment.