summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authorGusted <postmaster@gusted.xyz>2025-01-02 03:43:58 +0100
committerGusted <postmaster@gusted.xyz>2025-01-05 04:07:49 +0100
commit3f44b97b5f39ad3e8dd923528e8acd28a6f073b3 (patch)
tree9b7394b15f7d602bdea3d17896871cf748a12a37 /routers
parentchore: avoid trying to stream data (diff)
downloadforgejo-3f44b97b5f39ad3e8dd923528e8acd28a6f073b3.tar.xz
forgejo-3f44b97b5f39ad3e8dd923528e8acd28a6f073b3.zip
feat: add limited execution tracing support
- For every process that is spawned (every new non-trivial goroutine such as http requests, queues or tasks) start a [execution tracer](https://pkg.go.dev/runtime/trace). This allows very precise diagnosis of how each individual process over a time period. - It's safe and [fast](https://go.dev/blog/execution-traces-2024#low-overhead-tracing) to be run in production, hence no setting to disable this. There's only noticable overhead when tracing is actually performed and not continuous. - Proper tracing support would mean the codebase would be full of `trace.WithRegion` and `trace.Log`, which feels premature for this patch as there's no real-world usage yet to indicate which places would need this the most. So far only Git commands and SQL queries receive somewhat proper tracing support given that these are used throughout the codebase. - Make git commands a new process type. - Add tracing to diagnosis zip file.
Diffstat (limited to 'routers')
-rw-r--r--routers/common/middleware.go3
-rw-r--r--routers/web/admin/diagnosis.go33
2 files changed, 24 insertions, 12 deletions
diff --git a/routers/common/middleware.go b/routers/common/middleware.go
index 59e59b8d3f..ebc4d62d03 100644
--- a/routers/common/middleware.go
+++ b/routers/common/middleware.go
@@ -6,6 +6,7 @@ package common
import (
"fmt"
"net/http"
+ "runtime/trace"
"strings"
"code.gitea.io/gitea/modules/cache"
@@ -43,6 +44,8 @@ func ProtocolMiddlewares() (handlers []any) {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
ctx, _, finished := process.GetManager().AddTypedContext(req.Context(), fmt.Sprintf("%s: %s", req.Method, req.RequestURI), process.RequestProcessType, true)
defer finished()
+ trace.Log(ctx, "method", req.Method)
+ trace.Log(ctx, "url", req.RequestURI)
next.ServeHTTP(context.WrapResponseWriter(resp), req.WithContext(cache.WithCacheContext(ctx)))
})
})
diff --git a/routers/web/admin/diagnosis.go b/routers/web/admin/diagnosis.go
index 020554a35a..1c12259b06 100644
--- a/routers/web/admin/diagnosis.go
+++ b/routers/web/admin/diagnosis.go
@@ -7,6 +7,7 @@ import (
"archive/zip"
"fmt"
"runtime/pprof"
+ "runtime/trace"
"time"
"code.gitea.io/gitea/modules/httplib"
@@ -15,17 +16,12 @@ import (
func MonitorDiagnosis(ctx *context.Context) {
seconds := ctx.FormInt64("seconds")
- if seconds <= 5 {
- seconds = 5
- }
- if seconds > 300 {
- seconds = 300
- }
+ seconds = max(5, min(300, seconds))
httplib.ServeSetHeaders(ctx.Resp, &httplib.ServeHeaderOptions{
ContentType: "application/zip",
Disposition: "attachment",
- Filename: fmt.Sprintf("gitea-diagnosis-%s.zip", time.Now().Format("20060102-150405")),
+ Filename: fmt.Sprintf("forgejo-diagnosis-%s.zip", time.Now().Format("20060102-150405")),
})
zipWriter := zip.NewWriter(ctx.Resp)
@@ -44,14 +40,27 @@ func MonitorDiagnosis(ctx *context.Context) {
return
}
- err = pprof.StartCPUProfile(f)
- if err == nil {
- time.Sleep(time.Duration(seconds) * time.Second)
- pprof.StopCPUProfile()
- } else {
+ if err := pprof.StartCPUProfile(f); err != nil {
+ _, _ = f.Write([]byte(err.Error()))
+ }
+
+ f, err = zipWriter.CreateHeader(&zip.FileHeader{Name: "trace.dat", Method: zip.Deflate, Modified: time.Now()})
+ if err != nil {
+ ctx.ServerError("Failed to create zip file", err)
+ return
+ }
+
+ if err := trace.Start(f); err != nil {
_, _ = f.Write([]byte(err.Error()))
}
+ select {
+ case <-time.After(time.Duration(seconds) * time.Second):
+ case <-ctx.Done():
+ }
+ pprof.StopCPUProfile()
+ trace.Stop()
+
f, err = zipWriter.CreateHeader(&zip.FileHeader{Name: "goroutine-after.txt", Method: zip.Deflate, Modified: time.Now()})
if err != nil {
ctx.ServerError("Failed to create zip file", err)