Si el salto es 0, la función devuelve el nombre de la llamada actual función de llamadas, archivo, contador de programa PC, 1 es una función de capa, y así sucesivamente:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
ejemplo
package main
import (
"log"
"runtime"
)
func main() {
test()
}
func test() {
test2()
}
func test2() {
// 上2层函数信息
pc, file, line, ok := runtime.Caller(2)
// 是否获取成功
log.Println(ok)
// 函数指针
log.Println(pc)
// 所属文件
log.Println(file)
// 所属行
log.Println(line)
// 获取函数信息
f := runtime.FuncForPC(pc)
// 函数名
log.Println(f.Name())
// 当前函数信息
pc, file, line, ok = runtime.Caller(0)
log.Println(pc)
log.Println(file)
log.Println(line)
log.Println(ok)
f = runtime.FuncForPC(pc)
log.Println(f.Name())
// 上一层函数信息
pc, file, line, ok = runtime.Caller(1)
log.Println(pc)
log.Println(file)
log.Println(line)
log.Println(ok)
f = runtime.FuncForPC(pc)
log.Println(f.Name())
}
La salida es:
2020/04/04 03:54:48 true
2020/04/04 03:54:48 17410619
2020/04/04 03:54:48 /Users/lurongming/main.go
2020/04/04 03:54:48 9
2020/04/04 03:54:48 main.main
2020/04/04 03:54:48 17411178
2020/04/04 03:54:48 /Users/lurongming/main.go
2020/04/04 03:54:48 34
2020/04/04 03:54:48 true
2020/04/04 03:54:48 main.test2
2020/04/04 03:54:48 17410624
2020/04/04 03:54:48 /Users/lurongming/main.go
2020/04/04 03:54:48 13
2020/04/04 03:54:48 true
2020/04/04 03:54:48 main.test
Nombre de la función para obtener archivos directamente desde el puntero de función:
package main
import (
"log"
"reflect"
"runtime"
)
type Demo struct {
}
func (this *Demo) Hello() {
}
func main() {
demo := new(Demo)
pc := reflect.ValueOf(demo.Hello).Pointer()
f := runtime.FuncForPC(pc)
log.Println(f.Name())
log.Println(f.FileLine(pc))
}
La salida es:
2020/04/04 03:55:47 main.(*Demo).Hello-fm
2020/04/04 03:55:47 /Users/lurongming/main.go 12
Las personas que llaman FUNC (SKIP int, PC [] UIntPtr) int
Las personas que llaman al contador de programa vuelve a la estación que llama, colocados en un UIntPtr.
Las personas que llaman 0 por sí misma, y la importancia de este parámetro de llamada anterior no es la misma, debido a razones históricas. Esto corresponde a solamente 1 0 arriba.
package main
import (
"fmt"
"runtime"
)
func printMyName() string {
pc, _, _, _ := runtime.Caller(1)
return runtime.FuncForPC(pc).Name()
}
func printCallerName() string {
pc, _, _, _ := runtime.Caller(2)
return runtime.FuncForPC(pc).Name()
}
func Foo() {
fmt.Printf("我是 %s, %s 在调用我!\n", printMyName(), printCallerName())
Bar()
}
func Bar() {
fmt.Printf("我是 %s, %s 又在调用我!\n", printMyName(), printCallerName())
trace()
}
func trace() {
pc := make([]uintptr, 10) // at least 1 entry needed
n := runtime.Callers(0, pc)
for i := 0; i < n; i++ {
f := runtime.FuncForPC(pc[i])
file, line := f.FileLine(pc[i])
fmt.Printf("%s:%d %s\n", file, line, f.Name())
}
}
func main() {
Foo()
}
La salida es:
我是 main.Foo, main.main 在调用我!
我是 main.Bar, main.Foo 又在调用我!
/usr/local/go/src/runtime/extern.go:211 runtime.Callers
/Users/lurongming/main.go:27 main.trace
/Users/lurongming/main.go:24 main.Bar
/Users/lurongming/main.go:20 main.Foo
/Users/lurongming/main.go:37 main.main
/usr/local/go/src/runtime/proc.go:212 runtime.main
/usr/local/go/src/runtime/asm_amd64.s:1358 runtime.goexit
CallersFrames (llamadores [] UIntPtr) * Frames
Las personas que llaman por encima o simplemente apilar el contador de programa, si desea obtener información acerca de toda la pila, puede utilizar la función CallersFrames, eliminando la necesidad de FuncForPC llamada poligonal.
La función de rastreo anterior se puede cambiar de la siguiente manera, el resultado de salida es el mismo:
func trace() {
pc := make([]uintptr, 10) // at least 1 entry needed
n := runtime.Callers(0, pc)
frames := runtime.CallersFrames(pc[:n])
for {
frame, more := frames.Next()
fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
if !more {
break
}
}
}
programa de adquisición de pila
En el pánico programa, el general se llevará a cabo la lucha de la pila, la pila si desea obtener la información en el programa, puede debug.PrintStack () para imprimir. Por ejemplo, ¿se ejecuta un programa de error, pero no espera que el programa de pánico, sólo quiero imprimir un seguimiento de la pila información de depuración, puede utilizar debug.PrintStack ().
O bien, se lee la información de la pila, el procesamiento y la impresión propia:
func DumpStacks() {
buf := make([]byte, 16384)
buf = buf[:runtime.Stack(buf, true)]
fmt.Printf("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf)
}
Referencia herramienta de depuración: goroutine volcado de StackTrace .
La información también se puede obtener usando la pila de Identificación del goroutine, se refieren a: y luego hablar de la goroutine método de adquisición ID .
func GoID() int {
var buf [64]byte
n := runtime.Stack(buf[:], false)
idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]
id, err := strconv.Atoi(idField)
if err != nil {
panic(fmt.Sprintf("cannot get goroutine id: %v", err))
}
return id
}
referencia
Componente log golang usando análisis de rendimiento runtime.Caller