github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/utils/pprof.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package utils
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"os"
    10  	"sync"
    11  
    12  	tidbutils "github.com/pingcap/tidb-tools/pkg/utils"
    13  
    14  	berrors "github.com/pingcap/br/pkg/errors"
    15  
    16  	"github.com/pingcap/errors"
    17  
    18  	// #nosec
    19  	// register HTTP handler for /debug/pprof
    20  	_ "net/http/pprof"
    21  
    22  	"github.com/pingcap/failpoint"
    23  	"github.com/pingcap/log"
    24  	"go.uber.org/zap"
    25  )
    26  
    27  var (
    28  	startedPProf = ""
    29  	mu           sync.Mutex
    30  )
    31  
    32  func listen(statusAddr string) (net.Listener, error) {
    33  	mu.Lock()
    34  	defer mu.Unlock()
    35  	if startedPProf != "" {
    36  		log.Warn("Try to start pprof when it has been started, nothing will happen", zap.String("address", startedPProf))
    37  		return nil, errors.Annotate(berrors.ErrUnknown, "try to start pprof when it has been started at "+startedPProf)
    38  	}
    39  	failpoint.Inject("determined-pprof-port", func(v failpoint.Value) {
    40  		port := v.(int)
    41  		statusAddr = fmt.Sprintf(":%d", port)
    42  		log.Info("injecting failpoint, pprof will start at determined port", zap.Int("port", port))
    43  	})
    44  	listener, err := net.Listen("tcp", statusAddr)
    45  	if err != nil {
    46  		log.Warn("failed to start pprof", zap.String("addr", statusAddr), zap.Error(err))
    47  		return nil, errors.Trace(err)
    48  	}
    49  	startedPProf = listener.Addr().String()
    50  	log.Info("bound pprof to addr", zap.String("addr", startedPProf))
    51  	_, _ = fmt.Fprintf(os.Stderr, "bound pprof to addr %s\n", startedPProf)
    52  	return listener, nil
    53  }
    54  
    55  // StartPProfListener forks a new goroutine listening on specified port and provide pprof info.
    56  func StartPProfListener(statusAddr string, wrapper *tidbutils.TLS) error {
    57  	listener, err := listen(statusAddr)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	go func() {
    63  		if e := http.Serve(wrapper.WrapListener(listener), nil); e != nil {
    64  			log.Warn("failed to serve pprof", zap.String("addr", startedPProf), zap.Error(e))
    65  			mu.Lock()
    66  			startedPProf = ""
    67  			mu.Unlock()
    68  			return
    69  		}
    70  	}()
    71  	return nil
    72  }