From 70628bd870f54bef2c54c6c67c4f7e5e0481980b Mon Sep 17 00:00:00 2001 From: zeripath Date: Sat, 26 Mar 2022 20:04:36 +0000 Subject: [PATCH] Add auto logging of goroutine pid label (#19212) * Add auto logging of goroutine pid label This PR uses unsafe to export the hidden runtime_getProfLabel function from the runtime package and then casts the result to a map[string]string. We can then interrogate this map to get the pid label from the goroutine allowing us to log it with any logging request. Reference #19202 Signed-off-by: Andrew Thornton --- modules/log/groutinelabel.go | 20 ++++++++++++++++++ modules/log/groutinelabel_test.go | 34 +++++++++++++++++++++++++++++++ modules/log/multichannel.go | 7 +++++++ 3 files changed, 61 insertions(+) create mode 100644 modules/log/groutinelabel.go create mode 100644 modules/log/groutinelabel_test.go diff --git a/modules/log/groutinelabel.go b/modules/log/groutinelabel.go new file mode 100644 index 000000000..0d3739fd9 --- /dev/null +++ b/modules/log/groutinelabel.go @@ -0,0 +1,20 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package log + +import "unsafe" + +//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel +func runtime_getProfLabel() unsafe.Pointer // nolint + +type labelMap map[string]string + +func getGoroutineLabels() map[string]string { + l := (*labelMap)(runtime_getProfLabel()) + if l == nil { + return nil + } + return *l +} diff --git a/modules/log/groutinelabel_test.go b/modules/log/groutinelabel_test.go new file mode 100644 index 000000000..8e23721b8 --- /dev/null +++ b/modules/log/groutinelabel_test.go @@ -0,0 +1,34 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package log + +import ( + "context" + "runtime/pprof" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_getGoroutineLabels(t *testing.T) { + pprof.Do(context.Background(), pprof.Labels(), func(ctx context.Context) { + currentLabels := getGoroutineLabels() + pprof.ForLabels(ctx, func(key, value string) bool { + assert.EqualValues(t, value, currentLabels[key]) + return true + }) + + pprof.Do(ctx, pprof.Labels("Test_getGoroutineLabels", "Test_getGoroutineLabels_child1"), func(ctx context.Context) { + currentLabels := getGoroutineLabels() + pprof.ForLabels(ctx, func(key, value string) bool { + assert.EqualValues(t, value, currentLabels[key]) + return true + }) + if assert.NotNil(t, currentLabels) { + assert.EqualValues(t, "Test_getGoroutineLabels_child1", currentLabels["Test_getGoroutineLabels"]) + } + }) + }) +} diff --git a/modules/log/multichannel.go b/modules/log/multichannel.go index c725df4f3..8d94eb2b2 100644 --- a/modules/log/multichannel.go +++ b/modules/log/multichannel.go @@ -72,6 +72,13 @@ func (l *MultiChannelledLogger) Log(skip int, level Level, format string, v ...i if len(v) > 0 { msg = ColorSprintf(format, v...) } + labels := getGoroutineLabels() + if labels != nil { + pid, ok := labels["pid"] + if ok { + msg = "[" + ColorString(FgHiYellow) + pid + ColorString(Reset) + "] " + msg + } + } stack := "" if l.GetStacktraceLevel() <= level { stack = Stack(skip + 1)