2023-04-22 07:58:25 +00:00
|
|
|
package box
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"net/http/pprof"
|
|
|
|
"runtime"
|
|
|
|
"runtime/debug"
|
2023-12-27 09:33:07 +00:00
|
|
|
"strings"
|
2023-04-22 07:58:25 +00:00
|
|
|
|
|
|
|
"github.com/sagernet/sing-box/common/badjson"
|
2023-09-20 06:12:08 +00:00
|
|
|
"github.com/sagernet/sing-box/common/humanize"
|
2023-04-22 07:58:25 +00:00
|
|
|
"github.com/sagernet/sing-box/common/json"
|
|
|
|
"github.com/sagernet/sing-box/log"
|
|
|
|
"github.com/sagernet/sing-box/option"
|
|
|
|
E "github.com/sagernet/sing/common/exceptions"
|
|
|
|
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
)
|
|
|
|
|
|
|
|
var debugHTTPServer *http.Server
|
|
|
|
|
|
|
|
func applyDebugListenOption(options option.DebugOptions) {
|
|
|
|
if debugHTTPServer != nil {
|
|
|
|
debugHTTPServer.Close()
|
|
|
|
debugHTTPServer = nil
|
|
|
|
}
|
|
|
|
if options.Listen == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
r := chi.NewMux()
|
|
|
|
r.Route("/debug", func(r chi.Router) {
|
|
|
|
r.Get("/gc", func(writer http.ResponseWriter, request *http.Request) {
|
|
|
|
writer.WriteHeader(http.StatusNoContent)
|
|
|
|
go debug.FreeOSMemory()
|
|
|
|
})
|
|
|
|
r.Get("/memory", func(writer http.ResponseWriter, request *http.Request) {
|
|
|
|
var memStats runtime.MemStats
|
|
|
|
runtime.ReadMemStats(&memStats)
|
|
|
|
|
|
|
|
var memObject badjson.JSONObject
|
2023-09-20 06:12:08 +00:00
|
|
|
memObject.Put("heap", humanize.MemoryBytes(memStats.HeapInuse))
|
|
|
|
memObject.Put("stack", humanize.MemoryBytes(memStats.StackInuse))
|
|
|
|
memObject.Put("idle", humanize.MemoryBytes(memStats.HeapIdle-memStats.HeapReleased))
|
2023-04-22 07:58:25 +00:00
|
|
|
memObject.Put("goroutines", runtime.NumGoroutine())
|
|
|
|
memObject.Put("rss", rusageMaxRSS())
|
|
|
|
|
|
|
|
encoder := json.NewEncoder(writer)
|
|
|
|
encoder.SetIndent("", " ")
|
|
|
|
encoder.Encode(memObject)
|
|
|
|
})
|
2023-12-27 09:33:07 +00:00
|
|
|
r.Route("/pprof", func(r chi.Router) {
|
|
|
|
r.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
|
|
|
if !strings.HasSuffix(request.URL.Path, "/") {
|
|
|
|
http.Redirect(writer, request, request.URL.Path+"/", http.StatusMovedPermanently)
|
|
|
|
} else {
|
|
|
|
pprof.Index(writer, request)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
r.HandleFunc("/*", pprof.Index)
|
|
|
|
r.HandleFunc("/cmdline", pprof.Cmdline)
|
|
|
|
r.HandleFunc("/profile", pprof.Profile)
|
|
|
|
r.HandleFunc("/symbol", pprof.Symbol)
|
|
|
|
r.HandleFunc("/trace", pprof.Trace)
|
|
|
|
})
|
2023-04-22 07:58:25 +00:00
|
|
|
})
|
|
|
|
debugHTTPServer = &http.Server{
|
|
|
|
Addr: options.Listen,
|
|
|
|
Handler: r,
|
|
|
|
}
|
|
|
|
go func() {
|
|
|
|
err := debugHTTPServer.ListenAndServe()
|
|
|
|
if err != nil && !E.IsClosed(err) {
|
|
|
|
log.Error(E.Cause(err, "serve debug HTTP server"))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|