LineFormatter.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /**
  2. @author: xuhanlin
  3. @date: 2022/6/28
  4. @note: 基础线性格式日志
  5. **/
  6. package log
  7. import (
  8. "bytes"
  9. "fmt"
  10. "github.com/sirupsen/logrus"
  11. "runtime"
  12. "strconv"
  13. "strings"
  14. )
  15. // GetGid 获取协程ID
  16. func GetGid() uint64 {
  17. b := make([]byte, 64)
  18. b = b[:runtime.Stack(b, false)]
  19. b = bytes.TrimPrefix(b, []byte("goroutine "))
  20. b = b[:bytes.IndexByte(b, ' ')]
  21. n, err := strconv.ParseUint(string(b), 10, 64)
  22. if err != nil {
  23. return 0
  24. }
  25. return n
  26. }
  27. type LineFormatter struct {
  28. Skip int
  29. }
  30. func (f *LineFormatter) Format(entry *logrus.Entry) ([]byte, error) {
  31. data := ""
  32. // 毫秒时间
  33. data += entry.Time.Format("2006-01-02 15:04:05.000")
  34. // 日志等级
  35. data += "|" + strings.ToUpper(entry.Level.String())
  36. // 调用信息
  37. data += "|" + findCaller(f.Skip)
  38. // 线程信息
  39. data += "|" + strconv.FormatUint(GetGid(), 10)
  40. // 日志内容
  41. data += "|" + entry.Message
  42. return append([]byte(data), '\n'), nil
  43. }
  44. func findCaller(skip int) string {
  45. file, line, pc := getCaller(skip)
  46. fullFnName := runtime.FuncForPC(pc)
  47. fnName := ""
  48. if fullFnName != nil {
  49. fnNameStr := fullFnName.Name()
  50. parts := strings.Split(fnNameStr, ".")
  51. fnName = parts[len(parts)-1]
  52. }
  53. tmp := strings.Split(file, "/")
  54. return fmt.Sprintf("%s:%s:%d", tmp[len(tmp)-1], fnName, line)
  55. }
  56. func getCaller(skip int) (string, int, uintptr) {
  57. pc, file, line, ok := runtime.Caller(skip)
  58. if !ok {
  59. return "", 0, pc
  60. }
  61. n := 0
  62. for i := len(file) - 1; i > 0; i-- {
  63. if file[i] == '/' {
  64. n++
  65. if n >= 2 {
  66. file = file[i+1:]
  67. break
  68. }
  69. }
  70. }
  71. return file, line, pc
  72. }