github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/cmd/cli/cli_changefeed_statistics.go (about) 1 // Copyright 2021 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 cli 15 16 import ( 17 "context" 18 "fmt" 19 "time" 20 21 v2 "github.com/pingcap/tiflow/cdc/api/v2" 22 apiv2client "github.com/pingcap/tiflow/pkg/api/v2" 23 cmdcontext "github.com/pingcap/tiflow/pkg/cmd/context" 24 "github.com/pingcap/tiflow/pkg/cmd/factory" 25 "github.com/pingcap/tiflow/pkg/cmd/util" 26 "github.com/spf13/cobra" 27 "github.com/tikv/client-go/v2/oracle" 28 ) 29 30 // status specifies the current status of the changefeed. 31 type status struct { 32 SinkGap string `json:"sink_gap"` 33 ReplicationGap string `json:"replication_gap"` 34 } 35 36 // statisticsChangefeedOptions defines flags for the `cli changefeed statistics` command. 37 type statisticsChangefeedOptions struct { 38 apiClient apiv2client.APIV2Interface 39 40 changefeedID string 41 namespace string 42 interval uint 43 } 44 45 // newStatisticsChangefeedOptions creates new options for the `cli changefeed statistics` command. 46 func newStatisticsChangefeedOptions() *statisticsChangefeedOptions { 47 return &statisticsChangefeedOptions{} 48 } 49 50 // addFlags receives a *cobra.Command reference and binds 51 // flags related to template printing to it. 52 func (o *statisticsChangefeedOptions) addFlags(cmd *cobra.Command) { 53 cmd.PersistentFlags().StringVarP(&o.namespace, "namespace", "n", "default", "Replication task (changefeed) Namespace") 54 cmd.PersistentFlags().UintVarP(&o.interval, "interval", "I", 10, "Interval for outputing the latest statistics") 55 cmd.PersistentFlags().StringVarP(&o.changefeedID, "changefeed-id", "c", "", "Replication task (changefeed) ID") 56 _ = cmd.MarkPersistentFlagRequired("changefeed-id") 57 } 58 59 // complete adapts from the command line args to the data and client required. 60 func (o *statisticsChangefeedOptions) complete(f factory.Factory) error { 61 var err error 62 o.apiClient, err = f.APIV2Client() 63 if err != nil { 64 return err 65 } 66 return nil 67 } 68 69 // run cli command with api client 70 func (o *statisticsChangefeedOptions) runCliWithAPIClient(ctx context.Context, cmd *cobra.Command, lastCount *uint64, lastTime *time.Time) error { 71 now := time.Now() 72 var count uint64 73 74 changefeed, err := o.apiClient.Changefeeds().Get(ctx, o.namespace, o.changefeedID) 75 if err != nil { 76 return err 77 } 78 ts, err := o.apiClient.Tso().Query(ctx, 79 &v2.UpstreamConfig{ID: changefeed.UpstreamID}) 80 if err != nil { 81 return err 82 } 83 84 sinkGap := oracle.ExtractPhysical(changefeed.ResolvedTs) - 85 oracle.ExtractPhysical(changefeed.CheckpointTs) 86 replicationGap := ts.Timestamp - oracle.ExtractPhysical(changefeed.CheckpointTs) 87 statistics := status{ 88 SinkGap: fmt.Sprintf("%dms", sinkGap), 89 ReplicationGap: fmt.Sprintf("%dms", replicationGap), 90 } 91 92 *lastCount = count 93 *lastTime = now 94 return util.JSONPrint(cmd, statistics) 95 } 96 97 // run the `cli changefeed statistics` command. 98 func (o *statisticsChangefeedOptions) run(cmd *cobra.Command) error { 99 ctx := cmdcontext.GetDefaultContext() 100 101 tick := time.NewTicker(time.Duration(o.interval) * time.Second) 102 var lastTime time.Time 103 var lastCount uint64 104 _ = o.runCliWithAPIClient(ctx, cmd, &lastCount, &lastTime) 105 for { 106 select { 107 case <-ctx.Done(): 108 if err := ctx.Err(); err != nil { 109 return err 110 } 111 case <-tick.C: 112 _ = o.runCliWithAPIClient(ctx, cmd, &lastCount, &lastTime) 113 } 114 } 115 } 116 117 // newCmdStatisticsChangefeed creates the `cli changefeed statistics` command. 118 func newCmdStatisticsChangefeed(f factory.Factory) *cobra.Command { 119 o := newStatisticsChangefeedOptions() 120 121 command := &cobra.Command{ 122 Use: "statistics", 123 Short: "Periodically check and output the status of a replication task (changefeed)", 124 Args: cobra.NoArgs, 125 Run: func(cmd *cobra.Command, args []string) { 126 util.CheckErr(o.complete(f)) 127 util.CheckErr(o.run(cmd)) 128 }, 129 } 130 131 o.addFlags(command) 132 133 return command 134 }