Skip to content

proposal: runtime/pprof: add WriteGoroutineLabels function for logging #51223

Open
@ansiwen

Description

@ansiwen

Problem Statement

Given that goroutines are anonymous and there is no accessible goroutine id makes it very difficult to add goroutine context to debug/tracing output without having a context parameter in all functions and a context field in all objects, which is often unfeasible. That lead to many attempts to workaround this limitation and reoccurring debates about it. So, although beyond doubt there is a reasonable demand for context logging, it has deliberately been ignored in order to not undermine the anonymity of goroutines, which is regarded as more important.

Proposal

As a kind of compromise, that allows to log goroutine context, without making it too easy to abuse it for "goroutine local storage", I want to propose the following API:

package pprof

// WriteGoroutineLabels writes the current goroutine's labels to w. If a write
// to w returns an error, that error is returned, nil otherwise. The format of
// the output is not specified, and should only be used for logging/tracing
// purposes.
func WriteGoroutineLabels(w io.Writer) error { ... }

This would easily and efficiently allow to set labels with the SetGoroutineLabels() and Do() functions, and still log them in code paths, where the context is not available, and give important information for log forensics. This is especially useful for 3rd party libraries, that don't support contexts, but do support setting a global log sink for debug output. For example:

import (
  "context"
  "log"
  "runtime/pprof"

  "github.com/ansiwen/foobar"
)

func init() {
  foobar.SetDebugOutput(func(msg string) {
    var lbls strings.Builder
    _ = pprof.WriteGoroutineLabels(&lbls)
    log.Printf(`[DBG]<foobar> msg="%s" context="%s"`, msg, lbls.String())
  })
}

func fireFoobarRequest(id string, data []byte) {
  go func() {
    lbl := pprof.Labels("requestID", id)
    pprof.SetGoroutineLabels(pprof.WithLabels(context.Background(), lbl))
    foobar.doRequest(data)
  }()
}

Edit: added usage example.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Todo

    Status

    Incoming

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions