【】 Golang Ir 之 runtime.Caller / Llamadas / CallersFrames / FuncForPC 使用

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

Publicados 349 artículos originales · elogios ganado 14 · Vistas a 90000 +

Supongo que te gusta

Origin blog.csdn.net/LU_ZHAO/article/details/105305141
Recomendado
Clasificación