gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/server/operations/system.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package operations
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"io"
    13  	"net"
    14  	"strings"
    15  	"time"
    16  
    17  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/metadata"
    18  	"gitee.com/zhaochuninhefei/fabric-config-gm/healthz"
    19  	"gitee.com/zhaochuninhefei/fabric-gm/common/metrics"
    20  	"gitee.com/zhaochuninhefei/fabric-gm/common/metrics/disabled"
    21  	"gitee.com/zhaochuninhefei/fabric-gm/common/metrics/prometheus"
    22  	"gitee.com/zhaochuninhefei/fabric-gm/common/metrics/statsd"
    23  	http "gitee.com/zhaochuninhefei/gmgo/gmhttp"
    24  	tls "gitee.com/zhaochuninhefei/gmgo/gmtls"
    25  	"gitee.com/zhaochuninhefei/gmgo/mux"
    26  	"gitee.com/zhaochuninhefei/gmgo/prometheus/promhttp"
    27  	log "gitee.com/zhaochuninhefei/zcgolog/zclog"
    28  	kitstatsd "github.com/go-kit/kit/metrics/statsd"
    29  )
    30  
    31  // System is an operations server that is responsible for metrics and health checks
    32  type System struct {
    33  	metrics.Provider
    34  	healthHandler *healthz.HealthHandler
    35  
    36  	options    Options
    37  	statsd     *kitstatsd.Statsd
    38  	sendTicker *time.Ticker
    39  	httpServer *http.Server
    40  	mux        *mux.Router
    41  	addr       string
    42  }
    43  
    44  // Options contains configuration for the operations system
    45  type Options struct {
    46  	ListenAddress string
    47  	Metrics       MetricsOptions
    48  	TLS           TLS
    49  }
    50  
    51  // MetricsOptions contains the information on providers
    52  type MetricsOptions struct {
    53  	Provider string
    54  	Statsd   *Statsd
    55  }
    56  
    57  // Statsd contains configuration of statsd
    58  type Statsd struct {
    59  	Network       string
    60  	Address       string
    61  	WriteInterval time.Duration
    62  	Prefix        string
    63  }
    64  
    65  // NewSystem creates a System struct
    66  func NewSystem(o Options) *System {
    67  	system := &System{
    68  		options: o,
    69  	}
    70  
    71  	system.initializeServer()
    72  	system.initializeHealthCheckHandler()
    73  	system.initializeMetricsProvider()
    74  	system.initializeVersionInfoHandler()
    75  
    76  	return system
    77  }
    78  
    79  // Start starts the operations system server
    80  func (s *System) Start() error {
    81  	err := s.startMetricsTickers()
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	listener, err := s.listen()
    87  	if err != nil {
    88  		return err
    89  	}
    90  	s.addr = listener.Addr().String()
    91  
    92  	log.Infof("Operation Server Listening on %s", listener.Addr())
    93  	go s.httpServer.Serve(listener)
    94  
    95  	return nil
    96  }
    97  
    98  // Stop stop the operations system server
    99  func (s *System) Stop() error {
   100  	if s.sendTicker != nil {
   101  		s.sendTicker.Stop()
   102  		s.sendTicker = nil
   103  	}
   104  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   105  	defer cancel()
   106  
   107  	return s.httpServer.Shutdown(ctx)
   108  }
   109  
   110  func (s *System) initializeServer() {
   111  	s.mux = mux.NewRouter()
   112  	s.httpServer = &http.Server{
   113  		Addr:         s.options.ListenAddress,
   114  		Handler:      s.mux,
   115  		ReadTimeout:  10 * time.Second,
   116  		WriteTimeout: 2 * time.Minute,
   117  	}
   118  }
   119  
   120  func (s *System) initializeMetricsProvider() {
   121  	m := s.options.Metrics
   122  	providerType := m.Provider
   123  	switch providerType {
   124  	case "statsd":
   125  		prefix := m.Statsd.Prefix
   126  		if prefix != "" && !strings.HasSuffix(prefix, ".") {
   127  			prefix = prefix + "."
   128  		}
   129  
   130  		ks := kitstatsd.New(prefix, s)
   131  		s.Provider = &statsd.Provider{Statsd: ks}
   132  		s.statsd = ks
   133  
   134  	case "prometheus":
   135  		s.Provider = &prometheus.Provider{}
   136  		s.mux.Handle("/metrics", promhttp.Handler())
   137  
   138  	default:
   139  		if providerType != "disabled" {
   140  			log.Warnf("Unknown provider type: %s; metrics disabled", providerType)
   141  		}
   142  
   143  		s.Provider = &disabled.Provider{}
   144  	}
   145  }
   146  
   147  func (s *System) initializeHealthCheckHandler() {
   148  	s.healthHandler = healthz.NewHealthHandler()
   149  	s.mux.Handle("/healthz", s.healthHandler)
   150  }
   151  
   152  func (s *System) initializeVersionInfoHandler() {
   153  	version := fmt.Sprintf(`{"Version":"%s"}`, metadata.Version)
   154  	s.mux.HandleFunc("/version", func(w http.ResponseWriter, _ *http.Request) {
   155  		io.WriteString(w, version)
   156  	})
   157  }
   158  
   159  func (s *System) startMetricsTickers() error {
   160  	m := s.options.Metrics
   161  	if s.statsd != nil {
   162  		network := m.Statsd.Network
   163  		address := m.Statsd.Address
   164  		c, err := net.Dial(network, address)
   165  		if err != nil {
   166  			return err
   167  		}
   168  		c.Close()
   169  
   170  		writeInterval := s.options.Metrics.Statsd.WriteInterval
   171  
   172  		s.sendTicker = time.NewTicker(writeInterval)
   173  		go s.statsd.SendLoop(s.sendTicker.C, network, address)
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  // Log is a function required to meet the interface required by statsd
   180  func (s *System) Log(keyvals ...interface{}) error {
   181  	log.Warn(keyvals...)
   182  	return nil
   183  }
   184  
   185  // RegisterChecker registers the HealthCheck with Healthchecker server
   186  func (s *System) RegisterChecker(component string, checker healthz.HealthChecker) error {
   187  	return s.healthHandler.RegisterChecker(component, checker)
   188  }
   189  
   190  func (s *System) listen() (net.Listener, error) {
   191  	listener, err := net.Listen("tcp", s.options.ListenAddress)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  	tlsConfig, err := s.options.TLS.Config()
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	if tlsConfig != nil {
   200  		listener = tls.NewListener(listener, tlsConfig)
   201  	}
   202  	return listener, nil
   203  }
   204  
   205  // Addr returns the address of the listener
   206  func (s *System) Addr() string {
   207  	return s.addr
   208  }