Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to identify a goroutine?

Tags:

go

goroutine

Let's say I have a stacktrace for a bunch of goroutines, e. g.:

goroutine 5633 [select]:
net/http.(*persistConn).writeLoop(0xc21303ac00)
    /usr/lib/go/src/pkg/net/http/transport.go:791 +0x271
created by net/http.(*Transport).dialConn
    /usr/lib/go/src/pkg/net/http/transport.go:529 +0x61e

In my case a unique application-specific object is served by a set of goroutines, and I want to look at the stacktrace of goroutines relating to a particular object. I have hundreds of application-specific objects, so I get hundreds of identical goroutines.

How would I go about correlating my logs with goroutines in the stacktrace? There doesn't seem to be a way of identifying a current goroutine in a stack trace and no way of naming a goroutine so I can see a specific value in stack trace.

PS

I've already read the related why-would-you-want-to-do-it posts on Go mailing list, so I'm looking for alternatives/hacks/workarounds (that hopefully don't involve sprinkling the code with a log call every other line).

like image 331
Alex B Avatar asked Oct 13 '14 16:10

Alex B


2 Answers

A workaround is possible, and involves a small piece of C code.

goid.c

#include <runtime.h>
void ·GetGoID(int32 ret) {
    ret = g->goid;
    USED(&ret);
}

main.go

package main
import (
    "fmt"
    "sync"
)
// Declaration is required
func GetGoID() int32
func main() {
    var wg sync.WaitGroup
    f := func() {
        wg.Add(1)
        go func() {
            fmt.Printf("goroutine %d\n", GetGoID())
            wg.Done()
        }()
    }
    for i := 0; i < 10; i++ {
        f()
    }
    wg.Wait()
}

Build and run

$ go build
$ ./example
goroutine 20
goroutine 21
goroutine 22
goroutine 23
goroutine 24
goroutine 25
goroutine 26
goroutine 27
goroutine 28
goroutine 29
like image 101
Alex B Avatar answered Nov 13 '22 21:11

Alex B


Play

This method is simpler than @Alex B. It use the fact that debug.Stack() return stack trace in the form of byte slice which contains goroutine its id in the second word boundary along with, well stack trace. And parse it.

package main

import (
    "bytes"
    "fmt"
    "runtime/debug"
    "sync"
)

func main() {
    w := sync.WaitGroup{}
    w.Add(1)
    go func() {
        gr := bytes.Fields(debug.Stack())[1]
        fmt.Println(string(gr))
        w.Done()
    }()
    w.Wait()
}
like image 21
qxxt Avatar answered Nov 13 '22 21:11

qxxt