istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/bootstrap/monitoring.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bootstrap 16 17 import ( 18 "fmt" 19 "net" 20 "net/http" 21 "time" 22 23 commonFeatures "istio.io/istio/pkg/features" 24 "istio.io/istio/pkg/log" 25 "istio.io/istio/pkg/monitoring" 26 istioNetUtil "istio.io/istio/pkg/util/net" 27 "istio.io/istio/pkg/version" 28 ) 29 30 type monitor struct { 31 monitoringServer *http.Server 32 } 33 34 const ( 35 metricsPath = "/metrics" 36 versionPath = "/version" 37 ) 38 39 var ( 40 serverStart = time.Now() 41 42 _ = monitoring.NewDerivedGauge( 43 "istiod_uptime_seconds", 44 "Current istiod server uptime in seconds", 45 ).ValueFrom(func() float64 { 46 return time.Since(serverStart).Seconds() 47 }) 48 49 versionTag = monitoring.CreateLabel("version") 50 pilotVersion = monitoring.NewGauge( 51 "pilot_info", 52 "Pilot version and build information.", 53 ) 54 ) 55 56 func init() { 57 pilotVersion.With(versionTag.Value(version.Info.String())).Record(1) 58 } 59 60 func addMonitor(mux *http.ServeMux) error { 61 exporter, err := monitoring.RegisterPrometheusExporter(nil, nil) 62 if err != nil { 63 return fmt.Errorf("could not set up prometheus exporter: %v", err) 64 } 65 mux.Handle(metricsPath, metricsMiddleware(exporter)) 66 67 mux.HandleFunc(versionPath, func(out http.ResponseWriter, req *http.Request) { 68 if _, err := out.Write([]byte(version.Info.String())); err != nil { 69 log.Errorf("Unable to write version string: %v", err) 70 } 71 }) 72 73 return nil 74 } 75 76 func metricsMiddleware(handler http.Handler) http.Handler { 77 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 78 if commonFeatures.MetricsLocalhostAccessOnly && !istioNetUtil.IsRequestFromLocalhost(r) { 79 http.Error(w, "Only requests from localhost are allowed", http.StatusForbidden) 80 return 81 } 82 // Pass control back to the handler 83 handler.ServeHTTP(w, r) 84 }) 85 } 86 87 // Deprecated: we shouldn't have 2 http ports. Will be removed after code using 88 // this port is removed. 89 func startMonitor(addr string, mux *http.ServeMux) (*monitor, error) { 90 m := &monitor{} 91 92 // get the network stuff setup 93 var listener net.Listener 94 if addr != "" { 95 var err error 96 if listener, err = net.Listen("tcp", addr); err != nil { 97 return nil, fmt.Errorf("unable to listen on socket: %v", err) 98 } 99 } 100 101 // NOTE: this is a temporary solution to provide bare-bones debug functionality 102 // for pilot. a full design / implementation of self-monitoring and reporting 103 // is coming. that design will include proper coverage of statusz/healthz type 104 // functionality, in addition to how pilot reports its own metrics. 105 if err := addMonitor(mux); err != nil { 106 return nil, fmt.Errorf("could not establish self-monitoring: %v", err) 107 } 108 if addr != "" { 109 m.monitoringServer = &http.Server{ 110 Addr: listener.Addr().String(), 111 Handler: mux, 112 IdleTimeout: 90 * time.Second, // matches http.DefaultTransport keep-alive timeout 113 ReadTimeout: 30 * time.Second, 114 } 115 } 116 117 version.Info.RecordComponentBuildTag("pilot") 118 119 if addr != "" { 120 go func() { 121 _ = m.monitoringServer.Serve(listener) 122 }() 123 } 124 125 return m, nil 126 } 127 128 func (m *monitor) Close() error { 129 if m.monitoringServer != nil { 130 return m.monitoringServer.Close() 131 } 132 return nil 133 } 134 135 // initMonitor initializes the configuration for the pilot monitoring server. 136 func (s *Server) initMonitor(addr string) error { // nolint: unparam 137 s.addStartFunc("monitoring", func(stop <-chan struct{}) error { 138 monitor, err := startMonitor(addr, s.monitoringMux) 139 if err != nil { 140 return err 141 } 142 go func() { 143 <-stop 144 err := monitor.Close() 145 log.Debugf("Monitoring server terminated: %v", err) 146 }() 147 return nil 148 }) 149 return nil 150 }