vitess.io/vitess@v0.16.2/web/vtadmin/src/util/tabletDebugVars.ts (about)

     1  /**
     2   * Copyright 2021 The Vitess Authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  /**
    18   * TabletDebugVars is a best-effort typing of the /debug/vars tablet endpoint.
    19   * Only fields read by VTAdmin are defined here.
    20   *
    21   * A good future enhancement is a proto-typed gRPC endpoint in vtadmin.proto,
    22   * from which we can generate TypeScript typings vs. having to duplicate them here.
    23   * This would also offer us actual runtime type safety by way of protobufjs's
    24   * generated validate() functions. For now, everything in here is optional (hence
    25   * the Partial<>) and not guaranteed to be defined in every Vitess deployment.
    26   */
    27  export type TabletDebugVars = Partial<{
    28      // See https://github.com/vitessio/vitess/blob/main/go/vt/servenv/buildinfo.go
    29      BuildGitBranch: string;
    30      BuildGitRev: string;
    31      BuildHost: string;
    32      BuildInformation: { [k: string]: number | string };
    33      BuildNumber: string;
    34      BuildTimestamp: string;
    35      BuildUser: string;
    36  
    37      QPS: { [k: string]: number[] };
    38  
    39      // See https://github.com/vitessio/vitess/blob/main/go/vt/vttablet/tabletmanager/vreplication/stats.go
    40      VReplicationLag: { [k: string]: number[] };
    41      VReplicationQPS: { [k: string]: number[] };
    42  }>;
    43  
    44  export interface TimeseriesPoint {
    45      x: number;
    46      y: number;
    47  }
    48  
    49  export type TimeseriesMap = { [seriesName: string]: TimeseriesPoint[] };
    50  
    51  export const getQPSTimeseries = (d: TabletDebugVars | null | undefined, endAt?: number): TimeseriesMap =>
    52      formatTimeseriesMap(d?.QPS || {}, endAt);
    53  
    54  export const getStreamVReplicationLagTimeseries = (
    55      d: TabletDebugVars | null | undefined,
    56      endAt?: number
    57  ): TimeseriesMap => formatTimeseriesMap(d?.VReplicationLag || {}, endAt);
    58  
    59  export const getVReplicationQPSTimeseries = (d: TabletDebugVars | null | undefined, endAt?: number): TimeseriesMap =>
    60      formatTimeseriesMap(d?.VReplicationQPS || {}, endAt);
    61  
    62  /**
    63   * REFETCH_INTERVAL defines a default for how often charts, etc.
    64   * should refetch /debug/vars.
    65   */
    66  export const QPS_REFETCH_INTERVAL = 2500;
    67  
    68  export const RATES_INTERVAL = 5; // 5 seconds
    69  export const RATES_MAX_SPAN = 15 * 60; // 15 minutes
    70  export const SERIES_LENGTH = RATES_MAX_SPAN / RATES_INTERVAL;
    71  
    72  /**
    73   * formatTimeseriesMap formats an array of numbers from a Rates stats counter as
    74   * an array of TimeseriesPoints.
    75   *
    76   * For Rates stats, see https://github.com/vitessio/vitess/blob/main/go/stats/rates.go
    77   *
    78   * @param rates - An array of numbers, inferred as data points at 5 second intervals.
    79   *
    80   * @param endAt - Optional. The timestamp for the last (most recent) data point in the series.
    81   * The `dataUpdatedAt` property of a query is recommended. Defaults to Date.now() if unspecified.
    82   */
    83  export const formatTimeseriesMap = (rates: { [k: string]: number[] }, endAt?: number): TimeseriesMap => {
    84      // Rates stats are (unfortunately) not returned with timestamps, so we infer them here.
    85      // This behaviour matches that of the vtctld2 UI:
    86      // https://github.com/vitessio/vitess/blob/main/go/vt/vttablet/tabletserver/status.go#L178
    87      const _endAt = typeof endAt === 'number' ? endAt : Date.now();
    88  
    89      // The `rates` map returned from the API, keyed by series name, will either:
    90      //      (a) be empty, or
    91      //      (b) contain a minimum of two series, one of them named "All".
    92      // In the first case, inserting an empty "All" series renders more nicely
    93      // on a Highcharts graph since it will include the axes, etc. So, we add it here.
    94      const _rates = !!Object.keys(rates).length ? rates : { All: [] };
    95  
    96      const planTypes = Object.keys(_rates);
    97  
    98      const data: TimeseriesMap = {};
    99  
   100      // This logic is borrowed from the vtctld2 UI
   101      // https://github.com/vitessio/vitess/blob/09e74af/go/vt/vttablet/tabletmanager/vreplication/stats.go#L478-L505
   102      for (let i = 0; i < RATES_MAX_SPAN / RATES_INTERVAL; i++) {
   103          const x = _endAt - ((i * 60) / RATES_INTERVAL) * 1000;
   104  
   105          for (let j = 0; j < planTypes.length; j++) {
   106              // Assume 0.0 QPS for older, non-existent data points.
   107              let y = 0;
   108  
   109              if (i < _rates[planTypes[j]].length) {
   110                  const idx = _rates[planTypes[j]].length - i - 1;
   111                  y = +_rates[planTypes[j]][idx].toFixed(2);
   112              }
   113  
   114              if (!Array.isArray(data[planTypes[j]])) {
   115                  data[planTypes[j]] = [];
   116              }
   117  
   118              data[planTypes[j]].unshift({ x, y });
   119          }
   120      }
   121  
   122      return data;
   123  };