# Metrics statistics snapshot

This job will generate a data struct of metrics statistics from the specified cluster in a specified time range similar to the content of AWR.

## Inputs

Users can add more PromQL besides the default set.The statistics of default operators will be calculated on these PromQLs. Evenmore, users can get the raw data from the PromQL and use customized operators to get any insights if needed.

But the whole size of the response should be less than 5M bytes.

- cluster: str
- org_id: str
- org_type: 'cloud' or 'op'
- start_ts: int(seconds)
- stop_ts: int(seconds)
- (optional) promqls: json object

```json
{
  "args":{
    "cluster":"1373933076658091805",
    "start_ts":1660623886,
    "stop_ts":1660624552,
    "org_id":"274",
    "org_type":"cloud",
    "extra_promqls": [
      {
        "name": "TiDB_cpu_usage_norm:by_instance",
        "unit": "%",
        "expr": "label_replace(rate(process_cpu_seconds_total{{label_cluster_id},{label_component}=\"tidb\"}[2m])/tidb_server_maxprocs{{label_cluster_id},{label_component}=\"tidb\"}*100,\"name\",\"$1\",\"instance\",\"(.*)\")",
        "rawdata": false,
        "operators": [
          "continuous_high(0.8,5)"
        ]
      },
      {
        "name": "TiDB_cpu_usage_norm:total",
        "unit": "",
        "expr": "",
        "component": "",
        "rawdata": true,
        "operators": [
          "continuous_high(0.8,10)"
        ]
      }
    ]
  },
  "tags": {}
}
```

> The time step now is 15s as default and not able to be changed. So the time range of a job must be less than 100000s.

## Outputs

## Sample

```json
{
  "snapshot": {
    "Connnection_count:total": {
      "unit": "1",
      "insight": {
        "latest": 0,
        "latest_trend": 0.02073170731707291,
        "over_alltrend": 0.01137363844857801,
        "min": 0,
        "max": 22,
        "std": 1.8389495611190796,
        "mean": 18.990909576416016
      }
    },
    "TiKV_raft_propose_wait:by_instance": {
      "unit": "s",
      "insight": {
        "latest": {
          "db-tikv-0": 0,
          "db-tikv-1": 0,
          "db-tikv-2": 0
        },
        "latest_trend": {
          "db-tikv-0": 0.3456958425169614,
          "db-tikv-1": -0.07005544190622845,
          "db-tikv-2": -0.16175046914130597
        },
        "over_alltrend": {
          "db-tikv-0": -0.10894267551783268,
          "db-tikv-1": -0.1665491655577511,
          "db-tikv-2": -0.38157829258056236
        },
        "min": {
          "db-tikv-0": 0,
          "db-tikv-1": 0,
          "db-tikv-2": 0
        },
        "max": {
          "db-tikv-0": 178.6068878173828,
          "db-tikv-1": 120.16111755371094,
          "db-tikv-2": 214.49343872070312
        },
        "std": {
          "db-tikv-0": 33.39841079711914,
          "db-tikv-1": 24.88827896118164,
          "db-tikv-2": 47.486366271972656
        },
        "mean": {
          "db-tikv-0": 57.69681167602539,
          "db-tikv-1": 37.534793853759766,
          "db-tikv-2": 46.473934173583984
        },
        "imbalance": 0.45392341475706194
      }
    }
  },
  "fail_metrics": {
    "Asyncio_cpu:by_instance": "PromQL returns null. query: label_replace(sum(rate(tikv_thread_cpu_seconds_total{cluster_id=~\".*1379661944623214066\",name=~\"store_write.*\"}[2m]))by(instance),\"name\",\"$1\",\"instance\",\"(.*)\")"
  }
}
```

## How to contribute

### PromQLs

#### Naming

##### name:
* The PromQL's name is split by colon.
* The optional items after the colon should be:
  * total: the query always returns only one piece of time-series data, like sum(), avg(), etc.  
  * by_instance
  * by_type
  * by_orthogonality: by multiple demension, like by(instance,type)
  * by_xxx
##### unit:
* "1": counts
* "s":
* "%": pay attention to multiply 100 in the expression
* "Bytes":
* "Bps":
* etc.
##### expr:
* It is recommended to use label_replace to get a fixed label "name"
* Is there a more elegant expression alternative to nested label_replace to handle the expression with "by_orthogonality"?
* There are several template elements in the expression to adapt both the cloud and on-promise environment:
  * {label_cluster_id}
  * {label_component}
  * etc.
* If the teplate element is not universal, the expression might be seperated to "cloud" and "op"
##### component:

#### Examples

```yaml
- name: QPS:total
  unit: "1"
  expr: 'label_replace(sum(rate(tidb_executor_statement_total{{label_cluster_id}}[2m])),"name","total","","")'
  component: TiDB
- name: TiDB_uptime:by_instance
  unit: "s"
  expr:
    cloud: 'label_replace(time()-process_start_time_seconds{{label_cluster_id},component="tidb"},"name","$1","instance","(.*)")'
    op: 'label_replace(time()-process_start_time_seconds{{label_cluster_id},job="tidb"},"name","$1","instance","(.*)")'
  component: TiDB
```

#### Discussion

* Is it neccessary to add a "version" label to indicate the PromQL is available in some versions of TiDB?
### Operators

#### Preprocessing operators

* imputation
  * linear interpolation
  * special constant (mean, median, zero, NaN, etc.)
* filters
  * moving average
  * moving median
  * linear
  * fourier
* normalization
* etc.

#### Basic operators

* mean
* max
* min
* std
* quantile
* etc.

#### Advanced operators

* weak-sense stationary
* linear trend
* pearson correlation coefficient
* anomalies
* change-points
* etc.

## Prerequisities

* Layer: AWSDataWrangler-Python39 v7 python 3.9
* Layer: ce-python-layer    v6 python 3.9

## Actual requirements

* aiohttp==3.8.1
* aiohttp-retry==2.4.6
* mathbox==0.0.7
* numpy==1.22.3
* pandas==1.4.2
* PyYAML==5.4.1
