github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/http_status.go (about) 1 // Copyright 2020 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package cdc 15 16 import ( 17 "context" 18 "encoding/json" 19 "fmt" 20 "io" 21 "net" 22 "net/http" 23 "net/http/pprof" 24 "os" 25 26 "github.com/pingcap/ticdc/pkg/util" 27 28 "github.com/pingcap/errors" 29 "github.com/pingcap/failpoint" 30 "github.com/pingcap/log" 31 "github.com/pingcap/ticdc/cdc/kv" 32 "github.com/pingcap/ticdc/pkg/config" 33 cerror "github.com/pingcap/ticdc/pkg/errors" 34 "github.com/pingcap/ticdc/pkg/version" 35 "github.com/prometheus/client_golang/prometheus" 36 "github.com/prometheus/client_golang/prometheus/promhttp" 37 "go.etcd.io/etcd/clientv3" 38 "go.uber.org/zap" 39 ) 40 41 func (s *Server) startStatusHTTP() error { 42 serverMux := http.NewServeMux() 43 44 serverMux.HandleFunc("/debug/pprof/", pprof.Index) 45 serverMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 46 serverMux.HandleFunc("/debug/pprof/profile", pprof.Profile) 47 serverMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 48 serverMux.HandleFunc("/debug/pprof/trace", pprof.Trace) 49 50 serverMux.HandleFunc("/status", s.handleStatus) 51 serverMux.HandleFunc("/debug/info", s.handleDebugInfo) 52 serverMux.HandleFunc("/capture/owner/resign", s.handleResignOwner) 53 serverMux.HandleFunc("/capture/owner/admin", s.handleChangefeedAdmin) 54 serverMux.HandleFunc("/capture/owner/rebalance_trigger", s.handleRebalanceTrigger) 55 serverMux.HandleFunc("/capture/owner/move_table", s.handleMoveTable) 56 serverMux.HandleFunc("/capture/owner/changefeed/query", s.handleChangefeedQuery) 57 serverMux.HandleFunc("/admin/log", handleAdminLogLevel) 58 serverMux.HandleFunc("/api/v1/changefeeds", s.handleChangefeeds) 59 serverMux.HandleFunc("/api/v1/health", s.handleHealth) 60 61 if util.FailpointBuild { 62 // `http.StripPrefix` is needed because `failpoint.HttpHandler` assumes that it handles the prefix `/`. 63 serverMux.Handle("/debug/fail/", http.StripPrefix("/debug/fail", &failpoint.HttpHandler{})) 64 } 65 66 prometheus.DefaultGatherer = registry 67 serverMux.Handle("/metrics", promhttp.Handler()) 68 conf := config.GetGlobalServerConfig() 69 tlsConfig, err := conf.Security.ToTLSConfigWithVerify() 70 if err != nil { 71 log.Error("status server get tls config failed", zap.Error(err)) 72 return errors.Trace(err) 73 } 74 s.statusServer = &http.Server{Addr: conf.Addr, Handler: serverMux, TLSConfig: tlsConfig} 75 76 ln, err := net.Listen("tcp", conf.Addr) 77 if err != nil { 78 return cerror.WrapError(cerror.ErrServeHTTP, err) 79 } 80 go func() { 81 log.Info("status http server is running", zap.String("addr", conf.Addr)) 82 if tlsConfig != nil { 83 err = s.statusServer.ServeTLS(ln, conf.Security.CertPath, conf.Security.KeyPath) 84 } else { 85 err = s.statusServer.Serve(ln) 86 } 87 if err != nil && err != http.ErrServerClosed { 88 log.Error("status server error", zap.Error(cerror.WrapError(cerror.ErrServeHTTP, err))) 89 } 90 }() 91 return nil 92 } 93 94 // status of cdc server 95 type status struct { 96 Version string `json:"version"` 97 GitHash string `json:"git_hash"` 98 ID string `json:"id"` 99 Pid int `json:"pid"` 100 IsOwner bool `json:"is_owner"` 101 } 102 103 func (s *Server) writeEtcdInfo(ctx context.Context, cli *kv.CDCEtcdClient, w io.Writer) { 104 resp, err := cli.Client.Get(ctx, kv.EtcdKeyBase, clientv3.WithPrefix()) 105 if err != nil { 106 fmt.Fprintf(w, "failed to get info: %s\n\n", err.Error()) 107 return 108 } 109 110 for _, kv := range resp.Kvs { 111 fmt.Fprintf(w, "%s\n\t%s\n\n", string(kv.Key), string(kv.Value)) 112 } 113 } 114 115 func (s *Server) handleDebugInfo(w http.ResponseWriter, req *http.Request) { 116 if config.NewReplicaImpl { 117 s.captureV2.WriteDebugInfo(w) 118 fmt.Fprintf(w, "\n\n*** etcd info ***:\n\n") 119 s.writeEtcdInfo(req.Context(), s.etcdClient, w) 120 return 121 } 122 s.ownerLock.RLock() 123 defer s.ownerLock.RUnlock() 124 if s.owner != nil { 125 fmt.Fprintf(w, "\n\n*** owner info ***:\n\n") 126 s.owner.writeDebugInfo(w) 127 } 128 129 fmt.Fprintf(w, "\n\n*** processors info ***:\n\n") 130 if config.NewReplicaImpl { 131 s.capture.processorManager.WriteDebugInfo(w) 132 } else { 133 for _, p := range s.capture.processors { 134 p.writeDebugInfo(w) 135 fmt.Fprintf(w, "\n") 136 } 137 } 138 139 fmt.Fprintf(w, "\n\n*** etcd info ***:\n\n") 140 s.writeEtcdInfo(req.Context(), &s.capture.etcdClient, w) 141 } 142 143 func (s *Server) handleStatus(w http.ResponseWriter, req *http.Request) { 144 st := status{ 145 Version: version.ReleaseVersion, 146 GitHash: version.GitHash, 147 Pid: os.Getpid(), 148 } 149 if config.NewReplicaImpl { 150 if s.captureV2 != nil { 151 st.ID = s.captureV2.Info().ID 152 st.IsOwner = s.captureV2.IsOwner() 153 } 154 writeData(w, st) 155 return 156 } 157 s.ownerLock.RLock() 158 defer s.ownerLock.RUnlock() 159 if s.capture != nil { 160 st.ID = s.capture.info.ID 161 } 162 st.IsOwner = s.owner != nil 163 writeData(w, st) 164 } 165 166 func writeInternalServerError(w http.ResponseWriter, err error) { 167 writeError(w, http.StatusInternalServerError, err) 168 } 169 170 func writeError(w http.ResponseWriter, statusCode int, err error) { 171 w.WriteHeader(statusCode) 172 _, err = w.Write([]byte(err.Error())) 173 if err != nil { 174 log.Error("write error", zap.Error(err)) 175 } 176 } 177 178 func writeData(w http.ResponseWriter, data interface{}) { 179 js, err := json.MarshalIndent(data, "", " ") 180 if err != nil { 181 log.Error("invalid json data", zap.Reflect("data", data), zap.Error(err)) 182 writeInternalServerError(w, err) 183 return 184 } 185 w.Header().Set("Content-Type", "application/json") 186 w.WriteHeader(http.StatusOK) 187 _, err = w.Write(js) 188 if err != nil { 189 log.Error("fail to write data", zap.Error(err)) 190 } 191 }