NewRelicにSendGridのReputationを送る方法
はじめに
こんにちは!!株式会社Inner Resourceの檜野です。
NewRelicのダッシュボードでSendGridのReputationを監視したいと思った際に、公式ドキュメントだけだと連携設定が完全には出来ず試行錯誤する事になりました…
同様の事を試される方の一助となればと考え、今回は最終的な実装内容を共有します!
NewRelic公式が提示するSendGridとの連携方法
公式に記載のある連携方法は以下の2パターンがあります。
- AWS S3にあるログデータをAWS Lambda等を使用してNewRelicに送信する
- SendGridのEvent Webhookを用いて、設定されたEventの度にNewRelicのLog APIを用いてログデータを送信する
2番だとReputationを送る事が出来ない為、Reputationを送るという目的の為には1番にて実装することになります。
実装の大まかな流れ
- データを取得するSendGridのWeb APIの確認
- SendGridのWeb APIを叩く為のAPI Keyの発行
- S3, Lambdaの作成
- 3で作成したS3に対しNewRelicへ送信設定
- NewRelicのダッシュボードにReputationを監視するwidgetを追加
データを取得するSendGridのWeb APIの確認
SendGridのWeb APIで取得した情報を、S3に保存する流れになるので、Reputationを取得出来るAPIを探し、curl等を用いて実際の挙動を確認して使用する必要があります。
今回使用するAPIは以下です。
API名
GET User Account [GET]
Request
GET https://api.sendgrid.com/v3/user/account HTTP/1.1
Response
HTTP/1.1 200
{
"type": "free",
"reputation": 99.7
}
curl例
curl -X GET \
https://api.sendgrid.com/v3/user/account \
-H "Authorization: Bearer YOUR_API_KEY"
SendGridのWeb APIを叩く為のAPI Keyの発行
APIを叩くためには、API Keyが必要になります。
API Keyを発行する際には権限を設定する事が出来ます。
必要最低限な権限だけを与えたAPI Keyを発行したいのですが、通常のAPI Key作成画面で設定出来る権限だと今回のAPIを叩く事が出来ず、Full Accessな権限を与えるしかなくセキュリティ的によろしくない事になってしまいます。
そこで裏技的に、APIでAPI Keyの権限を設定する方法を用いて、必要最低限な権限のAPI Keyを作成します。下記に手順を記載します。
前提条件
- Reputation取得に使うAPI Keyの名前を
fetch-reputation
とします
手順の流れ
-
fetch-reputation
の作成の際に、API Key Permissionsを Restricted Access かつ Access Details を全て No Access で設定 - Full Access 権限の一時的なAPI Keyを発行
- 2で作成したAPI Keyを使用して
fetch-reputation
の権限をAPIで設定する -
fetch-reputation
を使用しReputation取得のAPIをcurlで叩きReputationが取得出来ることを確認する
使用するAPI名
Generate a new API Key for the authenticated user [POST]
Request
POST https://api.sendgrid.com/v3/api_keys HTTP/1.1
Request Body
{
"name": "My API Key",
"scopes": [
"mail.send",
"alerts.create",
"alerts.read"
]
}
Response
HTTP/1.1 201
{
"api_key": "SG.xxxxxxxx.yyyyyyyy",
"api_key_id": "xxxxxxxx",
"name": "My API Key",
"scopes": [
"mail.send",
"alerts.create",
"alerts.read"
]
}
curl例
scopesの権限がReputation取得に必要な権限です。
curl -X PUT \
https://api.sendgrid.com/v3/api_keys/{fetch-reputationのAPI Key ID}\
-H "Authorization: Bearer {手順2で作成したAPI Key}" \
-H "Content-Type: application/json" \
-d '{
"name": "fetch-reputation",
"scopes": [
"user.account.read",
"user.credits.read",
"user.email.read",
"user.profile.read",
"user.username.read"
]
}'
S3, Lambdaの作成
Reputationのログを貯めていくS3バケットの作成、またAPIを叩きReputationを取得しS3に保存を行うLambdaを作成します。
定期的にReputationを取得する場合はLambdaにEvent Bridgeを設定してあげてください。
詳細な設定手順は省きますが、作成したlambdaの実装例(Ruby)を記載しておきます。適宜参考にしてください。
# runtime: AWS Lambda Ruby 3.3 / x86_64
require 'aws-sdk-s3'
require 'net/http'
require 'uri'
require 'json'
def lambda_handler(event:, context:)
sendgrid_api_key = ENV['SENDGRID_API_KEY']
s3_bucket = ENV['S3_BUCKET']
raise StandardError.new("sendgrid_api_key is not set") if sendgrid_api_key.nil? || sendgrid_api_key.empty?
raise StandardError.new("s3_bucket is not set") if s3_bucket.nil? || s3_bucket.empty?
s3_key = "sendgrid_reputation_#{Time.now.strftime('%Y%m%d')}.json"
uri = URI.parse('https://api.sendgrid.com/v3/user/account')
begin
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{sendgrid_api_key}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
if response.is_a?(Net::HTTPSuccess)
# responseにはSendGridのプラン情報等も含まれており、ログとして必要のない情報は残さない為に、reputationのみを取得
response_data = JSON.parse(response.body)
reputation = response_data['reputation']
reputation_json = { reputation: reputation }.to_json
s3 = Aws::S3::Resource.new
obj = s3.bucket(s3_bucket).object(s3_key)
obj.put(body: reputation_json)
puts "Data saved to S3: #{s3_key}"
else
raise StandardError.new("Failed to retrieve data: #{response.code} #{response.message}")
end
rescue => e
raise StandardError.new("#{e.class}: #{e.message}")
end
end
S3に対しNewRelicへ送信設定
NewRelic が提供している AWS Serverless Application Repository の Lambdaアプリケーション を使用します。詳細は以下の公式ドキュメントや記事を参考にしてください。
NewRelicのダッシュボードにReputationを監視するwidgetを追加
詳細な設定手順は省きますが、widgetを作成するNRQLの例を以下に記載します。
監視方法に応じて適宜変更してください。
SELECT latest(reputation) AS 'latest reputation (%)'
FROM Log
WHERE aws.s3_bucket_name = '{Reputationのログが保存されているS3のバケット名}'
SINCE 1 day ago
まとめ
この記事が実装に困っている方の助けになれば嬉しいです!!
Discussion