みなさんこんにちは。マネージドサービス課の塩野です。
New Relic には Streaming Export という機能があります。これは、現在インジェストされているデータをニアリアルタイムに外部へ流し出す仕組みで、AWS Kinesis Data Firehose を経由して S3 や Redshift などに継続的にデータを送信できます。設定は NerdGraph という New Relic の GraphQL API を使って行い、「どのデータを」「どこに」送るかをルールとして定義します。
この Streaming Export 機能を利用するには Pro または Enterprise エディション、かつ Data Plus の契約が必須です。Standard エディションに Data Plus を追加しただけでは利用できない点に注意してください。事前に契約状況を確認しておきましょう。
今回は Streaming Export を使って New Relic のログを S3 にアーカイブし、最終的に Amazon Athena でクエリできる状態にするまでの手順と、途中でハマった圧縮設定の問題を紹介します。
S3 にログを保管する前に知っておきたいこと
New Relic のログ保管期間とコスト
New Relic のログ保管期間は契約プランによって異なります。Original Data プランではデフォルトで 30 日、Data Plus プランでは 最大 120 日まで保管できます。さらに延長したい場合は Extended Retention アドオン($0.05/GB/月・30 日単位)を追加するか、最大 7 年間の長期保管が可能な Live Archives を検討することになります。
ただし Live Archives は Advanced Compute との併用が必要で、保管だけでなくクエリ実行時にも別途課金が発生します。頻繁に参照しないアーカイブデータに対して New Relic 内でクエリコストを払い続けるのは、運用コスト的に見合わないケースもあります。
Streaming Export と AWS 側にかかる費用
Streaming Export を使う場合の費用は、大きく 2 つに分かれます。
まず New Relic 側では、Data Plus プランの料金が適用されます。Original Data プランは $0.40/GB のところ、Data Plus では $0.60/GB になります(いずれも月 100 GB の無料枠を超えた分)。Streaming Export 機能自体の個別課金は公式ドキュメントに明記されておらず、Data Plus に含まれる機能として提供されていると推測されます。
AWS 側では Kinesis Firehose の転送料がかかります。料金は GB あたり約 $0.029(5KB 単位切り上げ)で、これに S3 のストレージ料が加わります。S3 の標準ストレージは $0.023/GB/月程度なので、大量のログを長期保管する場合でも Live Archives と比べてコストを大幅に抑えられます。
S3 保管の注意点
S3 にエクスポートされたデータは New Relic のプラットフォーム外に出るため、New Relic の UI からは直接クエリできません。Athena や他の分析ツールを別途セットアップする必要があります。また、Streaming Export はインジェスト時のデータだけを対象とするため、機能を無効にしている期間のデータは遡って取得できません。過去データが必要な場合は Historical Data Export を使う必要があります。
全体構成と設定の流れ
設定は大きく以下の順番で進めます。
- AWS S3 バケットの作成
- IAM ロール / ポリシーの設定(Firehose が S3 に書き込むための権限)
- Kinesis Firehose Delivery Stream の作成
- New Relic 側で NerdGraph を使ったストリームルールの作成
AWS 側のリソースを先に用意し、作成した ARN などを New Relic 側のルール設定に登録する流れです。
flowchart TD
A["New Relic\nログ収集"]
B["Streaming Export\n(Data Plus 必須)"]
C["Kinesis Firehose\nDelivery Stream"]
D["Amazon S3\nログアーカイブ"]
E["Amazon Athena\nログ分析"]
A --> B
B --> C
C --> D
D --> E
AWS 側の設定
S3 バケットの作成
まず S3 バケットを作成します。バケット名はあとで Firehose の設定に使うので控えておきましょう。バージョニングは必須ではありませんが、誤削除対策として有効にしておくと安心です。暗号化は SSE-S3 を選択しておけば追加コストなく保護できます。
IAM ロールの設定
IAM ロールは目的別に 2 つ作成します。
① Firehose が S3 に書き込むためのロール
信頼ポリシーに firehose.amazonaws.com を指定し、S3 への書き込みに必要な最小権限を付与します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:GetBucketLocation", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:AbortMultipartUpload" ], "Resource": [ "arn:aws:s3:::YOUR_BUCKET_NAME", "arn:aws:s3:::YOUR_BUCKET_NAME/*" ] } ] }
② New Relic が Firehose にデータを送信するためのロール(Cross-Account ロール)
こちらが重要な設定です。New Relic の AWS アカウント(アカウント ID: 888632727556)を信頼する Cross-Account ロールとして作成します。
IAM コンソールで「別の AWS アカウント(Another AWS account)」を選択し、以下を入力します。
- アカウント ID:
888632727556(New Relic のエクスポート用 AWS アカウント ID) - 外部 ID(External ID): New Relic のアカウント ID(エクスポート元のアカウント ID)
このロールにアタッチするポリシーには
firehose:PutRecordとfirehose:PutRecordBatchを許可します。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "firehose:PutRecord", "firehose:PutRecordBatch" ], "Resource": "arn:aws:firehose:YOUR_REGION:YOUR_AWS_ACCOUNT_ID:deliverystream/YOUR_STREAM_NAME" } ] }
作成したロールの ARN は NerdGraph のミューテーション(awsParameters.role)で使用するので控えておきましょう。
Kinesis Firehose の設定
Firehose の Delivery Stream を作成します。Source は「Direct PUT」を選択し、Destination に S3 バケットを指定します。
バッファ設定はサイズ(デフォルト 5 MB)と時間(デフォルト 300 秒)のいずれか条件を満たしたタイミングで S3 に書き出す仕組みです。ログのリアルタイム性をあまり求めない場合は時間を長めに設定するとオブジェクト数が減ってコスト効率が上がります。
圧縮設定については後述の「問題発生」セクションで詳しく触れますが、Firehose 側で gzip を選択することを推奨します。
検証時の設定値
- ソースと送信先を選択
- ソース: DirectPut
- 送信先: Amazon S3
- Firehose ストリーム名
- Firehose ストリーム名: 任意の名前を設定
- 送信先の設定
- S3 バケット: 作成したバケット名を入力
- 改行の区切り文字: 有効ではありません
- 動的パーティショニング: 有効ではありません
- S3 バケットと S3 エラー出力プレフィックスタイムゾーン: Asia/Tokyo
- バックアップの設定
- バッファのヒント、圧縮、暗号化
- バッファサイズ: 1MiB
- バッファ間隔: 300 秒
- S3 圧縮と暗号化
- データレコードの圧縮: GZIP
- バッファのヒント、圧縮、暗号化
- 詳細設定
- サービスアクセス
- 既存の IAM ロールを選択: 前項で作成したIAMロールを指定
- サービスアクセス
New Relic 側の設定(NerdGraph API)
NerdGraph とは
NerdGraph は New Relic が提供する GraphQL API で、下記リンクよりアクセスして使用します。ここで使用するAPI キーは User キーが必要で、NerdGraph Explorer の画面上部で設定します。
https://api.newrelic.com/graphiql

ストリームルールの作成
以下のミューテーションで Streaming Export のルールを作成します。payloadCompression を DISABLED にしている点がポイントです(詳細は次のセクションで説明します)。下記クエリでの注意点として、YOUR_ROLE_NAMEの部分には、前項の IAM ロールの設定 で設定したロール名を指定すること、nrqlの項には実際に転送したいフィルタとなるクエリを記載すること(下記サンプルでは全てのログが送信されるため、フィルタを追加して送信量を制限してください)などがあります。
mutation { streamingExportCreateRule( accountId: YOUR_ACCOUNT_ID ruleParameters: { name: "log-export-to-s3" description: "Export logs to S3 via Firehose" payloadCompression: DISABLED nrql: "SELECT * FROM Log" } awsParameters: { awsAccountId: "YOUR_AWS_ACCOUNT_ID" deliveryStreamName: "YOUR_STREAM_NAME" region: "ap-northeast-1" role: "YOUR_ROLE_NAME" } ) { id status } }
実行後、status が CREATION_IN_PROGRESS から ENABLED になれば設定完了です。反映まで最大 6 分ほどかかることがあります。
S3 に保存できたが問題が発生した ー gzip 二重圧縮の落とし穴
症状と原因
S3 へのデータ書き込みは成功していたものの、ファイルを開くと文字化けしていました。原因は gzip の二重圧縮です。
New Relic の Streaming Export 側で payloadCompression: GZIP を設定すると、すでに gzip 圧縮されたバイナリデータが Firehose に送信されます。そこへさらに Firehose 側でも gzip 圧縮をかけると、圧縮が二重になった状態で S3 に書き出され、通常の展開では読めないファイルになってしまいます。
試行錯誤の記録
以下の 4 パターンを試して確認しました。
| New Relic 圧縮 | Firehose 圧縮 | 結果 |
|---|---|---|
| GZIP | GZIP | ❌ 文字化け |
| GZIP | 無圧縮 | ❌ 文字化け |
| 無圧縮 | 無圧縮 | ✅ 正常 |
| 無圧縮 | GZIP | ✅ 正常 |
New Relic 側で gzip をかけた時点で圧縮済みのバイナリになるため、Firehose を無圧縮にしても結果は変わりませんでした。New Relic 側を無圧縮(DISABLED)にし、Firehose 側で gzip を設定するのが正解でした。この構成なら S3 に gzip ファイルとして保存されるため、ストレージコストの削減も期待できます。Firehose の圧縮はインジェスト料金に影響せず、S3 側の容量だけが減るのでコスト面でもメリットがあります。
Athena でログを検索する
外部テーブルの作成
S3 に保存された JSON ファイルを Athena でクエリするには外部テーブルを定義します。New Relic のログフィールドにはドット(.)を含むキー(newrelic.source など)があるため、JSON SerDe の mapping プロパティを使ってカラム名をマッピングする必要があります。
CREATE EXTERNAL TABLE newrelic_logs ( `timestamp` BIGINT, `message` STRING, `hostname` STRING, `severity` INT, `newrelic_source` STRING, `newrelic_logpattern` STRING, `plugin_type` STRING ) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' WITH SERDEPROPERTIES ( 'ignore.malformed.json' = 'true', 'mapping.newrelic_source' = 'newrelic.source', 'mapping.newrelic_logpattern' = 'newrelic.logPattern', 'mapping.plugin_type' = 'plugin.type' ) STORED AS TEXTFILE LOCATION 's3://YOUR_BUCKET_NAME/PREFIX/';
ignore.malformed.json を true にしておくと、バッファの境界で JSON が壊れているレコードをスキップしてくれるので安定してクエリできます。
外部テーブルの作成例
下記はNew RelicのNPM機能(Ktranslate)を使用して取り込んだSyslogを使ってAthenaで検索した際に使用したクエリです。ログの種類によってカラム名が大きく変わってきますので、クエリは転送するログによって適宜調整してください。
CREATE EXTERNAL TABLE newrelic_logs (
`timestamp` BIGINT,
`message` STRING,
`hostname` STRING,
`device_name` STRING,
`client` STRING,
`client_name` STRING,
`app_name` STRING,
`severity` INT,
`facility` INT,
`priority` INT,
`version` INT,
`proc_id` STRING,
`msg_id` STRING,
`structured_data` STRING,
`eventtype` STRING,
`accountid` BIGINT,
`applicationid` BIGINT,
`messageid` STRING,
`newrelic_source` STRING,
`newrelic_logpattern` STRING,
`newrelic_logs_batchindex` INT,
`tags_container_service` STRING,
`plugin_type` STRING,
`instrumentation_provider` STRING,
`instrumentation_name` STRING,
`collector_name` STRING
)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
WITH SERDEPROPERTIES (
'ignore.malformed.json' = 'true',
'mapping.newrelic_source' = 'newrelic.source',
'mapping.newrelic_logpattern' = 'newrelic.logPattern',
'mapping.newrelic_logs_batchindex' = 'newrelic.logs.batchIndex',
'mapping.tags_container_service' = 'tags.container_service',
'mapping.instrumentation_provider' = 'instrumentation.provider',
'mapping.instrumentation_name' = 'instrumentation.name',
'mapping.collector_name' = 'collector.name',
'mapping.plugin_type' = 'plugin.type'
)
STORED AS TEXTFILE
LOCATION 's3://YOUR_BUCKET_NAME/PREFIX/';
TBLPROPERTIES ('compressionType' = 'gzip');
実際のクエリ例
unix タイムスタンプを日本時間に変換しながら直近のログを確認するクエリです。
SELECT from_unixtime(timestamp / 1000, 'Asia/Tokyo') AS log_time, hostname, severity, message FROM newrelic_logs ORDER BY log_time DESC LIMIT 20;
問題なく結果が返ってきたことで、S3 への保管と Athena での分析が一通り機能することを確認できました。

今後の改善点
現状のテーブル定義にはパーティションがないため、ログ量が増えるとフルスキャンになり Athena のクエリコストが上昇します。パーティション設計の選択肢としては、Firehose の動的パーティショニングを使うと、ログ内の timestamp フィールドを元に year=xxxx/month=xx/day=xx/ のプレフィックスで S3 に書き出せます。さらに Athena のパーティションプロジェクションと組み合わせると Glue Crawler が不要になり、運用もシンプルになります。ただし動的パーティショニングには GiB あたりの追加コストが発生するため、ログ量と照らし合わせてコスト試算をしてから導入を検討するのがよいでしょう。今回の記事ではそこまで考慮しておりませんが、実運用の際はログの量などを考慮して検討する必要があると考えております。
まとめ
今回の設定で一番ハマったのが圧縮設定の二重圧縮問題です。
New Relic 側でもFirehose側でも圧縮設定ができるのですが、私が検証した限りではNew Relic 側はパススルー設定にしてFirehose側で圧縮する方がよいのではという感触でした。また、Live Archives機能を使用してNew Relicに保管しておきNew Relic側で検索する案もあるかと思いますが、ログ保管期間やデータ管理の観点でのトレードがあるかなと考えており、この点についてはプロジェクト側でご判断頂ければと思います。
この記事がどなたかのお役に立てれば幸いです。
宣伝
弊社では、お客様環境のオブザーバビリティを加速するためのNew Relicアカウント開設を含めた伴走型のNew Relic導入支援サービスをご提供しております。 もしご興味をお持ちの方は、こちらのお問合せフォームよりお問合せ頂けましたら幸いでございます。
参考情報
◆ 塩野 正人
◆ マネージドサービス部 所属
◆ X(Twitter):@shioccii
◆ 過去記事はこちら
前職ではオンプレミスで仮想化基盤の構築や運用に従事。現在は運用部隊でNew Relicを使ってサービス改善に奮闘中。New Relic User Group運営。