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  }