AWS APIGatewayのアクセスのログ(json)を作成し、Kinesis Firehose(S3)に投げる
iOSアプリでユーザがあるいくつかのページを見たかどうかが知りたくなり、元々使ってみたかったAWS周りのサービスを使ってアプリの起動ログを送るようにしてみた覚書。
※2018/03/01前後の情報です。
※備忘録代わりメモなので雑なところあります。
やりたかったこと
- iOSアプリで特定ページを見たかどうかのログを取りたい
- アプリ自体はクライアントだけで動作するものなので、バックエンドはなく、そのためだけに用意もしない
- 今はログを取得したいだけだが、今後何か処理が入るかもしれない
- 今後ログの用途が広がる可能性も考えて、S3に置きたい
やったこと
- APIGatewayでエンドポイントを作成
- iOSアプリからリクエストを送る
- APIGatewayからKinesis Firehoseへログを送る
この記事で説明しないこと
- Kinesis Firehoseの話 (既にdelivery streamがある前提です)
- iOSアプリ側の実装 (特に今回の話に依存することはないので書きません)
APIGatewayでエンドポイントを作成
エンドポイントを用意する
- APIGatewayでエンドポイントを作成
- iOSアプリからリクエストを送る
- APIGatewayからKinesis Firehoseへログを送る
この記事で説明しないこと
- Kinesis Firehoseの話 (既にdelivery streamがある前提です)
- iOSアプリ側の実装 (特に今回の話に依存することはないので書きません)
APIGatewayでエンドポイントを作成
エンドポイントを用意する
エンドポイントを用意する
APIGatewayのトップ APIs
から Create API
を選択する。
New API
を選択し、必要情報を入力する。
API Name
: 適当な判別可能な名前
Description
: 必要なら説明
Endpoint Type
: Regional or Edge Optimized を選ぶ、それぞれの詳細はこちら
情報入力後、画面右下の Create API
を選択するとAPIが作成され、トップの APIs
の下に今作成したAPIの名前が追加される。
リソースとメソッドの追加
追加されたAPIを選択すると、次のような画面が表示される。
ここから、作成したAPIにresourceとmethodを追加していく。
Actions
から Create Resource
を選択すと、Resource作成画面へ遷移するので、必要情報を入力する。
今回は単純にiOSアプリからリクエストを叩きたいだけなので、proxy resourceやCORSにはチェックを入れずに進みます。
試しに test
というResourceを作成しました。
/test
というResourceが追加されたのがわかります。
続いて、ここにMethodを追加します。再び Actions
から Create Method
を選択すると、次のようにセレクトリストが出現します。
このセレクトリストでMethodを選択することができます。今回はログを残したいだけなのでGET
にします。リストからGET
を選択して、リストの隣に出るチェックマークを押すと、設定が保存され次のような画面が表示されます。
APIGatewayへのリクエストをLambdaなどで処理したい場合はこのままで結構ですが、今は一旦リクエストを送れるところまで進むため、Mock
を選択し、Saveします。
ここで、次のような画面になります。
これで一旦形としては出来ましたが、アプリから叩く場合はそのレスポンスが気になるため、仮でレスポンスを入れておきます。
上記画像でいう右下の、Integration Response
を選択します。
ここで、レスポンスのStatus Code
やContent Type
、Header
、Body
のテンプレートなどを設定することが出来ます。
今は一旦返ればなんでも良いとして、Body Mapping Template
を下記のようにしました。
テストとデプロイ
Resource > Method (GET) のページに戻ると、左上に TEST
の項目があることがわかります。
ここでは、作成したAPIをテストすることができます。今回はMock
での作成であるため落ちることはないかと思いますが、試してみましょう。
遷移後の画面の下の方で TEST
をクリック。
こんな感じで、ちゃんと動いていることがわかります。
問題なければ、外から叩くためにAPIをDeployしましょう。
Actions
から Deploy API
を選択すると、新たにウィンドウが表示されます。
Stage
から [New Stage]
を選択すると次のような画面になるため、必要情報を入力しましょう。
Stage
はバージョンのようなもので、テストの場合は、 Beta
などで良いと思います。
Deployすると、自動的にStagesのページに遷移すると思います。
トップに表示されている Invoke URL:
がエンドポイントのもととなるURLです。
※実際に使用する場合は、ここままだと誰でもAPIを叩けてしまうため、API Keyを作成する、Authorizerを設定する、など何かしらの制限を設けましょう。
iOSアプリからリクエストを送る
ここはiOSアプリの実装になるので、アプリ実装の説明は割愛します。
先程までの設定で、決まった値を返すエンドポイントを作成することが出来ました。
https://xxxx.execute-api.ap-northeast-1.amazonaws.com/beta/test
(stageがbeta
, resourceがtest
の場合)にリクエストを送り、Mockで設定した値が返ってくるかどうか確認してください。
APIGatewayからKinesis Firehoseへログを送る
Roleの作成
疎通の確認が取れたら、Mock
で作っていたAPIをKinesis FirehoseにObjectをPUTするように作り変えます。
がその前に、APIGatewayからKinesis Firehoseを使えるように、roleを作ってあげないといけないため、別で作成しましょう。
詳細は割愛しますが、IAMを開き、
- Policyから、Kinesis Firehoseに
Put Record
とPut Record Batch
のActionを許可するようなPolicyを作成する - 作成したPolicyを持つRoleを作成する
- 作成したRoleの
Trusted entities
にapigateway.amazonaws.com
を追加する
で出来ると思います。
とりあえず送れるようにする
roleを作成できたら、先程Mock
の選択した Integration Request
の設定画面へ行きます。
先程Mock
にした部分を、AWS Service
に変更し、各項目を次のように埋めます。
execution roleには、先程作成したroleのARNを入れてください。
Saveしたあとは、一旦テストしてみましょう。おそらく次のようなExceptionが返ってきます。
{
"__type": "SerializationException"
}
これは、Kinesis FirehoseにPUT RECORDする際は、次の形式で送らないといけないためです。
{
"DeliveryStreamName": "[Kinesis Firehose上のdelivery streams名]",
"Record": {
"Data": "[データのオブジェクト(Base64エンコード)]"
}
}
この形式にするために、Integration Request
の下の方にある設定の、Body Mapping Template
を編集します。
まずはAdd mapping template
から、Content-Typeに application/json
を指定します。
追加した application/json
を選択すると、更に下にスクロールできるようになり、Mapping Templateを編集できます。
ここにTemplateを記入していくわけですが、詳しくは下記を参照すると良いです。
API Gateway のマッピングテンプレートリファレンス
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html
テストの場合は、簡単に次のような形式で送ってみると良いと思います。
#set($data = "{ ""key"": ""property""}")
{
"DeliveryStreamName": "xxxxx",
"Record": {
"Data": "$util.base64Encode($data)"
}
}
ここまで出来たら動作確認しつつ、欲しい形式にTemplateを変えていきましょう。
動作確認では、まずはAPI GatewayでのTest機能で確認し、エラーが出なければ実際にリクエストを送るもの(今回はアプリ)から確認すると良いでしょう。
設定に問題がなければ、少しの時間の後にKinesis Firehoseの方にデータが送られます。
ここでは解説していませんが、実際はそこからS3などにデータを吐き出していると思いますので、そちらで意図した出力になっているか確認してください。
最終的なMapping Template
今回は、基本的にはログ目的だったので、resource名や時間、あればrequest parameterなどを拾えれば良いということで、最終的に下記のようになりました。(もっとスマートなやり方があるかもしれません...)
#set($allParams = $input.params())
#set($params = $allParams.get('querystring'))
#set($headers = $allParams.get('header'))
#set($json = "{
""requestId"":""$context.requestId"",
""ip"": ""$context.identity.sourceIp"",
""user"":""$context.identity.user"",
""requestTime"":""$context.requestTime"",
""requestTimeEpoch"":""$context.requestTimeEpoch"",
""httpMethod"":""$context.httpMethod"",
""resourcePath"":""$context.resourcePath"",
""queryParams"": {
#foreach($paramName in $params.keySet())
""$paramName"":""$util.escapeJavaScript($params.get($paramName))""#if($foreach.hasNext),
#end
#end
},
""queryStrings"": ""#foreach($paramName in $params.keySet())$paramName=$util.escapeJavaScript($params.get($paramName))#if($foreach.hasNext)&#end#end"",
""protocol"":""$context.protocol""
}")
#set($data = $json.replaceAll(" ","").replaceAll("\n","")+"
")
{
"DeliveryStreamName": "xxxxx",
"Record": {
"Data": "$util.base64Encode($data)"
}
}
各変数やメソッドはリファレンスを参照していただくとして、他の部分を少し説明します。
#set($json = "{ (略
ここで、 $json
にログとして残したい各パラメータをjson形式で無理やり作成しています。
#set($data = $json.replaceAll(" ","").replaceAll("\n","")+"
")
ここでは、ログを一行一レコードで保存したいので、先程作成した $json
の無駄な余白や改行を削除し、最後に無理やり改行を加えています。
(改行周りが "\n"
などで上手くいかなかったので、+
のあとに改行の入力を無理やりいれています...。)
その後、最後の実際に送るjsonのブロックで、Kinesis Firehoseの形式に合わせつつ、$data
をbase64エンコードしたものを追加しています。
おまけ
CloudWatch Logsを使わなかった理由
最初はAPI Gateway > Kinesis Firehose > S3 ではなく、API GatewayにはCloudWatch Logsと連携して簡単にアクセスログを取得できることから、そちらを利用する方法を考えていました。
参考記事:
Amazon API Gateway でアクセスログ記録をサポート
【新機能】Amazon API Gateway でアクセスログを記録する #reinvent
ただし今回は、ユーザがendpointを叩いたときのget parameterもログとして取得したいという前提があり、その実現方法が分からなかったため断念しました。
単純にアクセスログを残したいだけであれば、CloudWatch Logsを使うほうが楽だと思います。
以上です。何か間違いあればコメント頂けると幸いです。
Author And Source
この問題について(AWS APIGatewayのアクセスのログ(json)を作成し、Kinesis Firehose(S3)に投げる), 我々は、より多くの情報をここで見つけました https://qiita.com/cfiken/items/67c70a92b8a41f311ffb著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .