package unix import ( "fmt" "net" "net/http" "os" "path/filepath" "time" "linkfog.com/public/lib/l" "linkfog.com/public/lib/pprof/runtime" "linkfog.com/public/option" ) const defaultCollectDura = time.Minute type pprof struct { unixSocketPath string pprofProfilePath string listener net.Listener collectDura time.Duration } func New() *pprof { socketPath := filepath.Join(option.HostPrefix, option.NamespacePrefix, option.PProfPrefix, "pprof.sock") pprofProfilePath := filepath.Join(option.HostPrefix, option.NamespacePrefix, option.PProfPrefix) return NewUnix(socketPath, pprofProfilePath) } func NewUnix(socketPath, profilePath string) *pprof { return &pprof{ unixSocketPath: socketPath, pprofProfilePath: profilePath, collectDura: time.Minute, } } func (up *pprof) Start() { l.Info("start unix pprof") err := os.Remove(up.unixSocketPath) if err != nil { // err != os.ErrNotExist if os.IsNotExist(err) { l.Debug(err) } else { l.Error(err) } } go up.start() } func (up *pprof) start() { if err := os.MkdirAll(filepath.Dir(up.unixSocketPath), 0755); err != nil { l.Error(err) return } listener, err := net.Listen("unix", up.unixSocketPath) if err != nil { l.Error(err) return } up.listener = listener mux := http.NewServeMux() mux.Handle("/", up) srv := &http.Server{Handler: up} if err = srv.Serve(up.listener); err != nil { l.Error(err, up.unixSocketPath) } } func (up *pprof) ServeHTTP(w http.ResponseWriter, r *http.Request) { l.Info("start unix runtime pprof", up.collectDura.String()) if err := up.setProfileDuration(r); err != nil { l.Error(err) reply(w, "间隔时间格式错误"+err.Error()+"\n正确时间参数如:'1h2m3s'") return } if err := runtime.StartProfile(runtime.ModeManual, up.pprofProfilePath, "", up.collectDura); err != nil { l.Error(err) reply(w, "性能数据采集异常"+err.Error()) return } else { reply(w, "性能数据采集结束,耗时"+up.collectDura.String()) } l.Info("end unix runtime pprof") } func reply(w http.ResponseWriter, response string) { if _, err := fmt.Fprintf(w, response); err != nil { l.Error(err) } } func (up *pprof) Stop() { _ = os.Remove(up.unixSocketPath) if up.listener != nil { _ = up.listener.Close() } } func (up *pprof) setProfileDuration(r *http.Request) (err error) { keys, ok := r.URL.Query()["time"] if !ok || len(keys[0]) < 1 { up.collectDura = defaultCollectDura } else { dur, err := time.ParseDuration(keys[0]) if err != nil { return l.WrapError(err) } up.collectDura = dur } return }