cutter.go 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package internal
  2. import (
  3. "os"
  4. "path/filepath"
  5. "regexp"
  6. "strings"
  7. "sync"
  8. "time"
  9. )
  10. type Cutter struct {
  11. level string // 日志级别(debug, info, warn, error, dpanic, panic, fatal)
  12. format string // 时间格式(2006-01-02)
  13. Director string // 日志文件夹
  14. dept *os.File // 文件句柄
  15. mutex *sync.RWMutex // 读写锁
  16. }
  17. type CutterOption func(*Cutter)
  18. // WithCutterFormat 设置时间格式
  19. func WithCutterFormat(format string) CutterOption {
  20. return func(c *Cutter) {
  21. c.format = format
  22. }
  23. }
  24. func NewCutter(director string, level string, options ...CutterOption) *Cutter {
  25. rotate := &Cutter{
  26. level: level,
  27. Director: director,
  28. mutex: new(sync.RWMutex),
  29. }
  30. for i := 0; i < len(options); i++ {
  31. options[i](rotate)
  32. }
  33. return rotate
  34. }
  35. // Write satisfies the io.Writer interface. It writes to the
  36. // appropriate dept handle that is currently being used.
  37. // If we have reached rotation time, the target dept gets
  38. // automatically rotated, and also purged if necessary.
  39. func (c *Cutter) Write(bytes []byte) (n int, err error) {
  40. c.mutex.Lock()
  41. defer func() {
  42. if c.dept != nil {
  43. _ = c.dept.Close()
  44. c.dept = nil
  45. }
  46. c.mutex.Unlock()
  47. }()
  48. var business string
  49. if strings.Contains(string(bytes), "business") {
  50. var compile *regexp.Regexp
  51. compile, err = regexp.Compile(`{"business": "([^,]+)"}`)
  52. if err != nil {
  53. return 0, err
  54. }
  55. if compile.Match(bytes) {
  56. finds := compile.FindSubmatch(bytes)
  57. business = string(finds[len(finds)-1])
  58. bytes = compile.ReplaceAll(bytes, []byte(""))
  59. }
  60. compile, err = regexp.Compile(`"business": "([^,]+)"`)
  61. if err != nil {
  62. return 0, err
  63. }
  64. if compile.Match(bytes) {
  65. finds := compile.FindSubmatch(bytes)
  66. business = string(finds[len(finds)-1])
  67. bytes = compile.ReplaceAll(bytes, []byte(""))
  68. }
  69. }
  70. format := time.Now().Format(c.format)
  71. formats := make([]string, 0, 4)
  72. formats = append(formats, c.Director)
  73. if format != "" {
  74. formats = append(formats, format)
  75. }
  76. if business != "" {
  77. formats = append(formats, business)
  78. }
  79. formats = append(formats, c.level+".log")
  80. deptname := filepath.Join(formats...)
  81. dirname := filepath.Dir(deptname)
  82. err = os.MkdirAll(dirname, 0755)
  83. if err != nil {
  84. return 0, err
  85. }
  86. c.dept, err = os.OpenFile(deptname, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
  87. if err != nil {
  88. return 0, err
  89. }
  90. return c.dept.Write(bytes)
  91. }