code.gitea.io/gitea@v1.21.7/routers/private/manager_process.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package private 5 6 import ( 7 "bytes" 8 "fmt" 9 "io" 10 "net/http" 11 "runtime" 12 "time" 13 14 "code.gitea.io/gitea/modules/context" 15 "code.gitea.io/gitea/modules/log" 16 "code.gitea.io/gitea/modules/private" 17 process_module "code.gitea.io/gitea/modules/process" 18 ) 19 20 // Processes prints out the processes 21 func Processes(ctx *context.PrivateContext) { 22 pid := ctx.FormString("cancel-pid") 23 if pid != "" { 24 process_module.GetManager().Cancel(process_module.IDType(pid)) 25 runtime.Gosched() 26 time.Sleep(100 * time.Millisecond) 27 } 28 29 flat := ctx.FormBool("flat") 30 noSystem := ctx.FormBool("no-system") 31 stacktraces := ctx.FormBool("stacktraces") 32 json := ctx.FormBool("json") 33 34 var processes []*process_module.Process 35 goroutineCount := int64(0) 36 var processCount int 37 var err error 38 if stacktraces { 39 processes, processCount, goroutineCount, err = process_module.GetManager().ProcessStacktraces(flat, noSystem) 40 if err != nil { 41 log.Error("Unable to get stacktrace: %v", err) 42 ctx.JSON(http.StatusInternalServerError, private.Response{ 43 Err: fmt.Sprintf("Failed to get stacktraces: %v", err), 44 }) 45 return 46 } 47 } else { 48 processes, processCount = process_module.GetManager().Processes(flat, noSystem) 49 } 50 51 if json { 52 ctx.JSON(http.StatusOK, map[string]any{ 53 "TotalNumberOfGoroutines": goroutineCount, 54 "TotalNumberOfProcesses": processCount, 55 "Processes": processes, 56 }) 57 return 58 } 59 60 ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8") 61 ctx.Resp.WriteHeader(http.StatusOK) 62 63 if err := writeProcesses(ctx.Resp, processes, processCount, goroutineCount, "", flat); err != nil { 64 log.Error("Unable to write out process stacktrace: %v", err) 65 if !ctx.Written() { 66 ctx.JSON(http.StatusInternalServerError, private.Response{ 67 Err: fmt.Sprintf("Failed to get stacktraces: %v", err), 68 }) 69 } 70 return 71 } 72 } 73 74 func writeProcesses(out io.Writer, processes []*process_module.Process, processCount int, goroutineCount int64, indent string, flat bool) error { 75 if goroutineCount > 0 { 76 if _, err := fmt.Fprintf(out, "%sTotal Number of Goroutines: %d\n", indent, goroutineCount); err != nil { 77 return err 78 } 79 } 80 if _, err := fmt.Fprintf(out, "%sTotal Number of Processes: %d\n", indent, processCount); err != nil { 81 return err 82 } 83 if len(processes) > 0 { 84 if err := writeProcess(out, processes[0], " ", flat); err != nil { 85 return err 86 } 87 } 88 if len(processes) > 1 { 89 for _, process := range processes[1:] { 90 if _, err := fmt.Fprintf(out, "%s | \n", indent); err != nil { 91 return err 92 } 93 if err := writeProcess(out, process, " ", flat); err != nil { 94 return err 95 } 96 } 97 } 98 return nil 99 } 100 101 func writeProcess(out io.Writer, process *process_module.Process, indent string, flat bool) error { 102 sb := &bytes.Buffer{} 103 if flat { 104 if process.ParentPID != "" { 105 _, _ = fmt.Fprintf(sb, "%s+ PID: %s\t\tType: %s\n", indent, process.PID, process.Type) 106 } else { 107 _, _ = fmt.Fprintf(sb, "%s+ PID: %s:%s\tType: %s\n", indent, process.ParentPID, process.PID, process.Type) 108 } 109 } else { 110 _, _ = fmt.Fprintf(sb, "%s+ PID: %s\tType: %s\n", indent, process.PID, process.Type) 111 } 112 indent += "| " 113 114 _, _ = fmt.Fprintf(sb, "%sDescription: %s\n", indent, process.Description) 115 _, _ = fmt.Fprintf(sb, "%sStart: %s\n", indent, process.Start) 116 117 if len(process.Stacks) > 0 { 118 _, _ = fmt.Fprintf(sb, "%sGoroutines:\n", indent) 119 for _, stack := range process.Stacks { 120 indent := indent + " " 121 _, _ = fmt.Fprintf(sb, "%s+ Description: %s", indent, stack.Description) 122 if stack.Count > 1 { 123 _, _ = fmt.Fprintf(sb, "* %d", stack.Count) 124 } 125 _, _ = fmt.Fprintf(sb, "\n") 126 indent += "| " 127 if len(stack.Labels) > 0 { 128 _, _ = fmt.Fprintf(sb, "%sLabels: %q:%q", indent, stack.Labels[0].Name, stack.Labels[0].Value) 129 130 if len(stack.Labels) > 1 { 131 for _, label := range stack.Labels[1:] { 132 _, _ = fmt.Fprintf(sb, ", %q:%q", label.Name, label.Value) 133 } 134 } 135 _, _ = fmt.Fprintf(sb, "\n") 136 } 137 _, _ = fmt.Fprintf(sb, "%sStack:\n", indent) 138 indent += " " 139 for _, entry := range stack.Entry { 140 _, _ = fmt.Fprintf(sb, "%s+ %s\n", indent, entry.Function) 141 _, _ = fmt.Fprintf(sb, "%s| %s:%d\n", indent, entry.File, entry.Line) 142 } 143 } 144 } 145 if _, err := out.Write(sb.Bytes()); err != nil { 146 return err 147 } 148 sb.Reset() 149 if len(process.Children) > 0 { 150 if _, err := fmt.Fprintf(out, "%sChildren:\n", indent); err != nil { 151 return err 152 } 153 for _, child := range process.Children { 154 if err := writeProcess(out, child, indent+" ", flat); err != nil { 155 return err 156 } 157 } 158 } 159 return nil 160 }