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 }