From 70628bd870f54bef2c54c6c67c4f7e5e0481980b Mon Sep 17 00:00:00 2001
From: zeripath <art27@cantab.net>
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 <art27@cantab.net>
---
 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 0000000000..0d3739fd98
--- /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 0000000000..8e23721b86
--- /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 c725df4f3e..8d94eb2b22 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)