log.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package golog
  2. import (
  3. "fmt"
  4. "path/filepath"
  5. "runtime"
  6. "strings"
  7. "time"
  8. )
  9. // A Log represents a log line.
  10. type Log struct {
  11. // Logger is the original printer of this Log.
  12. Logger *Logger `json:"-"`
  13. // Time is the time of fired.
  14. Time time.Time `json:"-"`
  15. // Timestamp is the unix time in second of fired.
  16. Timestamp int64 `json:"timestamp,omitempty"`
  17. // Level is the log level.
  18. Level Level `json:"level"`
  19. // Message is the string reprensetation of the log's main body.
  20. Message string `json:"message"`
  21. // Fields any data information useful to represent this log.
  22. Fields Fields `json:"fields,omitempty"`
  23. // Stacktrace contains the stack callers when on `Debug` level.
  24. // The first one should be the Logger's direct caller function.
  25. Stacktrace []Frame `json:"stacktrace,omitempty"`
  26. // NewLine returns false if this Log
  27. // derives from a `Print` function,
  28. // otherwise true if derives from a `Println`, `Error`, `Errorf`, `Warn`, etc...
  29. //
  30. // This NewLine does not mean that `Message` ends with "\n" (or `pio#NewLine`).
  31. // NewLine has to do with the methods called,
  32. // not the original content of the `Message`.
  33. NewLine bool `json:"-"`
  34. }
  35. // Frame represents the log's caller.
  36. type Frame struct {
  37. // Function is the package path-qualified function name of
  38. // this call frame. If non-empty, this string uniquely
  39. // identifies a single function in the program.
  40. // This may be the empty string if not known.
  41. Function string `json:"function"`
  42. // Source contains the file name and line number of the
  43. // location in this frame. For non-leaf frames, this will be
  44. // the location of a call.
  45. Source string `json:"source"`
  46. }
  47. // String method returns the concat value of "file:line".
  48. // Implements the `fmt.Stringer` interface.
  49. func (f Frame) String() string {
  50. return f.Source
  51. }
  52. // FormatTime returns the formatted `Time`.
  53. func (l *Log) FormatTime() string {
  54. if l.Logger.TimeFormat == "" {
  55. return ""
  56. }
  57. return l.Time.Format(l.Logger.TimeFormat)
  58. }
  59. var funcNameReplacer = strings.NewReplacer(")", "", "(", "", "*", "")
  60. // GetStacktrace tries to return the callers of this function.
  61. func GetStacktrace(limit int) (callerFrames []Frame) {
  62. if limit < 0 {
  63. return nil
  64. }
  65. var pcs [32]uintptr
  66. n := runtime.Callers(1, pcs[:])
  67. frames := runtime.CallersFrames(pcs[:n])
  68. for {
  69. f, more := frames.Next()
  70. file := filepath.ToSlash(f.File)
  71. if strings.Contains(file, "go/src/") {
  72. continue
  73. }
  74. if strings.Contains(file, "github.com/kataras/golog") &&
  75. !(strings.Contains(file, "_examples") ||
  76. strings.Contains(file, "_test.go") ||
  77. strings.Contains(file, "integration.go")) {
  78. continue
  79. }
  80. if file != "" { // keep it here, break should be respected.
  81. funcName := f.Function
  82. if idx := strings.Index(funcName, ".("); idx > 1 {
  83. funcName = funcNameReplacer.Replace(funcName[idx+1:])
  84. // e.g. method: github.com/kataras/iris/v12.(*Application).Listen to:
  85. // Application.Listen
  86. } else if idx = strings.LastIndexByte(funcName, '/'); idx >= 0 && len(funcName) > idx+1 {
  87. funcName = strings.Replace(funcName[idx+1:], ".", "/", 1)
  88. // e.g. package-level function: github.com/kataras/iris/v12/context.Do to
  89. // context/Do
  90. }
  91. callerFrames = append(callerFrames, Frame{
  92. Function: funcName,
  93. Source: fmt.Sprintf("%s:%d", f.File, f.Line),
  94. })
  95. if limit > 0 && len(callerFrames) >= limit {
  96. break
  97. }
  98. }
  99. if !more {
  100. break
  101. }
  102. }
  103. return
  104. }