先月の記事 でCloudWatchのログを定期的に取得してS3に保存するshellscriptを書いたが、EC2上に置いておくとその都度インスタンスを起動しないといけないため、ちょっとイケてない。
そこで、今回はlambdaから実行するバージョンを作ってみる。
##概要(今回学んだこと)
- lambdaには一時的に利用できる/tmp/ディレクトリがあること。
- s3のライフサイクル
- 日付の取得(python)
- csvファイルの作成(python)
ソースコード
##構成
###メイン関数
def lambda_handler(event, context):
all_metrics_list = [
{
'NameSpaceHeader' : 'AWS/',
'NameSpace' : 'EC2',
'MetricName':'CPUUtilization',
'Dimensions':[{"Name" : "InstanceId","Value" : "i-xxxxxxxxxxxxxxxxx"}],
'Statistics' : 'Average'
}
]
for target in all_metrics_list:
#メトリクス取得
logs = getMetricStatistics(target)
#CSVへ変換・ソート
convertCSV(logs['Datapoints'])
sortCSV()
#適当なフォルダ名/ファイル名を生成して、s3へアップ
uploadToS3(generateFileName(target))
return {
'statusCode': 200,
'body': json.dumps('finish lambda')
}
##各論
###日付の取得
CloudWatchメトリクスはGMTなので、JSTで1日分のログを収集するには15時で切る。(JSTで指定したい)
today = datetime.today()
yesterday = today - timedelta(days=1)
dayBeforeYesterday = today - timedelta(days=2)
folder_title = datetime.strftime(yesterday, '%Y-%m-%d')
endTime = datetime.strftime(yesterday, '%Y-%m-%dT15:00:00Z')
startTime = datetime.strftime(dayBeforeYesterday, '%Y-%m-%dT15:00:00Z')
###メトリクスの取得
メトリクスによっては必要なDimensionが異なる。これが正しくないとNo Dataが返り続ける。
def getMetricStatistics(target_dict):
cloudwatch = boto3.client('cloudwatch', region_name='ap-northeast-1')
logs = cloudwatch.get_metric_statistics(Namespace=target_dict["NameSpaceHeader"] + target_dict["NameSpace"],
MetricName=target_dict["MetricName"],
Dimensions=target_dict["Dimensions"],
StartTime=startTime,
EndTime=endTime,
Period=300,
Statistics=[target_dict["Statistics"]]
)
return logs
###csvへの変換とソート
lambdaではtmpディレクトリが用意されている。ここに整形するファイルを置いておく。
def convertCSV(datapoints):
with open('/tmp/tmp.txt','w') as f:
if len(datapoints) == 0:
print("Empty")
pass
else:
csv.register_dialect('dialect1', doublequote=True, quoting=csv.QUOTE_ALL)
writer = csv.DictWriter(f, fieldnames=datapoints[0].keys(), dialect="dialect1")
for row in datapoints:
writer.writerow(row)
def sortCSV():
with open('/tmp/tmp.txt', 'r') as f:
reader = csv.reader(f)
result = sorted(reader, key=operator.itemgetter(0))
with open('/tmp/tmp.txt', 'w') as f:
data = csv.writer(f,delimiter=',')
for row in result:
data.writerow(row)
with
キーワードを使用すると、ファイル操作中にエラー終了してもcloseしてくれるので有能。
#####csvモジュールについて
register_dialect
: dialectを登録する。デリミタやクオーテーションの種類などはここで指定して、1つのセットを作り命名する。
DictWriter
: 辞書を出力行にマップするオブジェクトを生成する。fieldnamesはファイルに書き込む順番。
書き出す前にwriter.writeheader()
でヘッダーをつけられる。今回はいらない。
S3ライフサイクルの設定
Intelligent-TIERINGは、参照頻度に応じてStandardとStandard-IAに割り振ってくれる。30日アクセスされなければStandard-IAへ格納する。
管理タブから設定。S3はオブジェクトのバージョン管理もできるので有効にする場合には、現行のバージョン(LATEST)と以前のバージョンのそれぞれにライフサイクルのルールを設定できる。
おわりに
あとはCloudWatch Events(cron)で定期実行していけば自然にログが貯まる。
ただ、0時ちょうどに実行すると日付が正しくないような気がする?(今後もう少し検討)
##EC2上にスクリプトを置いてログ収集をする以前の方法