当記事では、ログ収集ソフトLogStare Collector(LSC)のCloudWatch Logs収集機能を用いてApplication Load Balancer (ALB)のログを取得する方法について記載します。
ALBはCloudWatch Logsに直接ログを出力することが出来ず、S3にしか出力できません。そのため、S3に出力されたログを、Lambdaを用いてCloudWatch Logsに集約し、LSCで収集します。
また、LSCをログ分析基盤であるLogStare Reporter(LSR)、LogStare Quint(LSQ)と連携することで、レポートを作成することができ、簡単にログを分析することが出来ます。
本記事ではALBは構築済みと想定し、手順を記載いたします。
- 当記事では複数のAWSサービスを利用します。それぞれ利用料金が発生いたしますので、予めご了承ください。
- 2024年3月に行った検証をもとに記載しており、詳細な手順等についてはAWSのドキュメント等についてもあわせてご参照ください。
- 記載内容により発生したいかなる損害、想定外のAWS利用料金の発生等について、一切の責任を負いかねます。予めご了承ください。
- 記載手順を実行後の完成後の状態は以下の通りです。
目次
S3の構築
まず、ALBのログを出力するためのS3を構築します。
コンソールから「S3」サービスを選択し、「バケットを作成」を押下します。
「AWSリージョン」はALBと同じリージョンに作成します。今回は「アジアパシフィック(東京)ap-northeast-1」を選択しました。
バケット名は任意の名前を入力します。
その他はデフォルトで結構です。設定が完了したらページ下部にある「バケットを作成」を押下します。
次に、ALBのログを出力できるようにするためにS3 バケットにポリシーをアタッチします。
作成したバケット名をクリックし、「アクセス許可」>「バケットポリシー」>「編集」を押下します。
その後は、「ステップ 2: S3 バケットにポリシーをアタッチする」を参考に、ポリシーを作成してください。
ALBのログ出力設定
次に、ALBの設定を変更し、ログがS3に出力されるようにします。
対象のALBを押下します。
「属性」の「編集」を押下します。
「モニタリング」の「アクセスログ」をオンにし、「S3 URI」に作成したS3をフォーマットに沿って指定します。設定が完了したら「変更を保存」を押下します。
ここまで完了するとS3にALBのログが出力されるようになります。(アクセスしてからログが出力されるまでにはある程度時間がかかります。)
CloudWatch Logsの構築
次に、ログを出力するCloudWatch Logsを構築します。
初めにロググループを作成します。
コンソールから「CloudWatch」サービスを選択し、「ログ」>「ロググループ」から「ロググループを作成」を押下します。
「ロググループ名」に任意の名前を入力し、特に設定は変更せずに「作成」を押下します。
次にログストリームを作成します。作成したロググループを押下し、「ログストリームの作成」を押下します。
任意のログストリーム名を入力し、「Create」を押下します。
Lambda関数の構築
次に、S3にあるログファイルをCloudWatch Logsに出力するLambda関数を作成します。
コンソールより「Lambda」サービスを選択し、メニューより「関数」を押下します。
右上の「関数の作成」を押下します。
「関数名」に任意の名前を入力し、ランタイムは「Python 3.9」を選択します。その他はデフォルトで結構です。
設定が完了したら「関数の作成」を押下します。
次にトリガーの設定を行います。
「トリガーを追加」を押下します。
「ソース」にS3を選択し、「Bucket」は作成したS3を指定します。
「Event types」はPUTを設定します。
「Recursive invocation」にチェックを入れ、「追加」を押下します。
トリガーが作成され、S3にログファイルが出力されたタイミングでLambda関数が実行されるようになりました。
次に、S3にあるログファイルをCloudWatch Logsに出力するコードを入力します。
「コード」を押下し、以下のコードを入力します。logGroupNameとlogStreamNameは環境に応じて書き換えてください。
※コードは以下のサイトを参考にしました。
- Lambda (Python) から特定のログストリームにログを書こうとして苦戦した2つのポイント - Qiita
- Python (Boto3) @ Lambda で CloudWatch Logs の特定のログストリームにログを出力する - Qiita
- LambdaでS3上に出力されたログをCloudWatch Logsに取り込んで監視する | mooapp (wordpress.com)
- s3に圧縮ファイルがアップされた際に、解凍して要素をCloudWatchLogsに出力するLambda Function(python版)
import json import urllib.parse import boto3 import time import gzip import os print('Loading function') s3 = boto3.client('s3') logs_client = boto3.client('logs') ## 変数 logGroupName = ※環境によって書き換えてください logStreamName = ※環境によって書き換えてください def lambda_handler(event, context): # Get the object from the event and show its content type bucket = event['Records'][0]['s3']['bucket']['name'] key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8') try: file_name = os.path.basename(key) file_path = os.path.join('/tmp', file_name) s3.download_file(bucket, key, file_path) with gzip.open(file_path, 'rt') as f: file_content=f.read() list = file_content.splitlines() for item in list: #keyを'/'で区切り、key_splittedに代入。 key_splitted=key.split('/') #AWSLogsという文字列を探し、その添え字を代入 AWS_Logs_index=key_splitted.index('AWSLogs') #key_splittedのAWSLogsの添え字に7を足したものを'_'で区切り、key_splitted_7に代入 key_splitted_7=key_splitted[AWS_Logs_index+7].split('_') #prefixがない場合はNoneにする。AWS_Logs_indexが0ではない場合はprefixが存在する。 prefix='None' if AWS_Logs_index >0: prefix='' for i in range(AWS_Logs_index): prefix=prefix+'/'+key_splitted[i] AWS_Logs=key_splitted[AWS_Logs_index] aws_account_id=key_splitted[AWS_Logs_index+1] region=key_splitted[AWS_Logs_index+3] date=key_splitted[AWS_Logs_index+4]+'/'+key_splitted[AWS_Logs_index+5]+'/'+key_splitted[AWS_Logs_index+6] #load_balancer_id=key_splitted_7[3].split('.')[1]+'.'+key_splitted_7[3].split('.')[2] load_balancer_id=key_splitted_7[3].lstrip('app.') end_time=key_splitted_7[4] ip_address=key_splitted_7[5] #key_splitted_7の添え字が6のものを'.'で区切り、それの添え字が0のものを代入 random_string=key_splitted_7[6].split('.')[0] item_inserted=' '.join([bucket,prefix,AWS_Logs,aws_account_id,region,date,load_balancer_id,end_time,ip_address,random_string,item]) put_logs(logs_client,logGroupName,logStreamName,item_inserted) #delete file in tmp if os.path.isfile(file_path): os.remove(file_path) return 'function complete' except Exception as e: print(e) print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket)) raise e def put_logs(client, group_name, stream_name_prefix, message): try: exist_log_stream = True log_event = { 'timestamp': int(time.time()) * 1000, 'message': message } sequence_token = None try: if exist_log_stream == False: #変数create_log_stream_responseは使用しないが、公式ドキュメントに記載されている書き方に合わせるため、定義。 create_log_stream_response = client.create_log_stream( logGroupName = group_name, logStreamName = stream_name_prefix) exist_log_stream = True if sequence_token is None: #変数put_log_events_responseは使用しないが、公式ドキュメントに記載されている書き方に合わせるため、定義。 put_log_events_response = client.put_log_events( logGroupName = group_name, logStreamName = stream_name_prefix, logEvents = [log_event]) else: put_log_events_response = client.put_log_events( logGroupName = group_name, logStreamName = stream_name_prefix, logEvents = [log_event], sequenceToken = sequence_token) except client.exceptions.ResourceNotFoundException as e: exist_log_stream = False except client.exceptions.DataAlreadyAcceptedException as e: sequence_token = e.response.get('expectedSequenceToken') except client.exceptions.InvalidSequenceTokenException as e: sequence_token = e.response.get('expectedSequenceToken') except Exception as e: print(e) except Exception as e: print(e)
入力が完了したら「Deploy」を押下します。
次に、Lambda関数に権限を付与します。
設定>アクセス権限から「ロール名」を押下します。
IAMの設定画面に遷移しますので、「設定を追加」の「インラインポリシーを作成」を押下します。
ここで、S3に「GetObject」、CloudWatch Logsに「PutLogEvents」の権限を付与します。
ARNは環境にあったものを設定してください。
ポリシー名に任意の名前を入力し、「ポリシーの作成」を押下します。
ここまで完了すると、CloudWatch Logsにログが出力されるようになります。
※タイムアウトについて
S3に出力されるログファイルによっては処理時間が長くなってしまい、タイムアウトが発生して処理が中断される場合があります。
タイムアウトが発生している場合には、CloudWatch Logsのlambda関数自身のログの中に「Task timed out」というエラーメッセージが出力されます。
その際は、対象のlambda関数の「設定」>「一般設定」からタイムアウト時間を適宜延長してください。
LogStare Collectorの構築
次に、CloudWatch Logsのログを収集できるようにLSCを構築します。
詳しい設定方法は「LogStare CollectorでのAWS WAFログの取得方法とログレポート」の「LogStare Collector側の設定」をご参照ください。
ログレポート
LSCをLogStare Reporter(LSR) または LogStare Quint(LSQ) に紐づけると、ログレポートを生成することが出来ます。以下が作成例です。
アクセスページ別リクエスト集計
アクセスされたページをまとめたレポートです。
アクセスされたホスト名、URI、ポート番号を把握することが出来ます。
アクセスページ別ALB-Target応答集計
アクセスされたページの応答をまとめたレポートです。
アクセスされたホスト名、URI、ポート番号だけでなく、ALBとホストのステータスコードを確認することが出来ます。
アクセスページ別リクエスト処理時間平均集計
アクセスされたページの処理時間をまとめたレポートです。
アクセスされたホスト、URI、ポート番号だけでなく、リクエストやレスポンスの処理時間も確認することが出来ます。
おわりに
今回は、LSCでのALBログの取得に向けたS3、CloudWatch Logs、Lambdaの構築方法と、LSR、LSQのレポート作成例をご紹介しました。
ALBのログをLSCに出力するためにはやや手間がかかりますが、LSR、LSQでレポート化することで、容易にログを分析出来るようになります。
実際にLSQの操作を行うことが出来るデモサイトがございますので、ぜひご覧ください。
ALBのログ管理にLSC、LSR、LSQをご活用いただけたら幸いです。
記載されている会社名、システム名、製品名は一般に各社の登録商標または商標です。
当社製品以外のサードパーティ製品の設定内容につきましては、弊社サポート対象外となります。