-
-
Notifications
You must be signed in to change notification settings - Fork 5.9k
Add PProf to admin pages and to gitea manager
#22742
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 5 commits
Commits
Show all changes
34 commits
Select commit
Hold shift + click to select a range
5093d7d
Add PProf to admin pages
zeripath 9cfcbb4
Update pprof.tmpl
zeripath f22aa21
Update locale_en-US.ini
zeripath b9989b1
Add FGProf handler
zeripath 6451d01
wire in PProfFGProfile
zeripath 351149b
Wire in FGProf
zeripath 7941fbb
Update locale_en-US.ini
zeripath 0ef07f6
Update pprof.tmpl
zeripath 8d0d93e
Update pprof.go
zeripath 768a960
Update pprof.go
zeripath 82169ca
Update web.go
zeripath ba894a1
Update pprof.go
zeripath 75d96e8
Update pprof.tmpl
zeripath 381f12a
Update pprof.tmpl
zeripath 2fc5d72
Update locale_en-US.ini
zeripath 79756cd
placate lint
zeripath 6247e72
Add pprof endpoints to manager too
zeripath d9eac18
add documentation
zeripath 7decd93
Add output option
zeripath 4d916b4
fix missing name
zeripath b9942cb
add trace and fix format
zeripath 7c4be9c
fix format on stacktraces
zeripath 6c2017d
fix trace
zeripath d37978e
Apply suggestions from code review
zeripath 950c474
Merge remote-tracking branch 'origin/main' into add-pprof-to-admin-pages
zeripath 2dbab58
as per delvh
zeripath 2b523f1
include indent in WriteProcess
zeripath 5925f47
as per delvh
zeripath 91bc97a
remove space
zeripath 61755a7
as per delvh
zeripath 1400ab2
as per delvh
zeripath edebd86
add some comments
zeripath 1ffe696
Merge remote-tracking branch 'origin/main' into add-pprof-to-admin-pages
zeripath 92ac295
move trace help in to the ui form
zeripath File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
// Copyright 2023 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package process | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io" | ||
) | ||
|
||
// WriteProcesses writes out processes to a provided writer | ||
func WriteProcesses(out io.Writer, processes []*Process, processCount int, goroutineCount int64, indent string, flat bool) error { | ||
if goroutineCount > 0 { | ||
if _, err := fmt.Fprintf(out, "%sTotal Number of Goroutines: %d\n", indent, goroutineCount); err != nil { | ||
return err | ||
} | ||
} | ||
if _, err := fmt.Fprintf(out, "%sTotal Number of Processes: %d\n", indent, processCount); err != nil { | ||
return err | ||
} | ||
if len(processes) > 0 { | ||
if err := WriteProcess(out, processes[0], " ", flat); err != nil { | ||
return err | ||
} | ||
} | ||
if len(processes) > 1 { | ||
for _, process := range processes[1:] { | ||
if _, err := fmt.Fprintf(out, "%s | \n", indent); err != nil { | ||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return err | ||
} | ||
if err := WriteProcess(out, process, " ", flat); err != nil { | ||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return err | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// WriteProcess writes out a process to a provided writer | ||
func WriteProcess(out io.Writer, process *Process, indent string, flat bool) error { | ||
sb := &bytes.Buffer{} | ||
if flat { | ||
if process.ParentPID != "" { | ||
_, _ = fmt.Fprintf(sb, "%s+ PID: %s\t\tType: %s\n", indent, process.PID, process.Type) | ||
} else { | ||
_, _ = fmt.Fprintf(sb, "%s+ PID: %s:%s\tType: %s\n", indent, process.ParentPID, process.PID, process.Type) | ||
} | ||
} else { | ||
_, _ = fmt.Fprintf(sb, "%s+ PID: %s\tType: %s\n", indent, process.PID, process.Type) | ||
} | ||
indent += "| " | ||
|
||
_, _ = fmt.Fprintf(sb, "%sDescription: %s\n", indent, process.Description) | ||
_, _ = fmt.Fprintf(sb, "%sStart: %s\n", indent, process.Start) | ||
|
||
if len(process.Stacks) > 0 { | ||
_, _ = fmt.Fprintf(sb, "%sGoroutines:\n", indent) | ||
for _, stack := range process.Stacks { | ||
indent := indent + " " | ||
_, _ = fmt.Fprintf(sb, "%s+ Description: %s", indent, stack.Description) | ||
if stack.Count > 1 { | ||
_, _ = fmt.Fprintf(sb, "* %d", stack.Count) | ||
} | ||
_, _ = fmt.Fprintf(sb, "\n") | ||
indent += "| " | ||
if len(stack.Labels) > 0 { | ||
_, _ = fmt.Fprintf(sb, "%sLabels: %q:%q", indent, stack.Labels[0].Name, stack.Labels[0].Value) | ||
|
||
if len(stack.Labels) > 1 { | ||
for _, label := range stack.Labels[1:] { | ||
_, _ = fmt.Fprintf(sb, ", %q:%q", label.Name, label.Value) | ||
} | ||
} | ||
_, _ = fmt.Fprintf(sb, "\n") | ||
} | ||
_, _ = fmt.Fprintf(sb, "%sStack:\n", indent) | ||
indent += " " | ||
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
zeripath marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for _, entry := range stack.Entry { | ||
_, _ = fmt.Fprintf(sb, "%s+ %s\n", indent, entry.Function) | ||
_, _ = fmt.Fprintf(sb, "%s| %s:%d\n", indent, entry.File, entry.Line) | ||
} | ||
} | ||
} | ||
if _, err := out.Write(sb.Bytes()); err != nil { | ||
return err | ||
} | ||
sb.Reset() | ||
if len(process.Children) > 0 { | ||
if _, err := fmt.Fprintf(out, "%sChildren:\n", indent); err != nil { | ||
return err | ||
} | ||
for _, child := range process.Children { | ||
if err := WriteProcess(out, child, indent+" ", flat); err != nil { | ||
return err | ||
} | ||
} | ||
} | ||
return nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
// Copyright 2022 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package admin | ||
|
||
import ( | ||
"fmt" | ||
"runtime/pprof" | ||
"strconv" | ||
"time" | ||
|
||
"code.gitea.io/gitea/modules/context" | ||
"code.gitea.io/gitea/modules/setting" | ||
|
||
"github.com/felixge/fgprof" | ||
) | ||
|
||
// PProfFGProfile returns the Full Go Profile from fgprof | ||
func PProfFGProfile(ctx *context.Context) { | ||
durationStr := ctx.FormString("duration") | ||
duration := 30 * time.Second | ||
if durationStr != "" { | ||
var err error | ||
duration, err = time.ParseDuration(durationStr) | ||
if err != nil { | ||
ctx.Flash.Error(ctx.Tr("monitor.pprof.cpuprofile.duration_invalid")) | ||
ctx.Redirect(setting.AppSubURL + "/admin/monitor") | ||
return | ||
} | ||
} | ||
|
||
format := ctx.FormString("format") | ||
if format != fgprof.FormatFolded { | ||
format = fgprof.FormatPprof | ||
} | ||
delvh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
start := time.Now() | ||
|
||
ctx.SetServeHeaders(&context.ServeHeaderOptions{ | ||
Filename: "fgprof-profile-" + strconv.FormatInt(start.Unix(), 10), | ||
LastModified: start, | ||
}) | ||
|
||
fn := fgprof.Start(ctx.Resp, format) | ||
|
||
select { | ||
case <-time.After(duration): | ||
case <-ctx.Done(): | ||
} | ||
|
||
err := fn() | ||
if err != nil { | ||
ctx.ServerError("fgprof.Write", err) | ||
} | ||
} | ||
|
||
|
||
// PProfCPUProfile returns the PProf CPU Profile | ||
func PProfCPUProfile(ctx *context.Context) { | ||
durationStr := ctx.FormString("duration") | ||
duration := 30 * time.Second | ||
if durationStr != "" { | ||
var err error | ||
duration, err = time.ParseDuration(durationStr) | ||
if err != nil { | ||
ctx.Flash.Error(ctx.Tr("monitor.pprof.cpuprofile.duration_invalid")) | ||
ctx.Redirect(setting.AppSubURL + "/admin/monitor") | ||
return | ||
} | ||
} | ||
|
||
start := time.Now() | ||
|
||
ctx.SetServeHeaders(&context.ServeHeaderOptions{ | ||
Filename: "cpu-profile-" + strconv.FormatInt(start.Unix(), 10), | ||
LastModified: start, | ||
}) | ||
|
||
err := pprof.StartCPUProfile(ctx.Resp) | ||
if err != nil { | ||
ctx.ServerError("StartCPUProfile", err) | ||
return | ||
} | ||
|
||
select { | ||
case <-time.After(duration): | ||
case <-ctx.Done(): | ||
} | ||
pprof.StopCPUProfile() | ||
} | ||
|
||
// PProfNamedProfile returns the PProf Profile | ||
func PProfNamedProfile(ctx *context.Context) { | ||
name := ctx.FormString("name") | ||
profile := pprof.Lookup(name) | ||
if profile == nil { | ||
ctx.ServerError(fmt.Sprintf("pprof.Lookup(%s)", name), fmt.Errorf("missing profile: %s", name)) | ||
return | ||
} | ||
|
||
debug := ctx.FormInt("debug") | ||
|
||
start := time.Now() | ||
|
||
ctx.SetServeHeaders(&context.ServeHeaderOptions{ | ||
Filename: name + "-profile-" + strconv.FormatInt(start.Unix(), 10), | ||
LastModified: start, | ||
}) | ||
if err := profile.WriteTo(ctx.Resp, debug); err != nil { | ||
ctx.ServerError(fmt.Sprintf("PProfNamedProfile(%s).WriteTo", name), err) | ||
return | ||
delvh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.