New Relic の Logs や Dashboard や NRQL を使い始めた話

# 現在携わっているプロダクト "Sheeta" について

株式会社ドワンゴという会社の「ファンコミュニティ事業室」という部署でファンコミュニティシステム "Sheeta" というサービスの開発を行っています。

https://www.sheeta-info.com/

今、運用しているサイトとしては上記ページ内に取り上げられている Ado 様のサイト[^1]や THE YELLOW MONKEY 様のサイト[^2][^3]、文化放送様のサイト[^4][^5]などがあります。

# 自分の主な業務内容の紹介

私は前述のプロジェクトで「コンテンツチーム」（客観的にはコンテンツデリバリーシステムチームに近い意味として使われている。）と呼ばれているチームに属しています。ここでいうコンテンツは大きく「動画配信(VoD)」「LIVE 配信」「記事投稿機能」「応募機能」があります。この中で「動画配信」「LIVE 配信」を中心に設計等を行っています。

特に「LIVE 配信」はその特性上、簡単に不安定になってしまいやすく、また、視聴ユーザーの環境によってので、 New Relic のような可視化プラットフォームでパフォーマンスの確認や問題の早期発見に役立てていきたいと考えています。

# New Relic について

前述のプロジェクトで New Relic を導入しました。まだプロジェクトとしても最大限使いこなせてはいないかもしれませんが、私の立場で触ってみた感触について書きます。

New Relic には「ユーザータイプ」があります。

https://docs.newrelic.com/jp/docs/accounts/accounts-billing/new-relic-one-user-management/user-type/

1. **ベーシックユーザー** : 無料だがログやダッシュボードは見られる 
1. **コアユーザー** : 開発者向け機能が使える
1. **フルプラットフォームユーザー** : 全ての機能にアクセスできる

私が今、使っているのは無料の「ベーシックユーザー」です。このタイプでもログは全部見られるし、ダッシュボードの作成やダッシュボード上に NRQL を用いたログ情報の可視化や閲覧はできます。現状はまだ使い始めということもあり、このユーザータイプで New Relic を利用しています。

上記利用に関連して今の使い心地を書きます。

## Logs 機能

（具体的には New Relic ポータル -> Logs -> All logs を指す。）

アプリケーション等のログを見る機能です。

各ログにさまざまな属性をつけた形で保持していて、その属性を指定して必要なものだけカラムに表示したり、フィルタをかけることができます。

基本的にログを見たいだけであればこの機能・ページだけで見ることができます。

また、よく使う表示は `Saved views` というボタンを押せば view 一覧に保存できる。簡単なものはここに保存し、もう少し高度なものになると、以降に話をする "NRQL" を使って "Dashboard" に保存して使うことになると思われます。

## Dashboard

New Relic には **Dashboard** という機能があります。

ベーシックユーザーでは基本的に **NRQL** を使って特定の条件のログ一覧や、ログ情報を用いて様々なグラフを出すことができます。（面グラフ、円グラフ、折れ線グラフ、棒グラフ、テーブル等）詳しくは以下のページに書かれています。

https://docs.newrelic.com/jp/docs/query-your-data/explore-query-data/use-charts/chart-types/

また、 Dashboard 上では、値域を設定してテーブルのセルや Widget の色を変える（ある値を超えた場合に赤色で表示するなど）もすることができ、問題が視認しやすくなっています。

また、特定の文字列を注視させたい場合は、以下の NRQL の構文で、文字列の先頭に `🔴` こういう絵文字を文字列として連結するなどして注視させるようにすることができます。

ex.
- `🔴 error`
- `🟡 warning`
- `🟢 good`

また、同一 Dashboard 上で「ページ」を指定できることも地味に便利で、 Dashboard をわけるのとの違いは、フィルターの条件やログの期間は同じ Dashboard 全体に対して設定でき、ページをわけることで例えば開発者や企画の担当者等、注視する項目が変えられるという利点があります。

ex.
- 「開発者が軽く全体を見たり企画担当の方がちらっと見るページ」
- 「開発者が細かく内容を把握するためのページ」

## NRQL

https://docs.newrelic.com/jp/docs/nrql/get-started/introduction-nrql-new-relics-query-language/

ログの属性を DB のカラムに見立てて SQL ライクにデータを処理することができる言語です。 `WHERE` 句に検索条件を書き、 `SELECT` 句で表示する項目を選択できます。

`FROM` 句で（私の今の現状だと）ログを指定できます。ここが現在の課題なのですが、コアユーザー以上になるとログ以外のデータも指定できるようなので、今はだいぶ制限された使い方の可能性があります。また、特定の書き方（出力データ）にすると、上記の Dashboard のところでも話した「チャートタイプ」を指定できるようになります。（ex. 単一の `SELECT` 句のデータと `TIMESERIES` 句というウインドウサイズを指定する句を指定すると折れ線グラフで表示できるなど）

### SQL と NRQL で特に違うところ2選

#### FACET

`FACET` を使用すると、結果を属性値で分割してグループ化できます。[^6] たとえば、 `PageView` データで `deviceType` 別に `FACET` を行い、トラフィックの何割が携帯電話、タブレット、およびデスクトップデバイスから発生しているかを把握することができます。（公式ドキュメントからそのまま引用）

```SQL:FACET サンプル
SELECT count(*) FROM PageView FACET deviceType;
```

`FACET CASES` 句を使うと特定の条件を明示的にしていすることもできます。

```SQL:FACET CASES サンプル
SELECT count(*) FROM PageView 
FACET CASES 
(
  WHERE duration < 1, 
  WHERE duration > 1 AND duration < 10, 
  WHERE duration > 10
);
```

#### TIMESERIES

NRQL が SQL を使うデータベースと違ってグラフ化等をすることが多いという特徴に関連して `TIMESERIES` 句というものがあります。[^7] 1日前からのデータに対して30分ごとに統計データを出力する場合は以下のように書くことができます。

```SQL:TIMESERIES 句 サンプル
SELECT ... SINCE 1 day AGO TIMESERIES 30 minutes;
```

また、 Dashboard 上で使用するにあたって、期間をころころ切り替えて表示されることになるので、集計ウインドウを可変にするためのいくつかの特殊な引数があります。

- `MAX`
- `AUTO`

Dashboard 上では特に意図的にウインドウ時間を限定したい場合を除いてこちらの引数を使うことが多い気がします。

### 気になる点

ここからは、使っていて少々気になった点について書いていきます。

#### JOIN をすると `timestamp` が現れる話

特定の操作をすると `SELECT` 句で指定していないのに `timestamp` のカラムが現れることがあります。私の場合はサブクエリを `JOIN` することで出てきています。また、特に不必要だと思う挙動として「 `JOIN` した時の時間が表示されること」です。（なので Dashboard 上などでは、全てのレコードで表示した（＝計算した）時間が表示されるだけなので、何の役にも立ちません。

ネットで検索してみると以下のようなフォーラムの記事もありました。

https://forum.newrelic.com/s/hubtopic/aAX8W0000008bTyWAI/how-to-remove-timestamp-from-nrql-results-tabular-format

ページ内で課題として取り組んでいると書かれていますが、私はまだ解決方法を見つけられていません。（このページ内で書かれているように、 `SELECT` 句の最後に明示的に指定することにより、表の右端に表示し、スクロールバーが表示されるようなサイズの場合は優先的に隠れるようにしたりして邪魔にならないようにすることしかできていません。）

New Relic の性質上、データは基本的に timestamp を持つ（timestamp に対する処理が多いことも含めて）ため、こういった挙動にならざるを得ないのかもしれませんが、消すだけなので消したいです。。。

#### ユニークを取るのが難しい話

いわゆる `SQL` の `DISTINCT` です。

```SQL:SQL DISTINCT
SELECT DISTINCT name FROM name_list;
```

NRQL には `DISTINCT` がありません。なので頑張って似た挙動をさせようとすると以下のようになります。

```SQL:NRQL で DISTINCT
SELECT count(*) FROM name_list FACET name;
```

想定できると思いますが、無駄な `count` のカラムが付いてきます。もちろん非表示にできないので、 Dashboard 上にノイジーな情報が出てしまうので他の解決策が欲しいです。。。

|name|count|
|----|-----|
|山田|3|
|佐藤|4|
|鈴木|1|

#### JOIN に制限がある？ドキュメントにない挙動が存在する？

これについてはわからな過ぎてどういう現象かもここに書けないのですが、サブクエリを2段階 JOIN しようとすると、 JOIN の段階でカラムが参照できないのか、テーブルを生成できなくて困っています。

New Relic はログを可視化するサービスなのですが、特定のコンテンツに対するログはコード上の同じ個所で出せなかったり同じタイミングで出せないこともあるので、よくバラバラで出力されることがあると思います。私のサービスでの場合は配信システムで、同一コンテンツに対する「映像の情報」と「音声の情報」、また「その他の情報」の3つが別のログとして出力されるのですが、それらをコンテンツごとに JOIN しようとすると2回以上 JOIN をする必要が出ます。ここで、 JOIN に使う ID を `content_id` という名前にします。ここで、「映像の情報」と「音声の情報」を JOIN すると `content_id` という名前が変化するのか、その後「その他の情報」と JOIN しようとするときに `content_id` いう名前が参照できなくて JOIN できないという問題が発生しています。

（JOIN の操作の仕方によって、途中の表を出力してみたときに表示されるテーブルのカラムの名前が `Content Id` や `content_id` のままだったり、表記ゆれが発生するので、操作によってたまに名前が暗黙的に変換されている可能性があるのではと調べています。）

こちらに関しては鋭意調査中になります。。。

# 今後使っていきたい機能

## APM

APM は Application Performance Monitoring の略のようです。アプリケーションのパフォーマンスをモニタリングできるようです（そのままですが笑）

https://newrelic.com/jp/blog/best-practices/what-is-application-performance-monitoring

特に便利なのが、言語を指定すると自動でページが作成され数分で利用可能になるそうです。

ただ、ベーシックユーザーの場合は使えないようなので、ユーザータイプを調整して使っていくかを決定する必要があります。

## ブラウザモニタリング

https://docs.newrelic.com/jp/docs/new-relic-solutions/best-practices-guides/full-stack-observability/browser-monitoring-best-practices-guide/

ブラウザモニタリング機能も良いという話を聞くのでどういう機能か積極的に調べて、プロジェクトの目的とマッチするのであれば使っていくことを考えたいと思っています。

HTML の `head` タグに New Relic 上で生成された JavaScript のコードを埋め込むのとその他必要なところに軽くコードを使うだけで、ユーザの行動の情報をモニタリングできるようです。（僕のメインがバックエンドエンジニアなので、間違ったことを言っている可能性があります。間違っていたらすみません。）

エージェントを仕込むことによってブラウザから New Relic のサービスにデータを飛ばしてくれて New Relic 上でいい感じに表示してくれるらしいです。

## CodeStream

https://docs.newrelic.com/jp/docs/codestream/start-here/what-is-codestream/

IDE 上でメトリックスを見られる他、ソースコードとコラボレーションして問題がありそうな個所を可視化してくれるらしいです。チームの体制的に、私はめちゃくちゃがっつりコードを書くわけではないので、どこまで有効活用できるかと、がっつりコードを書く人はかなりの人数がいるため、全員をコアユーザーまで引き上げるか、ちゃんと機能を確認して活用していく必要があると考えています。

# その他気になるところ

## NRQL を Visual Studio Code 上で書いて簡単に反映されて欲しい

テンプレート変数が書けたり、同じ Dashboard のページで同じ条件・同じ期間（ `SINCE` 句、 `UNTIL` 句を使用したもの）を使うことが多かったり、定型的に書く部分が多かったり、そういう条件でぱっと見、複雑に見えるものが多いので、インデントなどできれいに書きたいが、基本的には New Relic 上のエディタで書かないといけないのでちょっとツラい。普段 Visual Studio Code を使っている弊害かもしれないが Visual Studio Code 上で編集して反映させたい（現在 CodeStream を使っていないわけだが、たぶん、ここは CodeStream の範囲外だと思っていますが、間違っていたらごめんなさい。）

ただ、話を聞くと、そもそも NRQL をがっつり書く状況になっているのが New Relic のモチベーションとずれている可能性がある（APM などで自動生成をするのがメインの可能性がある）のでこの辺りは引き続き調べて解決していきたいと考えています。

## アプリケーション側でどこまで New Relic に寄り添って書くか

New Relic 上で取り回しやすい形にどこまでアプリケーション側で対応するかについて考えています。この辺りは APM 等で解決できる問題の可能性もあるので並行して確認していく予定です。例えば、特定の ID について処理の都合で接続時のログ等には出すことができなかったりするが（まだ ID が取得できていない等）、人間が見る場合には次の行を見ればよいが、 New Relic 上で加工する場合は NRQL で処理するため、 ID で JOIN するなどしないといけないため、この辺りを考慮してログを出すべきか等の課題があると思っています。（たぶん、人間では「この行と次の行は関連していて合わせるとこういう状況である」という判断ができるが、 NRQL では「次の行」や「このメッセージとこのメッセージの行を同じ ID の情報として連結して扱う」が簡単にはできない。この辺りにどこまで考慮してログを出してあげるか等を考えている。）

# 最後に

私が久しぶりに書いた記事を最後まで読んでいただきありがとうございます。 New Relic に関して、まだまだ簡単な使い方しかできていないので、開発のパフォーマンスを上げるためにも、これからも引き続き使い方を調べて最大限に活用していきたいと思います。

また、最近、アウトプットが足りていない自覚はあるので、これを機に改めて考えていきたいと思いました。以前までの記事と違い、だいぶ使っている技術範囲が変わりました。新しいことを勉強しつつ、アウトプットもしてこれからも様々なことにチャレンジしていきたいと思います。

この記事が読んでくださった方に少しでも役に立てれば嬉しいと思います。また、既に New Relic を活用されている方で、使用感や内容の誤りに気付かれた方は、気軽にコメントで教えていただけると幸いです。

[^1]: https://ado-dokidokihimitsukichi-daigakuimo.com/
[^2]: https://tymstorage.jp/
[^3]: https://realsound.jp/tech/2024/10/post-1806730.html
[^4]: https://qlover.jp/
[^5]: https://dwango.co.jp/news/5133564429467648/
[^6]: https://docs.newrelic.com/jp/docs/nrql/nrql-syntax-clauses-functions/#sel-facet
[^7]: https://docs.newrelic.com/jp/docs/nrql/nrql-syntax-clauses-functions/#sel-timeseries