diff --git a/docs/config.json b/docs/config.json index 57517c9..5bce9af 100644 --- a/docs/config.json +++ b/docs/config.json @@ -40,5 +40,9 @@ "mainRecvBatchSize": 0, "sendChannelCapacity": 0 } - ] + ], + "pprof": { + "enabled": false, + "listenAddress": ":8080" + } } diff --git a/pprof/pprof.go b/pprof/pprof.go new file mode 100644 index 0000000..388df6e --- /dev/null +++ b/pprof/pprof.go @@ -0,0 +1,63 @@ +package pprof + +import ( + "context" + "net" + "net/http" + _ "net/http/pprof" + + "go.uber.org/zap" +) + +// PprofConfig is the configuration for the pprof service. +type PprofConfig struct { + // Enabled controls whether the pprof service is enabled. + Enabled bool `json:"enabled"` + + // ListenAddress is the address to listen on. + ListenAddress string `json:"listenAddress"` +} + +// NewService creates a new pprof service. +func (pc *PprofConfig) NewService(logger *zap.Logger) *Service { + return &Service{ + logger: logger, + server: http.Server{ + Addr: pc.ListenAddress, + }, + } +} + +// Service implements [service.Service]. +type Service struct { + logger *zap.Logger + server http.Server +} + +// String implements [service.Service.String]. +func (s *Service) String() string { + return "pprof" +} + +// Start implements [service.Service.Start]. +func (s *Service) Start(ctx context.Context) error { + var lc net.ListenConfig + ln, err := lc.Listen(ctx, "tcp", s.server.Addr) + if err != nil { + return err + } + + go func() { + if err := s.server.Serve(ln); err != nil && err != http.ErrServerClosed { + s.logger.Error("Failed to serve pprof", zap.Error(err)) + } + }() + + s.logger.Info("Started pprof", zap.String("listenAddress", s.server.Addr)) + return nil +} + +// Stop implements [service.Service.Stop]. +func (s *Service) Stop() error { + return s.server.Close() +} diff --git a/service/service.go b/service/service.go index e88894c..9402419 100644 --- a/service/service.go +++ b/service/service.go @@ -10,6 +10,7 @@ import ( "github.com/database64128/swgp-go/conn" "github.com/database64128/swgp-go/packet" + "github.com/database64128/swgp-go/pprof" "go.uber.org/zap" ) @@ -121,13 +122,17 @@ func (pc *PerfConfig) CheckAndApplyDefaults() error { // Config stores configurations for a typical swgp service. // It may be marshaled as or unmarshaled from JSON. type Config struct { - Servers []ServerConfig `json:"servers"` - Clients []ClientConfig `json:"clients"` + Servers []ServerConfig `json:"servers"` + Clients []ClientConfig `json:"clients"` + Pprof pprof.PprofConfig `json:"pprof"` } // Manager initializes the service manager. func (sc *Config) Manager(logger *zap.Logger) (*Manager, error) { serviceCount := len(sc.Servers) + len(sc.Clients) + if sc.Pprof.Enabled { + serviceCount++ + } if serviceCount == 0 { return nil, errors.New("no services to start") } @@ -151,6 +156,10 @@ func (sc *Config) Manager(logger *zap.Logger) (*Manager, error) { services = append(services, c) } + if sc.Pprof.Enabled { + services = append(services, sc.Pprof.NewService(logger)) + } + return &Manager{services, logger}, nil }