aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/git/batch_reader.go18
-rw-r--r--modules/git/blame.go5
-rw-r--r--modules/git/command.go68
-rw-r--r--modules/git/command_test.go6
-rw-r--r--modules/git/repo.go13
-rw-r--r--modules/graceful/manager.go7
-rw-r--r--modules/graceful/manager_common.go16
-rw-r--r--modules/gtprof/gtprof.go25
-rw-r--r--modules/log/event_format.go26
-rw-r--r--modules/log/event_format_test.go30
-rw-r--r--modules/log/flags.go2
-rw-r--r--modules/log/groutinelabel.go19
-rw-r--r--modules/log/groutinelabel_test.go33
-rw-r--r--modules/log/logger_impl.go5
-rw-r--r--modules/process/manager.go21
-rw-r--r--modules/process/manager_stacktraces.go14
-rw-r--r--modules/queue/workerqueue.go4
-rw-r--r--modules/util/runtime.go13
-rw-r--r--modules/util/runtime_test.go32
19 files changed, 166 insertions, 191 deletions
diff --git a/modules/git/batch_reader.go b/modules/git/batch_reader.go
index 7dfda72155..532dbad989 100644
--- a/modules/git/batch_reader.go
+++ b/modules/git/batch_reader.go
@@ -7,10 +7,8 @@ import (
"bufio"
"bytes"
"context"
- "fmt"
"io"
"math"
- "runtime"
"strconv"
"strings"
@@ -32,7 +30,6 @@ type WriteCloserError interface {
func ensureValidGitRepository(ctx context.Context, repoPath string) error {
stderr := strings.Builder{}
err := NewCommand(ctx, "rev-parse").
- SetDescription(fmt.Sprintf("%s rev-parse [repo_path: %s]", GitExecutable, repoPath)).
Run(&RunOpts{
Dir: repoPath,
Stderr: &stderr,
@@ -62,13 +59,9 @@ func catFileBatchCheck(ctx context.Context, repoPath string) (WriteCloserError,
cancel()
}()
- _, filename, line, _ := runtime.Caller(2)
- filename = strings.TrimPrefix(filename, callerPrefix)
-
go func() {
stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch-check").
- SetDescription(fmt.Sprintf("%s cat-file --batch-check [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
Run(&RunOpts{
Dir: repoPath,
Stdin: batchStdinReader,
@@ -114,13 +107,9 @@ func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
cancel()
}()
- _, filename, line, _ := runtime.Caller(2)
- filename = strings.TrimPrefix(filename, callerPrefix)
-
go func() {
stderr := strings.Builder{}
err := NewCommand(ctx, "cat-file", "--batch").
- SetDescription(fmt.Sprintf("%s cat-file --batch [repo_path: %s] (%s:%d)", GitExecutable, repoPath, filename, line)).
Run(&RunOpts{
Dir: repoPath,
Stdin: batchStdinReader,
@@ -320,13 +309,6 @@ func ParseTreeLine(objectFormat ObjectFormat, rd *bufio.Reader, modeBuf, fnameBu
return mode, fname, sha, n, err
}
-var callerPrefix string
-
-func init() {
- _, filename, _, _ := runtime.Caller(0)
- callerPrefix = strings.TrimSuffix(filename, "modules/git/batch_reader.go")
-}
-
func DiscardFull(rd *bufio.Reader, discard int64) error {
if discard > math.MaxInt32 {
n, err := rd.Discard(math.MaxInt32)
diff --git a/modules/git/blame.go b/modules/git/blame.go
index a9b2706f21..cad720edf4 100644
--- a/modules/git/blame.go
+++ b/modules/git/blame.go
@@ -7,7 +7,6 @@ import (
"bufio"
"bytes"
"context"
- "fmt"
"io"
"os"
@@ -142,9 +141,7 @@ func CreateBlameReader(ctx context.Context, objectFormat ObjectFormat, repoPath
// There is no equivalent on Windows. May be implemented if Gitea uses an external git backend.
cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile)
}
- cmd.AddDynamicArguments(commit.ID.String()).
- AddDashesAndList(file).
- SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath))
+ cmd.AddDynamicArguments(commit.ID.String()).AddDashesAndList(file)
reader, stdout, err := os.Pipe()
if err != nil {
if ignoreRevsFile != nil {
diff --git a/modules/git/command.go b/modules/git/command.go
index 22cb275ab2..b231c3beea 100644
--- a/modules/git/command.go
+++ b/modules/git/command.go
@@ -12,6 +12,7 @@ import (
"io"
"os"
"os/exec"
+ "path/filepath"
"runtime"
"strings"
"time"
@@ -43,18 +44,24 @@ type Command struct {
prog string
args []string
parentContext context.Context
- desc string
globalArgsLength int
brokenArgs []string
}
-func (c *Command) String() string {
- return c.toString(false)
+func logArgSanitize(arg string) string {
+ if strings.Contains(arg, "://") && strings.Contains(arg, "@") {
+ return util.SanitizeCredentialURLs(arg)
+ } else if filepath.IsAbs(arg) {
+ base := filepath.Base(arg)
+ dir := filepath.Dir(arg)
+ return filepath.Join(filepath.Base(dir), base)
+ }
+ return arg
}
-func (c *Command) toString(sanitizing bool) string {
+func (c *Command) LogString() string {
// WARNING: this function is for debugging purposes only. It's much better than old code (which only joins args with space),
- // It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms.
+ // It's impossible to make a simple and 100% correct implementation of argument quoting for different platforms here.
debugQuote := func(s string) string {
if strings.ContainsAny(s, " `'\"\t\r\n") {
return fmt.Sprintf("%q", s)
@@ -63,12 +70,11 @@ func (c *Command) toString(sanitizing bool) string {
}
a := make([]string, 0, len(c.args)+1)
a = append(a, debugQuote(c.prog))
- for _, arg := range c.args {
- if sanitizing && (strings.Contains(arg, "://") && strings.Contains(arg, "@")) {
- a = append(a, debugQuote(util.SanitizeCredentialURLs(arg)))
- } else {
- a = append(a, debugQuote(arg))
- }
+ if c.globalArgsLength > 0 {
+ a = append(a, "...global...")
+ }
+ for i := c.globalArgsLength; i < len(c.args); i++ {
+ a = append(a, debugQuote(logArgSanitize(c.args[i])))
}
return strings.Join(a, " ")
}
@@ -112,12 +118,6 @@ func (c *Command) SetParentContext(ctx context.Context) *Command {
return c
}
-// SetDescription sets the description for this command which be returned on c.String()
-func (c *Command) SetDescription(desc string) *Command {
- c.desc = desc
- return c
-}
-
// isSafeArgumentValue checks if the argument is safe to be used as a value (not an option)
func isSafeArgumentValue(s string) bool {
return s == "" || s[0] != '-'
@@ -271,8 +271,12 @@ var ErrBrokenCommand = errors.New("git command is broken")
// Run runs the command with the RunOpts
func (c *Command) Run(opts *RunOpts) error {
+ return c.run(1, opts)
+}
+
+func (c *Command) run(skip int, opts *RunOpts) error {
if len(c.brokenArgs) != 0 {
- log.Error("git command is broken: %s, broken args: %s", c.String(), strings.Join(c.brokenArgs, " "))
+ log.Error("git command is broken: %s, broken args: %s", c.LogString(), strings.Join(c.brokenArgs, " "))
return ErrBrokenCommand
}
if opts == nil {
@@ -285,20 +289,14 @@ func (c *Command) Run(opts *RunOpts) error {
timeout = defaultCommandExecutionTimeout
}
- if len(opts.Dir) == 0 {
- log.Debug("git.Command.Run: %s", c)
- } else {
- log.Debug("git.Command.RunDir(%s): %s", opts.Dir, c)
- }
-
- desc := c.desc
- if desc == "" {
- if opts.Dir == "" {
- desc = fmt.Sprintf("git: %s", c.toString(true))
- } else {
- desc = fmt.Sprintf("git(dir:%s): %s", opts.Dir, c.toString(true))
- }
+ var desc string
+ callerInfo := util.CallerFuncName(1 /* util */ + 1 /* this */ + skip /* parent */)
+ if pos := strings.LastIndex(callerInfo, "/"); pos >= 0 {
+ callerInfo = callerInfo[pos+1:]
}
+ // these logs are for debugging purposes only, so no guarantee of correctness or stability
+ desc = fmt.Sprintf("git.Run(by:%s, repo:%s): %s", callerInfo, logArgSanitize(opts.Dir), c.LogString())
+ log.Debug("git.Command: %s", desc)
var ctx context.Context
var cancel context.CancelFunc
@@ -401,7 +399,7 @@ func IsErrorExitCode(err error, code int) bool {
// RunStdString runs the command with options and returns stdout/stderr as string. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr RunStdError) {
- stdoutBytes, stderrBytes, err := c.RunStdBytes(opts)
+ stdoutBytes, stderrBytes, err := c.runStdBytes(opts)
stdout = util.UnsafeBytesToString(stdoutBytes)
stderr = util.UnsafeBytesToString(stderrBytes)
if err != nil {
@@ -413,6 +411,10 @@ func (c *Command) RunStdString(opts *RunOpts) (stdout, stderr string, runErr Run
// RunStdBytes runs the command with options and returns stdout/stderr as bytes. and store stderr to returned error (err combined with stderr).
func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
+ return c.runStdBytes(opts)
+}
+
+func (c *Command) runStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunStdError) {
if opts == nil {
opts = &RunOpts{}
}
@@ -435,7 +437,7 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
PipelineFunc: opts.PipelineFunc,
}
- err := c.Run(newOpts)
+ err := c.run(2, newOpts)
stderr = stderrBuf.Bytes()
if err != nil {
return nil, stderr, &runStdError{err: err, stderr: util.UnsafeBytesToString(stderr)}
diff --git a/modules/git/command_test.go b/modules/git/command_test.go
index 9a6228c9ad..0823afd7f7 100644
--- a/modules/git/command_test.go
+++ b/modules/git/command_test.go
@@ -55,8 +55,8 @@ func TestGitArgument(t *testing.T) {
func TestCommandString(t *testing.T) {
cmd := NewCommandContextNoGlobals(context.Background(), "a", "-m msg", "it's a test", `say "hello"`)
- assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.String())
+ assert.EqualValues(t, cmd.prog+` a "-m msg" "it's a test" "say \"hello\""`, cmd.LogString())
- cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/")
- assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/"`, cmd.toString(true))
+ cmd = NewCommandContextNoGlobals(context.Background(), "url: https://a:b@c/", "/root/dir-a/dir-b")
+ assert.EqualValues(t, cmd.prog+` "url: https://sanitized-credential@c/" dir-a/dir-b`, cmd.LogString())
}
diff --git a/modules/git/repo.go b/modules/git/repo.go
index fc6e6e7acc..0993a4ac37 100644
--- a/modules/git/repo.go
+++ b/modules/git/repo.go
@@ -18,7 +18,6 @@ import (
"time"
"code.gitea.io/gitea/modules/proxy"
- "code.gitea.io/gitea/modules/util"
)
// GPGSettings represents the default GPG settings for this repository
@@ -160,12 +159,6 @@ func CloneWithArgs(ctx context.Context, args TrustedCmdArgs, from, to string, op
}
cmd.AddDashesAndList(from, to)
- if strings.Contains(from, "://") && strings.Contains(from, "@") {
- cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, util.SanitizeCredentialURLs(from), to, opts.Shared, opts.Mirror, opts.Depth))
- } else {
- cmd.SetDescription(fmt.Sprintf("clone branch %s from %s to %s (shared: %t, mirror: %t, depth: %d)", opts.Branch, from, to, opts.Shared, opts.Mirror, opts.Depth))
- }
-
if opts.Timeout <= 0 {
opts.Timeout = -1
}
@@ -213,12 +206,6 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
}
cmd.AddDashesAndList(remoteBranchArgs...)
- if strings.Contains(opts.Remote, "://") && strings.Contains(opts.Remote, "@") {
- cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, util.SanitizeCredentialURLs(opts.Remote), opts.Force, opts.Mirror))
- } else {
- cmd.SetDescription(fmt.Sprintf("push branch %s to %s (force: %t, mirror: %t)", opts.Branch, opts.Remote, opts.Force, opts.Mirror))
- }
-
stdout, stderr, err := cmd.RunStdString(&RunOpts{Env: opts.Env, Timeout: opts.Timeout, Dir: repoPath})
if err != nil {
if strings.Contains(stderr, "non-fast-forward") {
diff --git a/modules/graceful/manager.go b/modules/graceful/manager.go
index cac6ce62d6..433e8c4c27 100644
--- a/modules/graceful/manager.go
+++ b/modules/graceful/manager.go
@@ -9,6 +9,7 @@ import (
"sync"
"time"
+ "code.gitea.io/gitea/modules/gtprof"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
@@ -136,7 +137,7 @@ func (g *Manager) doShutdown() {
}
g.lock.Lock()
g.shutdownCtxCancel()
- atShutdownCtx := pprof.WithLabels(g.hammerCtx, pprof.Labels(LifecyclePProfLabel, "post-shutdown"))
+ atShutdownCtx := pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-shutdown"))
pprof.SetGoroutineLabels(atShutdownCtx)
for _, fn := range g.toRunAtShutdown {
go fn()
@@ -167,7 +168,7 @@ func (g *Manager) doHammerTime(d time.Duration) {
default:
log.Warn("Setting Hammer condition")
g.hammerCtxCancel()
- atHammerCtx := pprof.WithLabels(g.terminateCtx, pprof.Labels(LifecyclePProfLabel, "post-hammer"))
+ atHammerCtx := pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-hammer"))
pprof.SetGoroutineLabels(atHammerCtx)
}
g.lock.Unlock()
@@ -183,7 +184,7 @@ func (g *Manager) doTerminate() {
default:
log.Warn("Terminating")
g.terminateCtxCancel()
- atTerminateCtx := pprof.WithLabels(g.managerCtx, pprof.Labels(LifecyclePProfLabel, "post-terminate"))
+ atTerminateCtx := pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "post-terminate"))
pprof.SetGoroutineLabels(atTerminateCtx)
for _, fn := range g.toRunAtTerminate {
diff --git a/modules/graceful/manager_common.go b/modules/graceful/manager_common.go
index 15dd4406d5..7cfbdfbeb0 100644
--- a/modules/graceful/manager_common.go
+++ b/modules/graceful/manager_common.go
@@ -8,6 +8,8 @@ import (
"runtime/pprof"
"sync"
"time"
+
+ "code.gitea.io/gitea/modules/gtprof"
)
// FIXME: it seems that there is a bug when using systemd Type=notify: the "Install Page" (INSTALL_LOCK=false) doesn't notify properly.
@@ -22,12 +24,6 @@ const (
watchdogMsg systemdNotifyMsg = "WATCHDOG=1"
)
-// LifecyclePProfLabel is a label marking manager lifecycle phase
-// Making it compliant with prometheus key regex https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
-// would enable someone interested to be able to to continuously gather profiles into pyroscope.
-// Other labels for pprof (in "modules/process" package) should also follow this rule.
-const LifecyclePProfLabel = "graceful_lifecycle"
-
func statusMsg(msg string) systemdNotifyMsg {
return systemdNotifyMsg("STATUS=" + msg)
}
@@ -71,10 +67,10 @@ func (g *Manager) prepare(ctx context.Context) {
g.hammerCtx, g.hammerCtxCancel = context.WithCancel(ctx)
g.managerCtx, g.managerCtxCancel = context.WithCancel(ctx)
- g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels(LifecyclePProfLabel, "with-terminate"))
- g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels(LifecyclePProfLabel, "with-shutdown"))
- g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels(LifecyclePProfLabel, "with-hammer"))
- g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels(LifecyclePProfLabel, "with-manager"))
+ g.terminateCtx = pprof.WithLabels(g.terminateCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-terminate"))
+ g.shutdownCtx = pprof.WithLabels(g.shutdownCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-shutdown"))
+ g.hammerCtx = pprof.WithLabels(g.hammerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-hammer"))
+ g.managerCtx = pprof.WithLabels(g.managerCtx, pprof.Labels(gtprof.LabelGracefulLifecycle, "with-manager"))
if !g.setStateTransition(stateInit, stateRunning) {
panic("invalid graceful manager state: transition from init to running failed")
diff --git a/modules/gtprof/gtprof.go b/modules/gtprof/gtprof.go
new file mode 100644
index 0000000000..974b2c9757
--- /dev/null
+++ b/modules/gtprof/gtprof.go
@@ -0,0 +1,25 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package gtprof
+
+// This is a Gitea-specific profiling package,
+// the name is chosen to distinguish it from the standard pprof tool and "GNU gprof"
+
+// LabelGracefulLifecycle is a label marking manager lifecycle phase
+// Making it compliant with prometheus key regex https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
+// would enable someone interested to be able to continuously gather profiles into pyroscope.
+// Other labels for pprof should also follow this rule.
+const LabelGracefulLifecycle = "graceful_lifecycle"
+
+// LabelPid is a label set on goroutines that have a process attached
+const LabelPid = "pid"
+
+// LabelPpid is a label set on goroutines that have a process attached
+const LabelPpid = "ppid"
+
+// LabelProcessType is a label set on goroutines that have a process attached
+const LabelProcessType = "process_type"
+
+// LabelProcessDescription is a label set on goroutines that have a process attached
+const LabelProcessDescription = "process_description"
diff --git a/modules/log/event_format.go b/modules/log/event_format.go
index 0b8d1cec79..8fda0a4980 100644
--- a/modules/log/event_format.go
+++ b/modules/log/event_format.go
@@ -13,10 +13,9 @@ import (
type Event struct {
Time time.Time
- GoroutinePid string
- Caller string
- Filename string
- Line int
+ Caller string
+ Filename string
+ Line int
Level Level
@@ -218,17 +217,16 @@ func EventFormatTextMessage(mode *WriterMode, event *Event, msgFormat string, ms
}
if flags&Lgopid == Lgopid {
- if event.GoroutinePid != "" {
- buf = append(buf, '[')
- if mode.Colorize {
- buf = append(buf, ColorBytes(FgHiYellow)...)
- }
- buf = append(buf, event.GoroutinePid...)
- if mode.Colorize {
- buf = append(buf, resetBytes...)
- }
- buf = append(buf, ']', ' ')
+ deprecatedGoroutinePid := "no-gopid" // use a dummy value to avoid breaking the log format
+ buf = append(buf, '[')
+ if mode.Colorize {
+ buf = append(buf, ColorBytes(FgHiYellow)...)
+ }
+ buf = append(buf, deprecatedGoroutinePid...)
+ if mode.Colorize {
+ buf = append(buf, resetBytes...)
}
+ buf = append(buf, ']', ' ')
}
buf = append(buf, msg...)
diff --git a/modules/log/event_format_test.go b/modules/log/event_format_test.go
index 7c299a607d..6fd0f36d48 100644
--- a/modules/log/event_format_test.go
+++ b/modules/log/event_format_test.go
@@ -24,34 +24,32 @@ func TestItoa(t *testing.T) {
func TestEventFormatTextMessage(t *testing.T) {
res := EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: false, Flags: Flags{defined: true, flags: 0xffffffff}},
&Event{
- Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
- Caller: "caller",
- Filename: "filename",
- Line: 123,
- GoroutinePid: "pid",
- Level: ERROR,
- Stacktrace: "stacktrace",
+ Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
+ Caller: "caller",
+ Filename: "filename",
+ Line: 123,
+ Level: ERROR,
+ Stacktrace: "stacktrace",
},
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
)
- assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [pid] msg format: arg0 arg1
+ assert.Equal(t, `[PREFIX] 2020/01/02 03:04:05.000000 filename:123:caller [E] [no-gopid] msg format: arg0 arg1
stacktrace
`, string(res))
res = EventFormatTextMessage(&WriterMode{Prefix: "[PREFIX] ", Colorize: true, Flags: Flags{defined: true, flags: 0xffffffff}},
&Event{
- Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
- Caller: "caller",
- Filename: "filename",
- Line: 123,
- GoroutinePid: "pid",
- Level: ERROR,
- Stacktrace: "stacktrace",
+ Time: time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC),
+ Caller: "caller",
+ Filename: "filename",
+ Line: 123,
+ Level: ERROR,
+ Stacktrace: "stacktrace",
},
"msg format: %v %v", "arg0", NewColoredValue("arg1", FgBlue),
)
- assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mpid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
+ assert.Equal(t, "[PREFIX] \x1b[36m2020/01/02 03:04:05.000000 \x1b[0m\x1b[32mfilename:123:\x1b[32mcaller\x1b[0m \x1b[1;31m[E]\x1b[0m [\x1b[93mno-gopid\x1b[0m] msg format: arg0 \x1b[34marg1\x1b[0m\n\tstacktrace\n\n", string(res))
}
diff --git a/modules/log/flags.go b/modules/log/flags.go
index f025159d53..8064c91745 100644
--- a/modules/log/flags.go
+++ b/modules/log/flags.go
@@ -30,7 +30,7 @@ const (
LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
Llevelinitial // Initial character of the provided level in brackets, eg. [I] for info
Llevel // Provided level in brackets [INFO]
- Lgopid // the Goroutine-PID of the context
+ Lgopid // the Goroutine-PID of the context, deprecated and it is always a const value
Lmedfile = Lshortfile | Llongfile // last 20 characters of the filename
LstdFlags = Ldate | Ltime | Lmedfile | Lshortfuncname | Llevelinitial // default
diff --git a/modules/log/groutinelabel.go b/modules/log/groutinelabel.go
deleted file mode 100644
index 56d7af42da..0000000000
--- a/modules/log/groutinelabel.go
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-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
deleted file mode 100644
index 34e99653d6..0000000000
--- a/modules/log/groutinelabel_test.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2022 The Gitea Authors. All rights reserved.
-// SPDX-License-Identifier: MIT
-
-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/logger_impl.go b/modules/log/logger_impl.go
index d38c6516ed..76dd5f43fb 100644
--- a/modules/log/logger_impl.go
+++ b/modules/log/logger_impl.go
@@ -200,11 +200,6 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) {
event.Stacktrace = Stack(skip + 1)
}
- labels := getGoroutineLabels()
- if labels != nil {
- event.GoroutinePid = labels["pid"]
- }
-
// get a simple text message without color
msgArgs := make([]any, len(logArgs))
copy(msgArgs, logArgs)
diff --git a/modules/process/manager.go b/modules/process/manager.go
index 7b8ada786e..661511ce8d 100644
--- a/modules/process/manager.go
+++ b/modules/process/manager.go
@@ -11,6 +11,8 @@ import (
"sync"
"sync/atomic"
"time"
+
+ "code.gitea.io/gitea/modules/gtprof"
)
// TODO: This packages still uses a singleton for the Manager.
@@ -25,18 +27,6 @@ var (
DefaultContext = context.Background()
)
-// DescriptionPProfLabel is a label set on goroutines that have a process attached
-const DescriptionPProfLabel = "process_description"
-
-// PIDPProfLabel is a label set on goroutines that have a process attached
-const PIDPProfLabel = "pid"
-
-// PPIDPProfLabel is a label set on goroutines that have a process attached
-const PPIDPProfLabel = "ppid"
-
-// ProcessTypePProfLabel is a label set on goroutines that have a process attached
-const ProcessTypePProfLabel = "process_type"
-
// IDType is a pid type
type IDType string
@@ -187,7 +177,12 @@ func (pm *Manager) Add(ctx context.Context, description string, cancel context.C
Trace(true, pid, description, parentPID, processType)
- pprofCtx := pprof.WithLabels(ctx, pprof.Labels(DescriptionPProfLabel, description, PPIDPProfLabel, string(parentPID), PIDPProfLabel, string(pid), ProcessTypePProfLabel, processType))
+ pprofCtx := pprof.WithLabels(ctx, pprof.Labels(
+ gtprof.LabelProcessDescription, description,
+ gtprof.LabelPpid, string(parentPID),
+ gtprof.LabelPid, string(pid),
+ gtprof.LabelProcessType, processType,
+ ))
if currentlyRunning {
pprof.SetGoroutineLabels(pprofCtx)
}
diff --git a/modules/process/manager_stacktraces.go b/modules/process/manager_stacktraces.go
index e260893113..d83060f6ee 100644
--- a/modules/process/manager_stacktraces.go
+++ b/modules/process/manager_stacktraces.go
@@ -10,6 +10,8 @@ import (
"sort"
"time"
+ "code.gitea.io/gitea/modules/gtprof"
+
"github.com/google/pprof/profile"
)
@@ -202,7 +204,7 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
// Add the non-process associated labels from the goroutine sample to the Stack
for name, value := range sample.Label {
- if name == DescriptionPProfLabel || name == PIDPProfLabel || (!flat && name == PPIDPProfLabel) || name == ProcessTypePProfLabel {
+ if name == gtprof.LabelProcessDescription || name == gtprof.LabelPid || (!flat && name == gtprof.LabelPpid) || name == gtprof.LabelProcessType {
continue
}
@@ -224,7 +226,7 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
var process *Process
// Try to get the PID from the goroutine labels
- if pidvalue, ok := sample.Label[PIDPProfLabel]; ok && len(pidvalue) == 1 {
+ if pidvalue, ok := sample.Label[gtprof.LabelPid]; ok && len(pidvalue) == 1 {
pid := IDType(pidvalue[0])
// Now try to get the process from our map
@@ -238,20 +240,20 @@ func (pm *Manager) ProcessStacktraces(flat, noSystem bool) ([]*Process, int, int
// get the parent PID
ppid := IDType("")
- if value, ok := sample.Label[PPIDPProfLabel]; ok && len(value) == 1 {
+ if value, ok := sample.Label[gtprof.LabelPpid]; ok && len(value) == 1 {
ppid = IDType(value[0])
}
// format the description
description := "(dead process)"
- if value, ok := sample.Label[DescriptionPProfLabel]; ok && len(value) == 1 {
+ if value, ok := sample.Label[gtprof.LabelProcessDescription]; ok && len(value) == 1 {
description = value[0] + " " + description
}
// override the type of the process to "code" but add the old type as a label on the first stack
ptype := NoneProcessType
- if value, ok := sample.Label[ProcessTypePProfLabel]; ok && len(value) == 1 {
- stack.Labels = append(stack.Labels, &Label{Name: ProcessTypePProfLabel, Value: value[0]})
+ if value, ok := sample.Label[gtprof.LabelProcessType]; ok && len(value) == 1 {
+ stack.Labels = append(stack.Labels, &Label{Name: gtprof.LabelProcessType, Value: value[0]})
}
process = &Process{
PID: pid,
diff --git a/modules/queue/workerqueue.go b/modules/queue/workerqueue.go
index 672e9a4114..0f5b105551 100644
--- a/modules/queue/workerqueue.go
+++ b/modules/queue/workerqueue.go
@@ -6,6 +6,7 @@ package queue
import (
"context"
"fmt"
+ "runtime/pprof"
"sync"
"sync/atomic"
"time"
@@ -241,6 +242,9 @@ func NewWorkerPoolQueueWithContext[T any](ctx context.Context, name string, queu
w.origHandler = handler
w.safeHandler = func(t ...T) (unhandled []T) {
defer func() {
+ // FIXME: there is no ctx support in the handler, so process manager is unable to restore the labels
+ // so here we explicitly set the "queue ctx" labels again after the handler is done
+ pprof.SetGoroutineLabels(w.ctxRun)
err := recover()
if err != nil {
log.Error("Recovered from panic in queue %q handler: %v\n%s", name, err, log.Stack(2))
diff --git a/modules/util/runtime.go b/modules/util/runtime.go
new file mode 100644
index 0000000000..91ec3c869c
--- /dev/null
+++ b/modules/util/runtime.go
@@ -0,0 +1,13 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package util
+
+import "runtime"
+
+func CallerFuncName(skip int) string {
+ pc := make([]uintptr, 1)
+ runtime.Callers(skip+1, pc)
+ funcName := runtime.FuncForPC(pc[0]).Name()
+ return funcName
+}
diff --git a/modules/util/runtime_test.go b/modules/util/runtime_test.go
new file mode 100644
index 0000000000..20f9063b0b
--- /dev/null
+++ b/modules/util/runtime_test.go
@@ -0,0 +1,32 @@
+// Copyright 2024 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package util
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestCallerFuncName(t *testing.T) {
+ s := CallerFuncName(1)
+ assert.Equal(t, "code.gitea.io/gitea/modules/util.TestCallerFuncName", s)
+}
+
+func BenchmarkCallerFuncName(b *testing.B) {
+ // BenchmarkCaller/sprintf-12 12744829 95.49 ns/op
+ b.Run("sprintf", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _ = fmt.Sprintf("aaaaaaaaaaaaaaaa %s %s %s", "bbbbbbbbbbbbbbbbbbb", b.Name(), "ccccccccccccccccccccc")
+ }
+ })
+ // BenchmarkCaller/caller-12 10625133 113.6 ns/op
+ // It is almost as fast as fmt.Sprintf
+ b.Run("caller", func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ CallerFuncName(1)
+ }
+ })
+}