【Golang】ゴー之runtime.Caller /コーラー/ CallersFrames / FuncForPC使用

スキップが0である場合、この関数は、現在の通話発信機能、ファイル、プログラムカウンタPC、1名がレイヤ機能である、というように返します。

func Caller(skip int) (pc uintptr, file string, line int, ok bool)
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())
}

出力は次のようになります。

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

関数ポインタから直接ファイルを取得する機能の名前:

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))
}

出力は次のようになります。

2020/04/04 03:55:47 main.(*Demo).Hello-fm
2020/04/04 03:55:47 /Users/lurongming/main.go 12
FUNCコーラー(int型スキップ、PC [] uintptr)INT

uintptrに配置された呼び出しステーションにプログラムカウンタに戻り、発信者へ。

自体の発呼者0、および発信者が上記の歴史的な理由のために、同じではない、このパラメータの意味。わずか1 0上に、この対応します。

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()
}

出力は次のようになります。

我是 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(発信者[] uintptr)*フレーム

発信者は上記または単にプログラムカウンタをスタック、あなたはスタック全体についての情報を取得したい場合、あなたはトラバースコールFuncForPCする必要がなくなり、CallersFrames機能を使用することができます。

上記トレース機能は、以下のように変更することができ、出力結果は同じです。

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
		}
	}
}
スタック取得プログラム

あなたがプログラム内の情報を取得したい場合は、プログラムのパニックでは、一般的には、スタックのスタックを戦いを取るだろう、あなたはdebug.PrintStackは()プリントアウトすることができます。たとえば、あなたがプログラムのエラーを実行するのですが、プログラムのパニックを期待していない、単にデバッグ情報をスタックトレースをプリントアウトしたい、あなたはdebug.PrintStack()を使用することができます。

それとも、あなたはスタック情報、独自の処理や印刷をお読みください。

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)
}

参考デバッグツールました。:stackTraceのダンプゴルーチン

情報はまた、ゴルーチンIDのスタックを使用して得を参照することができる。その後、取得方法のゴルーチンの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
}
参照

runtime.Callerパフォーマンス分析を使用してgolangログコンポーネント

公開された349元の記事 ウォン称賛14 ビュー90000 +

おすすめ

転載: blog.csdn.net/LU_ZHAO/article/details/105305141