Instana API コールメモ

## はじめに

業務で IBM Instana に触れる機会があり、API を使ってデータをフェッチしてくる周りのことを行ったので忘備録として残す。

## Disclaimer

走り書きのため、中途半端な箇所あり

## Instana とは

https://www.ibm.com/products/instana

IBM 社が提供する、APM(Application Performance Management)ツールである。
主な機能としては以下のようなものがある(by ChatGPT 3.5)

- リアルタイムなアプリケーションモニタリング: インストールや設定が簡単で、アプリケーションのパフォーマンスをリアルタイムで監視します。これにより、アプリケーションのパフォーマンスの問題を迅速に検出し、対処することができます。

- エンドユーザーモニタリング: エンドユーザーの体験をモニタリングし、ユーザーがアプリケーションをどのように利用しているか、どのようなパフォーマンスを感じているかを把握します。

- 分散トレーシング: マイクロサービスアーキテクチャやコンテナ化されたアプリケーションにおいて、複数のサービス間でリクエストがどのように伝播しているかを追跡し、問題の原因を特定するための可視化を提供します。

- ログ分析: アプリケーションやインフラストラクチャのログを収集し、分析することで、問題の根本原因を理解する手助けをします。

- 自動検出とマッピング: アプリケーションのコンポーネントやサービスを自動的に検出し、それらの関係性を可視化する機能を持っています。

## API 資料

- https://instana.github.io/openapi/#section/Backend-REST-API

## 環境

- 実行環境: `MacBook Pro/Sonoma 14.4.1/Apple M1 Max`
- Instana のサーバーが設定されていること
- Instana の API 利用するための　API Token を取得済みであること
- `{host_url}` は実際の環境のものに置き換えること（Instana の GUI ホストと同一）


## CLI から叩く

### application list の取得

request:

```sh
curl -k --request GET \
  --url {host_url}/api/application-monitoring/applications \
  --header 'authorization: apiToken <token>'
```


<details><summary>response</summary>

```json
{
   "items":[
      {
         "id":"chrQOUFASMCqXLxpMzyBkQ",
         "label":"robot-shop",
         "boundaryScope":"INBOUND",
         "entityType":"APPLICATION",
         "_links":{
            "self":"{host_url}/api/application-monitoring/applications;id=chrQOUFASMCqXLxpMzyBkQ?to=1716784830092&windowSize=600000",
            "services":"{host_url}/api/application-monitoring/applications;id=chrQOUFASMCqXLxpMzyBkQ/services?to=1716784830092&windowSize=600000"
         }
      },
      {
         "id":"UUcovsmHSwGamDuDHyyhQQ",
         "label":"All Services",
         "boundaryScope":"INBOUND",
         "entityType":"APPLICATION",
         "_links":{
            "self":"{host_url}/api/application-monitoring/applications;id=UUcovsmHSwGamDuDHyyhQQ?to=1716784830092&windowSize=600000",
            "services":"{host_url}/api/application-monitoring/applications;id=UUcovsmHSwGamDuDHyyhQQ/services?to=1716784830092&windowSize=600000"
         }
      }
   ],
   "page":1,
   "pageSize":50,
   "totalHits":2,
   "adjustedTimeframe":{
      "windowSize":590000,
      "to":1716784830000
   },
   "_links":{
      "self":"{host_url}/api/application-monitoring/applications?to=1716784830092&windowSize=600000&page=1&pageSize=50"
   }
}
```

</details>

- `-k` オプションつけて `SSL certificate problem` 回避

### 指定したアプリケーションに属する各サービスのメトリクス（レイテンシー/平均値）を取得する

- refer: https://instana.github.io/openapi/#operation/getServicesMetrics 

request: 

POST の request body のうち、`applicationId` にアプリケーションを特定する ID を指定し、`metrics` に欲しい情報を指定する。

```sh
curl -k -X POST -H 'authorization: apiToken <token>' -H "Content-Type: application/json" -d '{"applicationId":"chrQOUFASMCqXLxpMzyBkQ", "metrics":[{"aggregation":"mean","metric":"latency"}]}' {host_url}/api/application-monitoring/metrics/services
```

<details><summary>response</summary>


```json
{
   "items":[
      {
         "service":{
            "id":"8bfb4e1aa590eab8f08f837b97acf5803a5737ed",
            "label":"cart",
            "types":[
               "HTTP"
            ],
            "technologies":[
               "nodeJsRuntimePlatform"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  9.055519053876479
               ]
            ]
         }
      },
      {
         "service":{
            "id":"3feb3dcd206c166ef2b41c707e0cd38d7cd325aa",
            "label":"catalogue",
            "types":[
               "DATABASE"
            ],
            "technologies":[
               "mongoDb"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  2.4755369928400954
               ]
            ]
         }
      },
      {
         "service":{
            "id":"1b946f915590dec37acb127a573c8cdd9ea99697",
            "label":"catalogue",
            "types":[
               "HTTP"
            ],
            "technologies":[
               "nodeJsRuntimePlatform"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  7.158313444709626
               ]
            ]
         }
      },
      {
         "service":{
            "id":"e86256b2787ee7ff0c33d0d4c6159cd922227b79",
            "label":"payment",
            "types":[
               "HTTP"
            ],
            "technologies":[
               "pythonRuntimePlatform"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  15.961822660098521
               ]
            ]
         }
      },
      {
         "service":{
            "id":"341f3d47be6d0964ff8da71dc29754341b210b21",
            "label":"ratings",
            "types":[
               "DATABASE"
            ],
            "technologies":[
               "mySqlDatabase"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  1.012242268041237
               ]
            ]
         }
      },
      {
         "service":{
            "id":"7bb083edad4751b79c6b2a9a76f28d0181ae8973",
            "label":"ratings",
            "types":[
               "HTTP"
            ],
            "technologies":[
               "phpRuntimePlatform",
               "httpd"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  11.761972498814604
               ]
            ]
         }
      },
      {
         "service":{
            "id":"a9bb2fe83b3a1ff2bcaef030dcf01173c1e49c83",
            "label":"redis:6379",
            "types":[
               "DATABASE"
            ],
            "technologies":[
               "redis"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  1.1781137035819915
               ]
            ]
         }
      },
      {
         "service":{
            "id":"12dea96fec20593566ab75692c9949596833adc9",
            "label":"user",
            "types":[
               "HTTP"
            ],
            "technologies":[
               "nodeJsRuntimePlatform"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  5.960809102402023
               ]
            ]
         }
      },
      {
         "service":{
            "id":"fa11441cb636961bfcb54dd54a4373555b3e8ac9",
            "label":"users",
            "types":[
               "DATABASE"
            ],
            "technologies":[
               "mongoDb"
            ],
            "snapshotIds":[
               
            ],
            "entityType":"SERVICE"
         },
         "metrics":{
            "latency.mean":[
               [
                  1716785940000,
                  2.7713754646840147
               ]
            ]
         }
      }
   ],
   "page":1,
   "pageSize":20,
   "totalHits":9,
   "adjustedTimeframe":{
      "windowSize":600000,
      "to":1716785940000
   }
}
```

</details>

#### 考察

- latency は API 結果と GUI 上の値が大体合ってる
- endpoints は API 結果と GUI 上の値が一致
- calls は API 結果が GUI の倍弱くらい（でも倍まで行かない）の値になっている？

### `metrics` に指定できる key/value は？

- `aggregation`: either of {`SUM`, `MEAN`, `MAX`, `MIN`, `P25`, `P50`, `P75`, `P90`, `P95`, `P98`, `P99`, `P99_9`, `P99_99`, `DISTRIBUTION`, `DISTINCT_COUNT`, `SUM_POSITIVE`, `PER_SECOND`} **※depending on metric specified**
- `granularity`: integer
- `numeratorTagFilterExpression`: object
- `metric`: string
	- `calls`, `erroneousCalls`, `latency`, `errors`, `traces`, `applications`, `services`, `endpoints`, `http.1xx`, `http.2xx`, `http.3xx`, `http.4xx`, `http.5xx`

### `metric` に指定できる値は、以下で確認可能

request:

```sh
curl -k --request GET \
  --url {host_url}/api/application-monitoring/catalog/metrics \
  --header 'authorization: apiToken <token>'
```

<details><summary>response</summary>


```json
[
   {
      "metricId":"calls",
      "label":"Call count",
      "formatter":"NUMBER",
      "description":"Number of received calls",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   },
   {
      "metricId":"erroneousCalls",
      "label":"Erroneous calls",
      "formatter":"NUMBER",
      "description":"The number of erroneous calls.",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   },
   {
      "metricId":"latency",
      "label":"Call latency",
      "formatter":"MILLIS",
      "description":"Latency of received calls in milliseconds.",
      "aggregations":[
         "MEAN",
         "P25",
         "SUM",
         "P75",
         "P50",
         "MAX",
         "P90",
         "P95",
         "P99",
         "P98",
         "MIN"
      ],
      "defaultAggregation":"MEAN"
   },
   {
      "metricId":"errors",
      "label":"Error rate",
      "formatter":"PERCENTAGE",
      "description":"Error rate of received calls. A value between 0 and 1.",
      "aggregations":[
         "MEAN"
      ],
      "defaultAggregation":"MEAN"
   },
   {
      "metricId":"traces",
      "label":"Trace count",
      "formatter":"NUMBER",
      "description":"Number of traces",
      "aggregations":[
         "SUM"
      ],
      "defaultAggregation":"SUM"
   },
   {
      "metricId":"applications",
      "label":"Application count",
      "formatter":"NUMBER",
      "description":"The number of applications.",
      "aggregations":[
         "DISTINCT_COUNT"
      ],
      "defaultAggregation":"DISTINCT_COUNT"
   },
   {
      "metricId":"services",
      "label":"Service count",
      "formatter":"NUMBER",
      "description":"The number of services.",
      "aggregations":[
         "DISTINCT_COUNT"
      ],
      "defaultAggregation":"DISTINCT_COUNT"
   },
   {
      "metricId":"endpoints",
      "label":"Endpoint count",
      "formatter":"NUMBER",
      "description":"The number of endpoints.",
      "aggregations":[
         "DISTINCT_COUNT"
      ],
      "defaultAggregation":"DISTINCT_COUNT"
   },
   {
      "metricId":"http.1xx",
      "label":"HTTP calls with 1XX responses",
      "formatter":"NUMBER",
      "description":"Counts the number of occurrences of HTTP status codes where 100 <= status code <= 199",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   },
   {
      "metricId":"http.2xx",
      "label":"HTTP calls with 2XX responses",
      "formatter":"NUMBER",
      "description":"Counts the number of occurrences of HTTP status codes where 200 <= status code <= 299",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   },
   {
      "metricId":"http.3xx",
      "label":"HTTP calls with 3XX responses",
      "formatter":"NUMBER",
      "description":"Counts the number of occurrences of HTTP status codes where 300 <= status code <= 399",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   },
   {
      "metricId":"http.4xx",
      "label":"HTTP calls with 4XX responses",
      "formatter":"NUMBER",
      "description":"Counts the number of occurrences of HTTP status codes where 400 <= status code <= 499",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   },
   {
      "metricId":"http.5xx",
      "label":"HTTP calls with 5XX responses",
      "formatter":"NUMBER",
      "description":"Counts the number of occurrences of HTTP status codes where 500 <= status code <= 599",
      "aggregations":[
         "SUM",
         "PER_SECOND"
      ],
      "defaultAggregation":null
   }
]
```

</details>

例えば、以下のような値が指定可能で、各メトリクスによって `aggregation` で指定できる内容も異なる。
- `calls`, `erroneousCalls`, `latency`, `errors`, `traces`, `applications`, `services`, `endpoints`, `http.1xx`, `http.2xx`, `http.3xx`, `http.4xx`, `http`

### 指定したサービスの詳細情報を取得

[こちら](#指定したアプリケーションに属する各サービスのメトリクス（レイテンシー/平均値）を取得する) と同じエンドポイントで、リクエストボディに `serviceId` を指定することでできそう。

## End User Monitoring(website monitoring/mobile app monitoring)

[参照URL](https://instana.github.io/openapi/#tag/Website-Metrics)

### Beacon metric pageload

request:

```sh
curl -k -X POST -H 'authorization: apiToken <TOKEN>' -H "Content-Type: application/json" -d '{"type": "PAGELOAD","metrics":[{"aggregation":"SUM","metric":"beaconCount"}, {"aggregation":"SUM","metric":"pageLoads"}, {"aggregation":"mean","metric":"beaconDuration"}]}' https://<HOST>/api/website-monitoring/v2/metrics
```

- ページロード回数（この二つは同じになるが、どう言う違いが。。）:
	{"aggregation":"SUM","metric":"beaconCount"}, {"aggregation":"SUM","metric":"pageLoads"}
- OnLoad 時間（平均）:
	{"aggregation":"mean","metric":"beaconDuration"}
- `timeFrame` で時間指定可能（他の POST 系リクエストでも同様の場合が多い）
- **アプリケーションを指定できるか？**

### JS エラー取得

request:

```sh
curl -k -X POST -H 'authorization: apiToken <TOKEN>' -H "Content-Type: application/json" -d '{"type": "error","metrics":[{"aggregation":"SUM","metric":"errors"}]}' https://<HOST>/api/website-monitoring/v2/metrics
```

### ページロード取得

request:

```sh
curl -k -X GET -H 'authorization: apiToken <TOKEN>' -H "Content-Type: application/json" https://<HOST>/api/website-monitoring/page-load;id=<pageloadId>;timestamp=<timestamp>
```

`pageloadId` は JS 側で取得できるモノらしい。。？
-> pageLoadId はページのロードごとに発行される ID なので、やりたいこととは違う
→ 指定した website に対するメトリクスをまとめて取得したい場合は以下のようなものをリクエストボディに追加する

```
{
  "tagFilterExpression": {
    "type": "TAG_FILTER",
    "name": "beacon.website.name",
    "operator": "EQUALS",
    "entity": "NOT_APPLICABLE",
    "value": <NAME> # ここは、`website-monitoring/config` のエンドポイントで取得できる`appName` か `name`
  }
}
```