github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/ginx/hlog/hlog.go (about) 1 package hlog 2 3 import ( 4 "bytes" 5 "time" 6 7 "github.com/bingoohuang/gg/pkg/ginx/adapt" 8 "github.com/bingoohuang/gg/pkg/snow" 9 "github.com/gin-gonic/gin" 10 ) 11 12 type Adapter struct { 13 Store Store 14 } 15 16 func NewAdapter(store Store) *Adapter { 17 adapter := &Adapter{ 18 Store: store, 19 } 20 21 return adapter 22 } 23 24 type Middle struct { 25 hlog *hlog 26 relativePath string 27 P *Adapter 28 } 29 30 func (m *Middle) Handle(c *gin.Context) {} 31 32 type writer struct { 33 gin.ResponseWriter 34 buf bytes.Buffer 35 } 36 37 func (w *writer) Write(data []byte) (n int, err error) { 38 w.buf.Write(data) 39 return w.ResponseWriter.Write(data) 40 } 41 42 func (w *writer) WriteString(s string) (n int, err error) { 43 w.buf.WriteString(s) 44 return w.ResponseWriter.WriteString(s) 45 } 46 47 func (w *writer) Body(maxSize int) string { 48 if w.ResponseWriter.Size() <= maxSize { 49 return w.buf.String() 50 } 51 52 return string(w.buf.Bytes()[:maxSize-3]) + "..." 53 } 54 55 func (m *Middle) Before(c *gin.Context) (after adapt.Handler) { 56 if m.P.Store == nil || m.hlog.Option.Ignore { 57 return nil 58 } 59 60 l := &Log{Created: time.Now()} 61 62 l.Option = m.hlog.Option 63 l.PathParams = c.Params 64 l.Biz = l.Option.Biz 65 66 r := c.Request 67 l.Method = r.Method 68 l.URL = r.URL.String() 69 l.ReqHeader = r.Header 70 l.Request = r 71 72 l.ID = snow.Next().String() 73 l.IPAddr = GetRemoteAddress(r) 74 75 maxSize := m.hlog.Option.MaxSize 76 l.ReqBody = string(PeekBody(r, maxSize)) 77 78 copyWriter := &writer{ 79 ResponseWriter: c.Writer, 80 } 81 c.Writer = copyWriter 82 l.Start = time.Now() 83 84 return adapt.HandlerFunc(func(c *gin.Context) { 85 l.End = time.Now() 86 l.Duration = l.End.Sub(l.Start) 87 l.RspStatus = copyWriter.Status() 88 l.RespSize = copyWriter.Size() 89 l.RspBody = copyWriter.Body(maxSize) 90 l.RspHeader = copyWriter.Header() 91 l.Attrs = c.Keys 92 93 m.P.Store.Store(c, l) 94 }) 95 } 96 97 func (a *Adapter) Default(relativePath string) adapt.Handler { 98 return &Middle{ 99 relativePath: relativePath, 100 hlog: &hlog{ 101 Option: NewOption(), 102 }, 103 P: a, 104 } 105 } 106 107 func (a *Adapter) Adapt(relativePath string, argV interface{}) adapt.Handler { 108 hlog, ok := argV.(*hlog) 109 if !ok { 110 return nil 111 } 112 113 middle := &Middle{ 114 relativePath: relativePath, 115 hlog: hlog, 116 P: a, 117 } 118 119 return middle 120 } 121 122 type Option struct { 123 MaxSize int 124 Biz string 125 Ignore bool 126 Tables []string 127 } 128 129 func NewOption() *Option { 130 return &Option{ 131 MaxSize: 3000, 132 } 133 } 134 135 type OptionFn func(option *Option) 136 137 func (a *Adapter) MaxSize(v int) OptionFn { 138 return func(option *Option) { 139 option.MaxSize = v 140 } 141 } 142 143 func (a *Adapter) Tables(tables ...string) OptionFn { 144 return func(option *Option) { 145 option.Tables = tables 146 } 147 } 148 149 func (a *Adapter) Biz(biz string) OptionFn { 150 return func(option *Option) { 151 option.Biz = biz 152 } 153 } 154 155 func (a *Adapter) Ignore() OptionFn { 156 return func(option *Option) { 157 option.Ignore = true 158 } 159 } 160 161 type hlog struct { 162 Option *Option 163 P *Adapter 164 } 165 166 func (h *hlog) Parent() adapt.Adapter { return h.P } 167 168 func (a *Adapter) F(fns ...OptionFn) adapt.Parent { 169 o := NewOption() 170 for _, f := range fns { 171 f(o) 172 } 173 174 return &hlog{P: a, Option: o} 175 }