package printer import ( "context" "joybuywork/internal/app" "joybuywork/internal/consts" "joybuywork/internal/plugins/hashid" "joybuywork/internal/repository/dao" "joybuywork/internal/repository/model" "joybuywork/internal/utils" "go-micro.dev/v4/metadata" "sync/atomic" "time" ) type slows struct { idx atomic.Int32 slowLogs [][]*model.SlowLog listen *app.Listener } var Slow = &slows{ idx: atomic.Int32{}, slowLogs: make([][]*model.SlowLog, 2), listen: app.NewListener(), } func (s *slows) Run() { Slow.listen.Listen(func() (messages []string) { i := s.idx.Load() if len(s.slowLogs[i]) == 0 { return } var logs = s.slowLogs[i] if i == 0 { s.idx.Add(1) } else { s.idx.Add(-1) } s.slowLogs[i] = nil _ = dao.SlowLog.WithContext(context.Background()).CreateInBatches(logs, 300) return }, 5*time.Second) } func (s *slows) Stop() { Slow.listen.Stop() } // 把慢日志入库 func init() { if consts.CollectSlowLog { Slow.Run() } } type SlowType func() time.Duration var ( normalSlow = func() time.Duration { return 51 * time.Millisecond } // 50ms TenNormalSlow = func() time.Duration { return 501 * time.Millisecond } // 500ms ) type SlowLog struct { ctx context.Context slow SlowType start time.Time } // NewSlowLog 实例化一个慢日志 func NewSlowLog(ctx context.Context, opts ...SlowLogOption) *SlowLog { sl := &SlowLog{ ctx: ctx, slow: normalSlow, } for _, opt := range opts { opt(sl) } return sl } // Start 开始 func (s *SlowLog) Start(msg string) { s.start = time.Now() Print(s.ctx, msg, nil) } // End 结束 func (s *SlowLog) End(msg string, err error, method, req, res string) { Print(s.ctx, msg, err) if time.Since(s.start) < s.slow() { return } if consts.CollectSlowLog { traceId, _ := metadata.Get(s.ctx, consts.TraceIdKey) Slow.slowLogs[int(Slow.idx.Load())] = append(Slow.slowLogs[int(Slow.idx.Load())], &model.SlowLog{ ID: hashid.IdBigint(), Method: method, Req: utils.STernary[string](req, "", "{}"), Res: utils.STernary[string](res, "", "{}"), Sec: time.Since(s.start).Milliseconds(), TraceID: traceId, }) } }