gdebug_stack.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Copyright GoFrame Author(https://goframe.org). 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. )
  12. // PrintStack prints to standard error the stack trace returned by runtime.Stack.
  13. func PrintStack(skip ...int) {
  14. fmt.Print(Stack(skip...))
  15. }
  16. // Stack returns a formatted stack trace of the goroutine that calls it.
  17. // It calls runtime.Stack with a large enough buffer to capture the entire trace.
  18. func Stack(skip ...int) string {
  19. return StackWithFilter(nil, skip...)
  20. }
  21. // StackWithFilter returns a formatted stack trace of the goroutine that calls it.
  22. // It calls runtime.Stack with a large enough buffer to capture the entire trace.
  23. //
  24. // The parameter `filter` is used to filter the path of the caller.
  25. func StackWithFilter(filters []string, skip ...int) string {
  26. return StackWithFilters(filters, skip...)
  27. }
  28. // StackWithFilters returns a formatted stack trace of the goroutine that calls it.
  29. // It calls runtime.Stack with a large enough buffer to capture the entire trace.
  30. //
  31. // The parameter `filters` is a slice of strings, which are used to filter the path of the
  32. // caller.
  33. //
  34. // TODO Improve the performance using debug.Stack.
  35. func StackWithFilters(filters []string, skip ...int) string {
  36. number := 0
  37. if len(skip) > 0 {
  38. number = skip[0]
  39. }
  40. var (
  41. name = ""
  42. space = " "
  43. index = 1
  44. buffer = bytes.NewBuffer(nil)
  45. ok = true
  46. pc, file, line, start = callerFromIndex(filters)
  47. )
  48. for i := start + number; i < maxCallerDepth; i++ {
  49. if i != start {
  50. pc, file, line, ok = runtime.Caller(i)
  51. }
  52. if ok {
  53. if filterFileByFilters(file, filters) {
  54. continue
  55. }
  56. if fn := runtime.FuncForPC(pc); fn == nil {
  57. name = "unknown"
  58. } else {
  59. name = fn.Name()
  60. }
  61. if index > 9 {
  62. space = " "
  63. }
  64. buffer.WriteString(fmt.Sprintf("%d.%s%s\n %s:%d\n", index, space, name, file, line))
  65. index++
  66. } else {
  67. break
  68. }
  69. }
  70. return buffer.String()
  71. }