diff --git a/pdctl/command/log_command.go b/pdctl/command/log_command.go new file mode 100644 index 00000000000..a84cd58bb36 --- /dev/null +++ b/pdctl/command/log_command.go @@ -0,0 +1,62 @@ +// Copyright 2018 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package command + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + + "github.com/spf13/cobra" +) + +var ( + logPrefix = "pd/api/v1/log" +) + +// NewLogCommand New a log subcommand of the rootCmd +func NewLogCommand() *cobra.Command { + conf := &cobra.Command{ + Use: "log [fatal|error|warn|info|debug]", + Short: "set log level", + Run: logCommandFunc, + } + return conf +} + +func logCommandFunc(cmd *cobra.Command, args []string) { + var err error + if len(args) != 1 { + fmt.Println(cmd.UsageString()) + return + } + + data, err := json.Marshal(args[0]) + if err != nil { + fmt.Printf("Failed to set log level: %s\n", err) + return + } + req, err := getRequest(cmd, logPrefix, http.MethodPost, "application/json", bytes.NewBuffer(data)) + if err != nil { + fmt.Printf("Failed to set log level: %s\n", err) + return + } + _, err = dail(req) + if err != nil { + fmt.Printf("Failed to set log level: %s\n", err) + return + } + fmt.Println("Success!") +} diff --git a/pdctl/ctl.go b/pdctl/ctl.go index fd0a24d707a..a319dc7a72a 100644 --- a/pdctl/ctl.go +++ b/pdctl/ctl.go @@ -56,6 +56,7 @@ func init() { command.NewClusterCommand(), command.NewTableNamespaceCommand(), command.NewHealthCommand(), + command.NewLogCommand(), ) cobra.EnablePrefixMatching = true } diff --git a/server/api/log.go b/server/api/log.go new file mode 100644 index 00000000000..cab2e8abce4 --- /dev/null +++ b/server/api/log.go @@ -0,0 +1,57 @@ +// Copyright 2018 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package api + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "github.com/pingcap/pd/pkg/logutil" + "github.com/pingcap/pd/server" + log "github.com/sirupsen/logrus" + "github.com/unrolled/render" +) + +type logHandler struct { + svr *server.Server + rd *render.Render +} + +func newlogHandler(svr *server.Server, rd *render.Render) *logHandler { + return &logHandler{ + svr: svr, + rd: rd, + } +} + +func (h *logHandler) Handle(w http.ResponseWriter, r *http.Request) { + var level string + data, err := ioutil.ReadAll(r.Body) + r.Body.Close() + if err != nil { + h.rd.JSON(w, http.StatusInternalServerError, err.Error()) + return + } + err = json.Unmarshal(data, &level) + if err != nil { + h.rd.JSON(w, http.StatusInternalServerError, err.Error()) + return + } + + h.svr.SetLogLevel(level) + log.SetLevel(logutil.StringToLogLevel(level)) + + h.rd.JSON(w, http.StatusOK, nil) +} diff --git a/server/api/router.go b/server/api/router.go index 7abb11c6b2f..f9bbb452192 100644 --- a/server/api/router.go +++ b/server/api/router.go @@ -104,6 +104,9 @@ func createRouter(prefix string, svr *server.Server) *mux.Router { trendHandler := newTrendHandler(svr, rd) router.HandleFunc("/api/v1/trend", trendHandler.Handle).Methods("GET") + logHanler := newlogHandler(svr, rd) + router.HandleFunc("/api/v1/log", logHanler.Handle).Methods("POST") + router.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {}).Methods("GET") return router } diff --git a/server/schedule/filters.go b/server/schedule/filters.go index 428609e08dd..3ae4c22d2e6 100644 --- a/server/schedule/filters.go +++ b/server/schedule/filters.go @@ -17,6 +17,7 @@ import ( "github.com/pingcap/pd/server/cache" "github.com/pingcap/pd/server/core" "github.com/pingcap/pd/server/namespace" + log "github.com/sirupsen/logrus" ) // Filter is an interface to filter source and target store. @@ -31,6 +32,7 @@ type Filter interface { func FilterSource(opt Options, store *core.StoreInfo, filters []Filter) bool { for _, filter := range filters { if filter.FilterSource(opt, store) { + log.Debugf("[filter %T] filters store %v from source", filter, store) return true } } @@ -41,6 +43,7 @@ func FilterSource(opt Options, store *core.StoreInfo, filters []Filter) bool { func FilterTarget(opt Options, store *core.StoreInfo, filters []Filter) bool { for _, filter := range filters { if filter.FilterTarget(opt, store) { + log.Debugf("[filter %T] filters store %v from target", filter, store) return true } } diff --git a/server/schedulers/balance_leader.go b/server/schedulers/balance_leader.go index 5a299701bbf..6592a9edf48 100644 --- a/server/schedulers/balance_leader.go +++ b/server/schedulers/balance_leader.go @@ -16,6 +16,7 @@ package schedulers import ( "github.com/pingcap/pd/server/core" "github.com/pingcap/pd/server/schedule" + log "github.com/sirupsen/logrus" ) func init() { @@ -74,6 +75,7 @@ func (l *balanceLeaderScheduler) Schedule(cluster schedule.Cluster, opInfluence source := cluster.GetStore(region.Leader.GetStoreId()) target := cluster.GetStore(newLeader.GetStoreId()) + log.Debugf("[region %d] source store id is %v, target store id is %v", region.GetId(), source.GetId(), target.GetId()) avgScore := cluster.GetStoresAverageScore(core.LeaderKind) if !shouldBalance(source, target, avgScore, core.LeaderKind, region, opInfluence, cluster.GetTolerantSizeRatio()) { schedulerCounter.WithLabelValues(l.GetName(), "skip").Inc() diff --git a/server/schedulers/balance_region.go b/server/schedulers/balance_region.go index 65c93f601b0..4450f794614 100644 --- a/server/schedulers/balance_region.go +++ b/server/schedulers/balance_region.go @@ -20,6 +20,7 @@ import ( "github.com/pingcap/pd/server/cache" "github.com/pingcap/pd/server/core" "github.com/pingcap/pd/server/schedule" + log "github.com/sirupsen/logrus" ) func init() { @@ -117,6 +118,7 @@ func (s *balanceRegionScheduler) transferPeer(cluster schedule.Cluster, region * target := cluster.GetStore(newPeer.GetStoreId()) avgScore := cluster.GetStoresAverageScore(core.RegionKind) + log.Debugf("[region %d] source store id is %v, target store id is %v", region.GetId(), source.GetId(), target.GetId()) if !shouldBalance(source, target, avgScore, core.RegionKind, region, opInfluence, cluster.GetTolerantSizeRatio()) { schedulerCounter.WithLabelValues(s.GetName(), "skip").Inc() return nil diff --git a/server/schedulers/utils.go b/server/schedulers/utils.go index c2599282965..88906319da7 100644 --- a/server/schedulers/utils.go +++ b/server/schedulers/utils.go @@ -39,6 +39,7 @@ func scheduleTransferLeader(cluster schedule.Cluster, schedulerName string, s sc mostLeaderStore := s.SelectSource(cluster, stores, filters...) leastLeaderStore := s.SelectTarget(cluster, stores, filters...) + log.Debugf("[%s] mostLeaderStore is %v, leastLeaderStore is %v", schedulerName, mostLeaderStore, leastLeaderStore) var mostLeaderDistance, leastLeaderDistance float64 if mostLeaderStore != nil { @@ -47,6 +48,7 @@ func scheduleTransferLeader(cluster schedule.Cluster, schedulerName string, s sc if leastLeaderStore != nil { leastLeaderDistance = math.Abs(leastLeaderStore.LeaderScore() - averageLeader) } + log.Debugf("[%s] mostLeaderDistance is %v, leastLeaderDistance is %v", schedulerName, mostLeaderDistance, leastLeaderDistance) if mostLeaderDistance == 0 && leastLeaderDistance == 0 { schedulerCounter.WithLabelValues(schedulerName, "already_balanced").Inc() return nil, nil @@ -63,7 +65,11 @@ func scheduleTransferLeader(cluster schedule.Cluster, schedulerName string, s sc region, peer = scheduleRemoveLeader(cluster, schedulerName, mostLeaderStore.GetId(), s) } } - + if region == nil { + log.Debugf("[%v] select no region", schedulerName) + } else { + log.Debugf("[region %v][%v] select %v to be new leader", region.GetId(), schedulerName, peer) + } return region, peer } @@ -173,6 +179,7 @@ func shouldBalance(source, target *core.StoreInfo, avgScore float64, kind core.R sourceScore := source.ResourceScore(kind) targetScore := target.ResourceScore(kind) if targetScore >= sourceScore { + log.Debugf("should balance return false cause targetScore %v >= sourceScore %v", targetScore, sourceScore) return false } @@ -183,6 +190,7 @@ func shouldBalance(source, target *core.StoreInfo, avgScore float64, kind core.R sourceSizeDiff := (sourceScore - avgScore) * source.ResourceWeight(kind) targetSizeDiff := (avgScore - targetScore) * target.ResourceWeight(kind) + log.Debugf("[region %d] size diff is %v and tolerant size is %v", region.GetId(), math.Min(sourceSizeDiff, targetSizeDiff), float64(region.ApproximateSize)*tolerantRatio) return math.Min(sourceSizeDiff, targetSizeDiff) >= float64(region.ApproximateSize)*tolerantRatio } diff --git a/server/server.go b/server/server.go index e7503b5bd3d..3816c6716bc 100644 --- a/server/server.go +++ b/server/server.go @@ -558,3 +558,8 @@ func (s *Server) GetClusterStatus() (*ClusterStatus, error) { func (s *Server) getAllocIDPath() string { return path.Join(s.rootPath, "alloc_id") } + +// SetLogLevel sets log level. +func (s *Server) SetLogLevel(level string) { + s.cfg.Log.Level = level +}