gdebug_stack.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Copyright 2019-2020 gf Author(https://github.com/gogf/gf). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gdebug
  7. import (
  8. "bytes"
  9. "fmt"
  10. "runtime"
  11. "strings"
  12. )
  13. // PrintStack prints to standard error the stack trace returned by runtime.Stack.
  14. func PrintStack(skip ...int) {
  15. fmt.Print(Stack(skip...))
  16. }
  17. // Stack returns a formatted stack trace of the goroutine that calls it.
  18. // It calls runtime.Stack with a large enough buffer to capture the entire trace.
  19. func Stack(skip ...int) string {
  20. return StackWithFilter("", skip...)
  21. }
  22. // StackWithFilter returns a formatted stack trace of the goroutine that calls it.
  23. // It calls runtime.Stack with a large enough buffer to capture the entire trace.
  24. //
  25. // The parameter <filter> is used to filter the path of the caller.
  26. func StackWithFilter(filter string, skip ...int) string {
  27. return StackWithFilters([]string{filter}, skip...)
  28. }
  29. // StackWithFilters returns a formatted stack trace of the goroutine that calls it.
  30. // It calls runtime.Stack with a large enough buffer to capture the entire trace.
  31. //
  32. // The parameter <filters> is a slice of strings, which are used to filter the path of the
  33. // caller.
  34. //
  35. // TODO Improve the performance using debug.Stack.
  36. func StackWithFilters(filters []string, skip ...int) string {
  37. number := 0
  38. if len(skip) > 0 {
  39. number = skip[0]
  40. }
  41. var (
  42. name = ""
  43. space = " "
  44. index = 1
  45. buffer = bytes.NewBuffer(nil)
  46. filtered = false
  47. ok = true
  48. pc, file, line, start = callerFromIndex(filters)
  49. )
  50. for i := start + number; i < gMAX_DEPTH; i++ {
  51. if i != start {
  52. pc, file, line, ok = runtime.Caller(i)
  53. }
  54. if ok {
  55. // Filter empty file.
  56. if file == "" {
  57. continue
  58. }
  59. // GOROOT filter.
  60. if goRootForFilter != "" &&
  61. len(file) >= len(goRootForFilter) &&
  62. file[0:len(goRootForFilter)] == goRootForFilter {
  63. continue
  64. }
  65. // Custom filtering.
  66. filtered = false
  67. for _, filter := range filters {
  68. if filter != "" && strings.Contains(file, filter) {
  69. filtered = true
  70. break
  71. }
  72. }
  73. if filtered {
  74. continue
  75. }
  76. if strings.Contains(file, gFILTER_KEY) {
  77. continue
  78. }
  79. if fn := runtime.FuncForPC(pc); fn == nil {
  80. name = "unknown"
  81. } else {
  82. name = fn.Name()
  83. }
  84. if index > 9 {
  85. space = " "
  86. }
  87. buffer.WriteString(fmt.Sprintf("%d.%s%s\n %s:%d\n", index, space, name, file, line))
  88. index++
  89. } else {
  90. break
  91. }
  92. }
  93. return buffer.String()
  94. }