github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/operations/system.go (about)

     1  /*
     2  Copyright hechain All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package operations
     8  
     9  import (
    10  	"context"
    11  	"net"
    12  	"strings"
    13  	"time"
    14  
    15  	kitstatsd "github.com/go-kit/kit/metrics/statsd"
    16  	"github.com/hechain20/hechain/common/fabhttp"
    17  	"github.com/hechain20/hechain/common/flogging"
    18  	"github.com/hechain20/hechain/common/flogging/httpadmin"
    19  	"github.com/hechain20/hechain/common/metadata"
    20  	"github.com/hechain20/hechain/common/metrics"
    21  	"github.com/hechain20/hechain/common/metrics/disabled"
    22  	"github.com/hechain20/hechain/common/metrics/prometheus"
    23  	"github.com/hechain20/hechain/common/metrics/statsd"
    24  	"github.com/hechain20/hechain/common/metrics/statsd/goruntime"
    25  	"github.com/hyperledger/fabric-lib-go/healthz"
    26  	"github.com/prometheus/client_golang/prometheus/promhttp"
    27  )
    28  
    29  //go:generate counterfeiter -o fakes/logger.go -fake-name Logger . Logger
    30  
    31  type Logger interface {
    32  	Warn(args ...interface{})
    33  	Warnf(template string, args ...interface{})
    34  }
    35  
    36  type Statsd struct {
    37  	Network       string
    38  	Address       string
    39  	WriteInterval time.Duration
    40  	Prefix        string
    41  }
    42  
    43  type MetricsOptions struct {
    44  	Provider string
    45  	Statsd   *Statsd
    46  }
    47  
    48  type Options struct {
    49  	fabhttp.Options
    50  	Metrics MetricsOptions
    51  	Version string
    52  }
    53  
    54  type System struct {
    55  	*fabhttp.Server
    56  	metrics.Provider
    57  
    58  	logger          Logger
    59  	healthHandler   *healthz.HealthHandler
    60  	options         Options
    61  	statsd          *kitstatsd.Statsd
    62  	collectorTicker *time.Ticker
    63  	sendTicker      *time.Ticker
    64  	versionGauge    metrics.Gauge
    65  }
    66  
    67  func NewSystem(o Options) *System {
    68  	logger := o.Logger
    69  	if logger == nil {
    70  		logger = flogging.MustGetLogger("operations.runner")
    71  	}
    72  
    73  	s := fabhttp.NewServer(o.Options)
    74  
    75  	system := &System{
    76  		Server:  s,
    77  		logger:  logger,
    78  		options: o,
    79  	}
    80  
    81  	system.initializeHealthCheckHandler()
    82  	system.initializeLoggingHandler()
    83  	system.initializeMetricsProvider()
    84  	system.initializeVersionInfoHandler()
    85  
    86  	return system
    87  }
    88  
    89  func (s *System) Start() error {
    90  	err := s.startMetricsTickers()
    91  	if err != nil {
    92  		return err
    93  	}
    94  
    95  	s.versionGauge.With("version", s.options.Version).Set(1)
    96  
    97  	return s.Server.Start()
    98  }
    99  
   100  func (s *System) Stop() error {
   101  	if s.collectorTicker != nil {
   102  		s.collectorTicker.Stop()
   103  		s.collectorTicker = nil
   104  	}
   105  	if s.sendTicker != nil {
   106  		s.sendTicker.Stop()
   107  		s.sendTicker = nil
   108  	}
   109  	return s.Server.Stop()
   110  }
   111  
   112  func (s *System) RegisterChecker(component string, checker healthz.HealthChecker) error {
   113  	return s.healthHandler.RegisterChecker(component, checker)
   114  }
   115  
   116  func (s *System) initializeMetricsProvider() error {
   117  	m := s.options.Metrics
   118  	providerType := m.Provider
   119  	switch providerType {
   120  	case "statsd":
   121  		prefix := m.Statsd.Prefix
   122  		if prefix != "" && !strings.HasSuffix(prefix, ".") {
   123  			prefix = prefix + "."
   124  		}
   125  
   126  		ks := kitstatsd.New(prefix, s)
   127  		s.Provider = &statsd.Provider{Statsd: ks}
   128  		s.statsd = ks
   129  		s.versionGauge = versionGauge(s.Provider)
   130  		return nil
   131  
   132  	case "prometheus":
   133  		s.Provider = &prometheus.Provider{}
   134  		s.versionGauge = versionGauge(s.Provider)
   135  		// swagger:operation GET /metrics operations metrics
   136  		// ---
   137  		// responses:
   138  		//     '200':
   139  		//        description: Ok.
   140  		s.RegisterHandler("/metrics", promhttp.Handler(), s.options.TLS.Enabled)
   141  		return nil
   142  
   143  	default:
   144  		if providerType != "disabled" {
   145  			s.logger.Warnf("Unknown provider type: %s; metrics disabled", providerType)
   146  		}
   147  
   148  		s.Provider = &disabled.Provider{}
   149  		s.versionGauge = versionGauge(s.Provider)
   150  		return nil
   151  	}
   152  }
   153  
   154  func (s *System) initializeLoggingHandler() {
   155  	// swagger:operation GET /logspec operations logspecget
   156  	// ---
   157  	// summary: Retrieves the active logging spec for a peer or orderer.
   158  	// responses:
   159  	//     '200':
   160  	//        description: Ok.
   161  
   162  	// swagger:operation PUT /logspec operations logspecput
   163  	// ---
   164  	// summary: Updates the active logging spec for a peer or orderer.
   165  	//
   166  	// parameters:
   167  	// - name: payload
   168  	//   in: formData
   169  	//   type: string
   170  	//   description: The payload must consist of a single attribute named spec.
   171  	//   required: true
   172  	// responses:
   173  	//     '204':
   174  	//        description: No content.
   175  	//     '400':
   176  	//        description: Bad request.
   177  	// consumes:
   178  	//   - multipart/form-data
   179  	s.RegisterHandler("/logspec", httpadmin.NewSpecHandler(), s.options.TLS.Enabled)
   180  }
   181  
   182  func (s *System) initializeHealthCheckHandler() {
   183  	s.healthHandler = healthz.NewHealthHandler()
   184  	// swagger:operation GET /healthz operations healthz
   185  	// ---
   186  	// summary: Retrieves all registered health checkers for the process.
   187  	// responses:
   188  	//     '200':
   189  	//        description: Ok.
   190  	//     '503':
   191  	//        description: Service unavailable.
   192  	s.RegisterHandler("/healthz", s.healthHandler, false)
   193  }
   194  
   195  func (s *System) initializeVersionInfoHandler() {
   196  	versionInfo := &VersionInfoHandler{
   197  		CommitSHA: metadata.CommitSHA,
   198  		Version:   metadata.Version,
   199  	}
   200  	// swagger:operation GET /version operations version
   201  	// ---
   202  	// summary: Returns the orderer or peer version and the commit SHA on which the release was created.
   203  	// responses:
   204  	//     '200':
   205  	//        description: Ok.
   206  	s.RegisterHandler("/version", versionInfo, false)
   207  }
   208  
   209  func (s *System) startMetricsTickers() error {
   210  	m := s.options.Metrics
   211  	if s.statsd != nil {
   212  		network := m.Statsd.Network
   213  		address := m.Statsd.Address
   214  		c, err := net.Dial(network, address)
   215  		if err != nil {
   216  			return err
   217  		}
   218  		c.Close()
   219  
   220  		opts := s.options.Metrics.Statsd
   221  		writeInterval := opts.WriteInterval
   222  
   223  		s.collectorTicker = time.NewTicker(writeInterval / 2)
   224  		goCollector := goruntime.NewCollector(s.Provider)
   225  		go goCollector.CollectAndPublish(s.collectorTicker.C)
   226  
   227  		s.sendTicker = time.NewTicker(writeInterval)
   228  		go s.statsd.SendLoop(context.TODO(), s.sendTicker.C, network, address)
   229  	}
   230  
   231  	return nil
   232  }