github.com/sagernet/sing-box@v1.9.0-rc.20/debug_http.go (about)

     1  package box
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/pprof"
     6  	"runtime"
     7  	"runtime/debug"
     8  	"strings"
     9  
    10  	"github.com/sagernet/sing-box/common/humanize"
    11  	"github.com/sagernet/sing-box/log"
    12  	"github.com/sagernet/sing-box/option"
    13  	E "github.com/sagernet/sing/common/exceptions"
    14  	"github.com/sagernet/sing/common/json"
    15  	"github.com/sagernet/sing/common/json/badjson"
    16  
    17  	"github.com/go-chi/chi/v5"
    18  )
    19  
    20  var debugHTTPServer *http.Server
    21  
    22  func applyDebugListenOption(options option.DebugOptions) {
    23  	if debugHTTPServer != nil {
    24  		debugHTTPServer.Close()
    25  		debugHTTPServer = nil
    26  	}
    27  	if options.Listen == "" {
    28  		return
    29  	}
    30  	r := chi.NewMux()
    31  	r.Route("/debug", func(r chi.Router) {
    32  		r.Get("/gc", func(writer http.ResponseWriter, request *http.Request) {
    33  			writer.WriteHeader(http.StatusNoContent)
    34  			go debug.FreeOSMemory()
    35  		})
    36  		r.Get("/memory", func(writer http.ResponseWriter, request *http.Request) {
    37  			var memStats runtime.MemStats
    38  			runtime.ReadMemStats(&memStats)
    39  
    40  			var memObject badjson.JSONObject
    41  			memObject.Put("heap", humanize.MemoryBytes(memStats.HeapInuse))
    42  			memObject.Put("stack", humanize.MemoryBytes(memStats.StackInuse))
    43  			memObject.Put("idle", humanize.MemoryBytes(memStats.HeapIdle-memStats.HeapReleased))
    44  			memObject.Put("goroutines", runtime.NumGoroutine())
    45  			memObject.Put("rss", rusageMaxRSS())
    46  
    47  			encoder := json.NewEncoder(writer)
    48  			encoder.SetIndent("", "  ")
    49  			encoder.Encode(memObject)
    50  		})
    51  		r.Route("/pprof", func(r chi.Router) {
    52  			r.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
    53  				if !strings.HasSuffix(request.URL.Path, "/") {
    54  					http.Redirect(writer, request, request.URL.Path+"/", http.StatusMovedPermanently)
    55  				} else {
    56  					pprof.Index(writer, request)
    57  				}
    58  			})
    59  			r.HandleFunc("/*", pprof.Index)
    60  			r.HandleFunc("/cmdline", pprof.Cmdline)
    61  			r.HandleFunc("/profile", pprof.Profile)
    62  			r.HandleFunc("/symbol", pprof.Symbol)
    63  			r.HandleFunc("/trace", pprof.Trace)
    64  		})
    65  	})
    66  	debugHTTPServer = &http.Server{
    67  		Addr:    options.Listen,
    68  		Handler: r,
    69  	}
    70  	go func() {
    71  		err := debugHTTPServer.ListenAndServe()
    72  		if err != nil && !E.IsClosed(err) {
    73  			log.Error(E.Cause(err, "serve debug HTTP server"))
    74  		}
    75  	}()
    76  }