github.com/gogf/gf/v2@v2.7.4/debug/gdebug/gdebug_stack.go (about)

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