chore(api): add block and goroutine profiles to support bundle (#9824)

This commit is contained in:
Jakob Borg 2024-11-16 09:43:17 +01:00 committed by GitHub
parent 110e1ae6f9
commit 7eaf843de2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1165,6 +1165,7 @@ type fileEntry struct {
func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
var files []fileEntry
const profilingDuration = 4 * time.Second
// Redacted configuration as a JSON
if jsonConfig, err := json.MarshalIndent(getRedactedConfig(s), "", " "); err != nil {
@ -1231,10 +1232,10 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
}
// Metrics data as text
buf := bytes.NewBuffer(nil)
wr := bufferedResponseWriter{Writer: buf}
var metricsBuf bytes.Buffer
wr := bufferedResponseWriter{Writer: &metricsBuf}
promhttp.Handler().ServeHTTP(wr, &http.Request{Method: http.MethodGet})
files = append(files, fileEntry{name: "metrics.txt", data: buf.Bytes()})
files = append(files, fileEntry{name: "metrics.txt", data: metricsBuf.Bytes()})
// Connection data as JSON
connStats := s.model.ConnectionStats()
@ -1244,20 +1245,42 @@ func (s *service) getSupportBundle(w http.ResponseWriter, r *http.Request) {
files = append(files, fileEntry{name: "connection-stats.json.txt", data: connStatsJSON})
}
// Heap and CPU Proofs as a pprof extension
var heapBuffer, cpuBuffer bytes.Buffer
filename := fmt.Sprintf("syncthing-heap-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
runtime.GC()
if err := pprof.WriteHeapProfile(&heapBuffer); err == nil {
files = append(files, fileEntry{name: filename, data: heapBuffer.Bytes()})
// Write a goroutine profile
if p := pprof.Lookup("goroutine"); p != nil {
var goroutineBuf bytes.Buffer
_ = p.WriteTo(&goroutineBuf, 0)
filename := fmt.Sprintf("syncthing-goroutines-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
files = append(files, fileEntry{name: filename, data: goroutineBuf.Bytes()})
}
const duration = 4 * time.Second
filename = fmt.Sprintf("syncthing-cpu-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
if err := pprof.StartCPUProfile(&cpuBuffer); err == nil {
time.Sleep(duration)
// Take a heap profile
var heapBuf bytes.Buffer
runtime.GC()
if err := pprof.WriteHeapProfile(&heapBuf); err == nil {
filename := fmt.Sprintf("syncthing-heap-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
files = append(files, fileEntry{name: filename, data: heapBuf.Bytes()})
}
// Enable block profiling
runtime.SetBlockProfileRate(1)
defer runtime.SetBlockProfileRate(0)
// Take a CPU profile, waiting for the profiling duration. This also
// gives time for the block profile.
var cpuBuf bytes.Buffer
if err := pprof.StartCPUProfile(&cpuBuf); err == nil {
time.Sleep(profilingDuration)
pprof.StopCPUProfile()
files = append(files, fileEntry{name: filename, data: cpuBuffer.Bytes()})
filename := fmt.Sprintf("syncthing-cpu-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
files = append(files, fileEntry{name: filename, data: cpuBuf.Bytes()})
}
// Write the block profile
if p := pprof.Lookup("block"); p != nil {
var blockBuf bytes.Buffer
_ = p.WriteTo(&blockBuf, 0)
filename := fmt.Sprintf("syncthing-block-%s-%s-%s-%s.pprof", runtime.GOOS, runtime.GOARCH, build.Version, time.Now().Format("150405")) // hhmmss
files = append(files, fileEntry{name: filename, data: blockBuf.Bytes()})
}
// Add buffer files to buffer zip
@ -1483,7 +1506,7 @@ func (*service) getDeviceID(w http.ResponseWriter, r *http.Request) {
func (*service) getLang(w http.ResponseWriter, r *http.Request) {
lang := r.Header.Get("Accept-Language")
var weights = make(map[string]float64)
weights := make(map[string]float64)
for _, l := range strings.Split(lang, ",") {
parts := strings.SplitN(l, ";", 2)
code := strings.ToLower(strings.TrimSpace(parts[0]))
@ -1502,7 +1525,7 @@ func (*service) getLang(w http.ResponseWriter, r *http.Request) {
weights[code] = q
}
}
var langs = make([]string, 0, len(weights))
langs := make([]string, 0, len(weights))
for code := range weights {
langs = append(langs, code)
}