New Relic JavaエージェントをDocker＋Spring Boot構成で導入してみた

# はじめに
New RelicのJavaエージェントをDockerで導入し、
ECS（Fargate）上でSpring Bootアプリケーションと連携させてみました。

# 作業手順
「Integrations & Agents」を押下する。
![スクリーンショット 2025-05-03 13.44.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/f0b18d3b-8eee-47fb-8c37-680b701d1b49.png)

「Java」を押下する。
![スクリーンショット 2025-05-03 13.48.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/33b4e303-2993-4d2a-9fde-d1a35f9ba395.png)

「Docker」を押下する。
![スクリーンショット 2025-05-03 14.12.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/d03c19d6-47f1-4128-a671-5546db276d16.png)

「Create a new key」を押下し、APIキーが表示されたら、「Continue」を押下する。
![スクリーンショット 2025-05-03 14.13.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/387affac-4745-46e5-90c8-adbff02f8746.png)

:::note info
APIキーの用途（Notes）が空白で作成されるので、後で必ず記載しましょう。
後で何のAPIキーかわからなくなることがあるので。
:::

:::note alert
APIキーはここでしか確認できないので、忘れずに保管しておきましょう。
:::

「No, running on Linux.」を押下する。
![スクリーンショット 2025-05-03 14.38.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/736f3e66-196e-4f33-812e-ccc9a136048a.png)

「Copy to clipboard」を押下する。
![スクリーンショット 2025-05-03 20.01.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/9e4923ef-efa9-45a7-969e-0496fddb6cd6.png)

コピーしたcurlをターミナルなどで実行する。
```shell-session:sh
$ curl -O https://download.newrelic.com/newrelic/java-agent/newrelic-agent/current/newrelic-java.zip
```

取得したzipファイルを解凍する。（newrelicフォルダが作成されます。）
```shell-session:sh
$ unzip newrelic-java.zip 
```
中身はこんな感じです。これらをnewrelicフォルダごとJavaプロジェクトフォルダに配置します。
```shell-session:sh
$ ls newrelic 
extension-example.xml           newrelic-api-javadoc.jar        newrelic.jar
extension.xsd                   newrelic-api-sources.jar        newrelic.yml
LICENSE                         newrelic-api.jar                THIRD_PARTY_NOTICES.md
```

アプリケーション名を設定し、newrelic.ymlをダウンロードする。
![スクリーンショット 2025-05-03 20.25.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/c9e175a9-69b5-45ea-b5ff-667a0f944047.png)

ダウンロードした「newrelic.yml」を先ほど解凍したnewrelicフォルダ配下の同名ファイルに差し替えます。

全て実施したら「Continue」を押下する。
![スクリーンショット 2025-05-03 20.30.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/171a0719-0cf0-4876-993e-4b9c01d9cbec.png)

DockerfileにNewRelicエージェントを起動する処理を追加します。

```Dockerfile:Dockerfile
FROM amazoncorretto:17-alpine

COPY target/app-0.0.1-SNAPSHOT.jar /usr/local/app.jar

RUN mkdir -p /usr/local/newrelic
ADD ./newrelic/newrelic.jar /usr/local/newrelic/newrelic.jar
ADD ./newrelic/newrelic.yml /usr/local/newrelic/newrelic.yml

EXPOSE 8080

ENTRYPOINT ["java", "-javaagent:/usr/local/newrelic/newrelic.jar", "-jar", "/usr/local/app.jar"]
```

Dockefileを修正したら、「Continue」を押下する。
![スクリーンショット 2025-05-03 20.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/8d251c8f-7b5c-4959-a6a7-6eec0dd79212.png)

infrastructure agentの導入については、今回は導入しないので「Skip」を押下する。
（コンテナのCPUやメモリの使用率などが連携されるようになります。）
![スクリーンショット 2025-05-03 15.08.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/614bb5c5-a8f4-47d0-9fb2-3820dc642a93.png)

「Test connection」を押下する。
![スクリーンショット 2025-05-03 15.18.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/4743571b-81d0-4d4c-8c42-dca2ba6b9074.png)

Statusが「Successful」となっていることを確認したら、「See your data」を押下する。
![スクリーンショット 2025-05-03 21.32.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/81792f0f-76ab-4b8e-831d-65b7698028b9.png)

NewRelicへの連携が開始されると、色々と情報が連携されるようになります。
例えば、トランザクション情報だと、APM & Services > Transactionsを見ると、
全体的なスループットやTATなど確認することができます。![スクリーンショット 2025-05-03 23.18.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/caeab244-01de-4131-bfdc-9d7bd13ee492.png)

# 追加設定
デフォルトでも色々と情報を取得できるのですが、追加で様々な情報を取得できます。

### レスポンス情報を取得する
基本的に、NewRelicはレスポンス情報については連携していないようで、
連携したい場合は、明示的に設定する必要があるみたいです。
その場合には、addCustomParameter() というメソッドを使います。

以下のように、Javaソースにて、NewRelicエージェントをインポートします。
```java:java
import com.newrelic.api.agent.NewRelic;
```
あとはこんな感じでメソッドを追加するだけです。
第一引数が表示名称、第二引数が値です。
```java:java
NewRelic.addCustomParameter("resultCode", response.getResultCode());
```

すると、以下のようにCustom attribute項目として連携されるようになります。
![スクリーンショット 2025-05-04 8.08.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/d1c16b51-5918-4494-b4d9-285a98cdc821.png)

### リクエストボディ項目を取得する
リクエストボディ項目については、
newrelic.ymlに以下の設定を追加することで、連携対象項目を追加できます。

common.attributes.includeに連携したい項目名を記載します。
```yml:newrelic.yml
common:
  attributes:
    include: request.parameters.email
```
設定すると、APM & Services > Transactions > Attributesに出力されます。
![スクリーンショット 2025-05-04 8.00.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/31449b1e-36e5-4b05-a079-363954554a36.png)

:::note info
request.parameters.*とした場合、リクエストボディの全項目を取得します。
複数項目を指定したい場合は、カンマ区切りで設定すると良いです。
:::

:::note warn
request.parametersによる情報取得はGETメソッドの場合もしくは、Content-Typeが「application/x-www-form-urlencoded」の場合は取得できるみたいです。
JSON形式などの場合は、addCustomParameter() で取得する必要がありそう。
:::

### リクエストヘッダ項目を取得する
リクエストボディと同様にヘッダも連携する対象を追加できます。
common.transaction_eventsにcustom_request_headersを追加し、
リスト形式で連携したいヘッダ名を記載します。
```yaml:newrelic.yml
common:
  transaction_events:
    custom_request_headers:
        - header_name: "x-forwarded-for"
```

同じく、APM & Services > Transactions > Attributesに出力されます。
![スクリーンショット 2025-05-04 8.08.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/d1c16b51-5918-4494-b4d9-285a98cdc821.png)

NewRelic上の表示名を変更することも可能です。詳細は以下のページを参照。

https://docs.newrelic.com/jp/docs/apm/agents/java-agent/configuration/java-agent-configuration-config-file/#tt-custom-request-headers

# 気にした方が良いポイント
触ってみて思いましたが、以下の点は検討しておいた方が良さそうです。

### ログ出力対象を制御する
NewRelicエージェントを導入すると、デフォルトでログ連携がされるようになります。
Logs > All logsなどを見ると、INFO、WARN、ERROR全て出力されることがわかります。
![スクリーンショット 2025-05-04 17.06.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/b6975fe3-198d-41af-a7db-6fa9f99488e4.png)

ログはコスト増や機密情報流出のタネになりやすいので、しっかり制御した方が良さそうです。
どのレベルのログをNewRelicへ連携するかについては、アプリ側で制御する必要があります。（試しに、logback-spring.xmlでWARN指定すると、NewRelicへ連携されるログレベルもWARN以上となりました。）
ちなみに、newrelic.ymlの以下あたりをfalseにするとログ連携されなくなります。
```yaml:newrelic.yml
common:
  application_logging:
    enabled: false
    forwarding:
      enabled: false
```

:::note warn
newrelic.ymlにlog_levelという項目がありますが、これはNewRelicエージェントログの出力対象を制御する項目で、エージェントの連携対象を制御するものではありません。
:::

上記以外にも、例えばAPM & Services > Errors (errors inbox)あたりにも、
想定外の内容が出力されていないかは確認した方が良いです。


### 取得対象のトランザクションを制御する
例えば、LBからのヘルスチェックをSpring Bootで受け付けたりする場合（/actuator/healthなどに対して）そのトランザクション情報がNewRelicへ連携されます。
そうすると、NewRelicにデータ取込された分だけコストがかかってしまうので、不要であれば除外する必要があります。

様々なやり方があるみたいですが、NerdGraphを使うとトランザクション情報を除外できるみたいです。

サイドメニューの「Apps」を押下する。
![スクリーンショット 2025-05-13 21.52.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/9898aff5-5422-48b4-9a02-7c3ea639476b.png)

「NerdGraph API Explorer」を押下する。
![スクリーンショット 2025-05-13 21.52.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/32007907-e9bd-4182-9d0b-609e6adbeb54.png)

左上にUSER KEYを設定し、「Submit」を押下する。
![スクリーンショット 2025-05-13 21.53.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/a1a70e01-20ac-4191-8df8-da1645486e38.png)

クエリを貼り付けて、実行ボタンを押下する。
![スクリーンショット 2025-05-14 8.01.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/29072586-4931-4c73-bd96-b3e47c021226.png)

例）トランザクション情報からNLBからのヘルスチェックを除外するクエリ
```:NerdGraph
mutation {
  nrqlDropRulesCreate(
    accountId: <アカウントID（7桁の数字）>
    rules: [
      {
        action: DROP_DATA
        nrql: "SELECT * FROM Transaction WHERE request.headers.userAgent = 'ELB-HealthChecker/2.0'"
        description: "Exclude HealthCheck URI Transactions from data ingestion"
      }
    ]
  ) {
    successes {
      id
    }
    failures {
      submitted {
        nrql
      }
      error {
        reason
        description
      }
    }
  }
}

```

トランザクション情報は連携されなくなりました。
![スクリーンショット 2025-05-13 22.10.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508112/0bb98dbe-1767-4254-8694-a01fd072cb40.png)

あとは、試していないですが、以下でもできそう。

https://docs.newrelic.com/jp/docs/apm/agents/java-agent/instrumentation/ignore-transactions-using-api/


### サンプリング数を適切に設定する
newrelic.ymlの以下項目は、New Relicエージェントが1回の収集間隔でTransactionまたはSpanを取得する件数を制御するものです。（初期値は2,000）
トランザクション量に応じて取得すると良いですが、増やすとその分だけ負荷が掛かってしまうので注意です。
- common.transaction_events.max_samples_stored：Transaction用
- common.span_events.max_samples_stored；Span用

# おわりに
NewRelicは様々な情報を細かく取得できそうで、かつ、情報を落とす仕組みもあるので、
基本的には連携させてNewRelic側で除外設定をして必要な情報を監視するのが良さそうです。

個人的にはトランザクション情報がSQLに似たクエリで検索できる点が良かったです。