NewRelicの情報をChatGPTに分析してもらってみた

# はじめに
NewRelicの分析をChatGPTにやってもらってみました。
NewRelicからの情報取得およびChatGPTへの連携は、AWS Lambda+Pythonで実施します。

# 作業手順
※前提条件：NewRelicへデータが連携されていること。

まずはLambdaを作っていきます。

検索窓に「Lambda」と検索し、Lambdaを押下します。
![スクリーンショット 2025-05-17 22.25.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/afa6792a-9849-4cc6-89a7-3b49be445e35.png)

サイドメニューの「関数」を押下する。
![スクリーンショット 2025-05-17 22.26.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/f9fe46ea-d346-487d-8eb8-7a28289e7ea4.png)

右側の「関数を作成」を押下する。
![スクリーンショット 2025-05-17 22.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/805652b1-a13e-414f-afda-ee59cd6bccbc.png)

関数名を入力し、ランタイムに「Python 3.13」を選択し、「関数の作成」を押下する。
![スクリーンショット 2025-05-17 22.29.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/a74bb15e-59e9-4a73-8e09-9206eeac9e0c.png)

以下のソースを貼り付けて、「Deploy」を押下する。
![スクリーンショット 2025-05-17 22.47.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/662d92d3-1f24-46d9-b728-84b56dd59131.png)

```python:Lambdaのコードソース
import os
import json
from openai import OpenAI
from gql import gql, Client
from gql.transport.requests import RequestsHTTPTransport

# 環境変数からキーを取得
NEWRELIC_KEY = os.environ["NEWRELIC_KEY"]
NEWRELIC_ID = os.environ["NEWRELIC_ID"]
CHAT_GPT_KEY = os.environ["CHAT_GPT_KEY"]

# OpenAIクライアント初期化
client = OpenAI(api_key=CHAT_GPT_KEY)

# gqlクライアント初期化
transport = RequestsHTTPTransport(
    url="https://api.newrelic.com/graphql",
    headers={"API-Key": NEWRELIC_KEY, "Content-Type": "application/json"},
    verify=True,
    retries=3,
)
gql_client = Client(transport=transport, fetch_schema_from_transport=True)

# New Relicデータ取得（gql版）
def get_newrelic_data():
    query = gql(f"""
    {{
      actor {{
        account(id: {NEWRELIC_ID}) {{
          nrql(query: "SELECT * FROM Span SINCE 30 minutes ago") {{
            results
          }}
        }}
      }}
    }}
    """)
    result = gql_client.execute(query)
    return result

# ChatGPTに送信して分析（長さ制限あり）
def analyze_with_chatgpt(nr_data):
    summary_data = json.dumps(nr_data.get("actor", {}), ensure_ascii=False)
    limited_input = summary_data[:8000]

    response = client.chat.completions.create(
        model="gpt-4",
        messages=[
            {
                "role": "system",
                "content": "あなたは優秀なSREエンジニアです。傾向分析結果と改善点を箇条書きで回答してください。"
            },
            {
                "role": "user",
                "content": f"""以下のNewRelicデータを分析してください：
                分析の観点は以下の通り。
                ・各URIの応答が100ms未満であること。：OK or NG
                　理由）
                ・エラーが未発生であること。：OK or NG
                　理由）
                ・特定のユーザーやIPに偏ったアクセスが発生していないこと。：OK or NG
                　理由）
                ・時間帯によるアクセス集中やスパイクが発生していないこと。:OK or NG
                　理由）
                
                また、エラーが発生している場合、ソースコードの改善点も回答してください。

                {limited_input}
                """
            }
        ]
    )
    return response.choices[0].message.content

# Lambdaハンドラ
def lambda_handler(event, context):
    nr_data = get_newrelic_data()
    analysis = analyze_with_chatgpt(nr_data)
    return {
        "statusCode": 200,
        "body": analysis
    }
```
【ポイント】
- ソースコードはChatGPTに書いてもらいました。（NerdGraph APIの使用は指定しましたが、それ以外は生成してくれました。）
- NRQLをNewRelicにPOSTすることで情報取得できます。
- gpt-4モデルの場合、10,000トークン/分の制限があるのでリミットを掛けています。

:::note alert
上記の例では各APIキーを環境変数に入れてますが、セキュリティ面からするとAWS Secrets Managerなどで管理するのが望ましいです。
:::


環境変数も設定していきます。

設定 > 環境変数に遷移し、「編集」を押下する。
![スクリーンショット 2025-05-17 23.39.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/95794f97-fa4e-4f94-aa8e-6b7a3e436a61.png)

「環境変数の追加」を押下した後、以下の環境変数を設定して「保存」を押下する。
- CHAT_GPT_KEY：ChatGPTのAPIキー
- NEWRELIC_ID：NewRelicのアカウントID
- NEWRELIC_KEY：NewRelicのユーザキー
![スクリーンショット 2025-05-17 23.43.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/1e7a86b2-6126-4a13-a0a4-cf919c8931f5.png)

応答に時間がかかるので、タイムアウト時間も伸ばしておきます。

設定 > 一般設定に遷移し、「編集」を押下する。
![スクリーンショット 2025-05-18 15.54.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/6fc4ecdb-80e6-4578-817b-67bd0a4b0fd8.png)

タイムアウト時間を1分にして「保存」を押下する。
![スクリーンショット 2025-05-18 15.56.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/103d58e4-1387-4454-a193-77fee2d1cd7c.png)


![スクリーンショット 2025-05-17 23.48.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/2c2d17ef-12d8-4f82-9789-428ea3f40e12.png)

引き続き、前述のPythonソースコードでインポートしているモジュールを使うためのLayerを作っていきます。

Pythonライブラリをzipファイルに圧縮する
```sh:sh
mkdir -p python/lib/python3.13/site-packages
pip install --platform manylinux2014_x86_64 --implementation cp --python-version 3.13 --only-binary=:all: openai>=1.14.0 jiter gql requests_toolbelt -t python/lib/python3.13/site-packages/
zip -r layer.zip python
```
:::note warn
普通に持ってくると「No module named 'pydantic_core._pydantic_core'」が出てしまったので、色々指定しています。（とりあえずChatGPTを動かすための指定なので、実際に動かす際は各環境に合った指定をする必要があります。）
:::


サイドメニューの「レイヤー」を押下する。
![スクリーンショット 2025-05-18 0.20.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/71fc5859-e8f1-4111-bebd-211512e10aee.png)

右側の「レイヤーの作成」を押下する。
![スクリーンショット 2025-05-18 0.22.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/5746ace0-053c-47e2-9cd4-d885b2eb5e3d.png)

関数名を入力し、zipファイルの場所やランタイムを選択した後、「作成」を押下する。
（ローカルからのアップロード、S3の場所指定どちらでも可。）
![スクリーンショット 2025-05-18 0.26.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/6cb1e316-6a37-441c-b4df-3932159663c5.png)


先ほどのLambda関数の画面に戻り、下部の「レイヤーの追加」を押下する。
![スクリーンショット 2025-05-18 0.18.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/5794a3b9-7411-42d5-99eb-16a92f07f402.png)

「カスタムレイヤー」を指定し、先ほど作成したレイヤーを選択し、「追加」を押下する。
![スクリーンショット 2025-05-18 0.47.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/f208f093-9c63-4f83-91f2-1ee597ea6ae8.png)

あとは「テスト」を押下して実行する。
![スクリーンショット 2025-05-18 2.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/642c0082-f510-4bb2-9a30-db44569442cd.png)

<table>
<tr><td>出力結果　※見やすい様に改行しています。</td></tr>
<tr><td>
以下に傾向分析結果と改善点を記載します。

傾向分析結果：
1. 各URIの応答が100ms未満であること：OK
   理由：全てのトランザクションが100ms（0.1秒）を大幅に下回っており、非常に高速な応答を実現しています。

2. エラーが未発生であること：NG
   理由： \"error.group.name\": \"org.springframework.web.HttpRequestMethodNotSupportedException\"が含まれており、GETリクエストがサポートされていないというエラーが発生しています。

3. 特定のユーザーやIPに偏ったアクセスが発生していないこと：OK
   理由：分析対象のデータには特定のユーザーやIPからの偏ったアクセスについての情報は含まれていません。

4. 時間帯によるアクセス集中やスパイクが発生していないこと：OK
   理由：分析対象のデータには時間帯によるアクセス集中やスパイクについての情報は含まれていません。

改善点：
1. \"error.group.name\": \"org.springframework.web.HttpRequestMethodNotSupportedException\"のエラーに対して、ソースコードをGETリクエストをサポートするように改修する。

具体的なコード修正は以下の通り：
修正前：
```java
@PostMapping(\"/api/select\")
public ResponseEntity<Void> selectItems(){
// Some Implementation
}
```
修正後：
```java
@GetMapping(\"/api/select\")
public ResponseEntity<Void> selectItems(){
// Some Implementation
}
```
2.サーバのパフォーマンス改善やレスポンス時間の短縮に役立つ最適化を行い、応答時間を100ms未満にする。具体的な手段としては、キャッシュの利用、データベースの最適化、非同期処理の導入などが考えられます。"
</td></tr>
</table>

```json:元データ
{
  "statusCode": 200,
  "body": "以下に傾向分析結果と改善点を記載します。\n\n傾向分析結果：\n1. 各URIの応答が100ms未満であること：OK\n   理由： 全てのトランザクションが100ms（0.1秒）を大幅に下回っており、非常に高速な応答を実現しています。\n\n2. エラーが未発生であること：NG\n   理由： \"error.group.name\": \"org.springframework.web.HttpRequestMethodNotSupportedException\"が含まれており、GETリクエストがサポートされていないというエラーが発生しています。\n\n3. 特定のユーザーやIPに偏ったアクセスが発生していないこと：OK\n   理由：分析対象のデータには特定のユーザーやIPからの偏ったアクセスについての情報は含まれていません。\n\n4. 時間帯によるアクセス集中やスパイクが発生していないこと：OK\n   理由：分析対象のデータには時間帯によるアクセス集中やスパイクについての情報は含まれていません。\n\n改善点：\n1. \"error.group.name\": \"org.springframework.web.HttpRequestMethodNotSupportedException\"のエラーに対して、ソースコードをGETリクエストをサポートするように改修する。\n\n具体的なコード修正は以下の通り：\n修正前：\n```java\n@PostMapping(\"/api/select\")\npublic ResponseEntity<Void> selectItems(){\n// Some Implementation\n}\n```\n修正後：\n```java\n@GetMapping(\"/api/select\")\npublic ResponseEntity<Void> selectItems(){\n// Some Implementation\n}\n```\n\n2. サーバのパフォーマンス改善やレスポンス時間の短縮に役立つ最適化を行い、応答時間を100ms未満にする。具体的な手段としては、キャッシュの利用、データベースの最適化、非同期処理の導入などが考えられます。"
}
```

修正案はツッコミどころあるものの、分析はしてくれました。
実際にソースコードを渡してあげるともう少し具体的なアドバイスをしてくれそうです。


# おわりに
NRQLで取得した情報をもとにChatGPTが分析してくれました。
AWS Lambdaなどで作成して定期的に取得して分析してもらったり、
蓄積した情報から分析みたいなことをAIにしてもらっても良さそうですね