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  }