🤖

CloudWatchログアラームの作成が面倒なので、Excelファイルから設定値を読み込んで作成できるようにしてみた。

2023/02/05に公開

はじめに

こんにちは、山田です。
今回は、CloudWatchログアラームをExcelから作成する方法について記載していきます。
よろしくお願いします。

概要図

概要図は以下の通りです。
image.png
①:Lambdaを用いて、Excelファイルを作成してS3にアップロードします。
②:作成されたExcelファイルをダウンロードします。
③:ダウンロード後、Excelファイルを記入してアップロードします。
④:Lambdaを用いて、Excelファイルを読み込みCloudWatchアラームを作成します。

エクセルファイル作成用Lmabdaのフローチャート・コード

エクセルファイル作成用Lmabdaのフローチャート・コードはそれぞれ以下になります。

フローチャート

フローチャートは以下の通りです。
フローチャート (1).png

コード

実際のコードは以下の通りです。

import openpyxl
import boto3
import os
from openpyxl import Workbook
from openpyxl.worksheet.datavalidation import DataValidation
from openpyxl.styles import PatternFill, Font, Border, Side

s3 = boto3.resource('s3')
s3_client = boto3.client('s3')
sns_client = boto3.client('sns')
cloudwatch_client = boto3.client('cloudwatch')
logs_client = boto3.client('logs')

os.chdir('/tmp')

book = openpyxl.Workbook()
book_x = book.active
book_x.title = 'ログアラーム'
book_y = book.create_sheet('メトリクスフィルター')

book_sheet = ["ログアラーム","メトリクスフィルター"]
for item in book_sheet:
    sheet = book[item]
    for row in range(1,100):
        for col in range(1,6):
            cell = sheet.cell(row = row, column = col)
            cell.font = openpyxl.styles.Font(name='MeiryoUI')
    
    fill = PatternFill(start_color="1F497D", end_color="1F497D", fill_type = "solid")
    font = Font(bold=True, color="FFFFFF")
    for col in range(1,6):
        cell = sheet.cell(row = 1, column = col)
        cell.fill = fill
        cell.font = font
        
    thin = Side(border_style="thin", color="000000")
    for row in range(1,100):
        for col in range(1,6):
            cell = sheet.cell(row = row, column = col)
            cell.border = Border(left=thin, right=thin, top=thin, bottom=thin)
    
    sheet.column_dimensions['I'].hidden = True


def create_logalarmsheet():

    sheet = book['ログアラーム']

    sheet['A1'] = 'No.'
    sheet['B1'] = 'AlarmName'
    sheet['C1'] = 'Description'
    sheet['D1'] = 'MetricsName'
    sheet['E1'] = 'SNS ARN'
    
    sns=[]

    response=sns_client.list_topics()
    count = 0
    for i in range(len(response['Topics'])):
        sns.append(response['Topics'][i]['TopicArn'])
        count+=1
    count = 0
    while 'nextToken' in response:
        response=sns_client.list_topics(nextToken=response['nextToken'])
        for i in range(len(response['Topics'])):
            sns.append(response['Topics'][i]['TopicArn'])
            count+=1

    for i in range(2,100):
        sheet.cell(row=i,column=4).value = '=メトリクスフィルター!E' + str(i)
    
    for i in range(1,100):
        sheet['D'+str(i)].number_format = '#'
    
    for i in range(len(sns)):
        sheet.cell(row=(i+1),column=9).value = sns[i]
        
    dv = DataValidation(type="list", formula1='I1:I'+str(len(sns)), allow_blank=True)
    dv.add(f"E2:E100")

    sheet.add_data_validation(dv)

def create_metricsfiltersheet():

    sheet = book['メトリクスフィルター']

    sheet['A1'] = 'No.'
    sheet['B1'] = 'LogGroupName'
    sheet['C1'] = 'FilterName'
    sheet['D1'] = 'FilterPattern'
    sheet['E1'] = 'MetricsName'

    loggroup = []

    response=logs_client.describe_log_groups()
    count = 0
    for i in range(len(response['logGroups'])):
        loggroup.append(response['logGroups'][i]['logGroupName'])
        count+=1
    count = 0
    while 'nextToken' in response:
        response=logs_client.describe_log_groups(nextToken=response['nextToken'])
        for i in range(len(response['logGroups'])):
            loggroup.append(response['logGroups'][i]['logGroupName'])
            count+=1
    
    for i in range(len(loggroup)):
        sheet.cell(row=(i+1),column=9).value = loggroup[i]
        
    dv = DataValidation(type="list", formula1='I1:I'+str(len(loggroup)), allow_blank=True)
    dv.add(f"B2:B100")
    
    sheet.add_data_validation(dv)

def lambda_handler(event, context):
    create_logalarmsheet()
    create_metricsfiltersheet()
    book.save('エクセル名.xlsx')
    s3_client.upload_file('エクセル名.xlsx','エクセルファイルをアプロードするS3バケット名', 'エクセル名.xlsx')

Excelファイル

実際に生成されるエクセルファイルの以下の通りです。
image.png
image.png

CloudWAtchアラーム作成用Lmabdaのフローチャート・コード

CloudWAtchアラーム作成用Lmabdaのフローチャート・コードは以下の通りです。

フローチャート

フローチャートは以下の通りです。
フローチャート (2).png

コード

実際のコードは以下の通りです。

import openpyxl
import boto3
import os
import time
from io import BytesIO

s3 = boto3.resource('s3')
s3_client = boto3.client('s3')
sns_client = boto3.client('sns')
cloudwatch_client = boto3.client('cloudwatch')
logs_client = boto3.client('logs')

os.chdir('/tmp')

source_bucket_obj = s3.Bucket('S3バケット名')
source_bucket_obj.download_file('エクセル名.xlsx', 'エクセル名.xlsx')
book = openpyxl.load_workbook('エクセル名.xlsx')
def put_logevent():
    
    s3_resp = s3_client.get_object(Bucket='S3バケット名', Key='エクセル名.xlsx')
    wb = openpyxl.load_workbook(BytesIO(s3_resp['Body'].read()),data_only=True)
    sheet = wb["メトリクスフィルター"]
    
    B = []
    D = []
    
    eng=[B,D]
    
    B_column = len(list(sheet.columns)[2])
    for item in eng:
        count = (eng.index(item)+1)*2
        for i in range(2,B_column+1):
            if sheet.cell(row=i, column=count).value is not None:
                item.append(sheet.cell(row=i, column=count).value)


    for i in range(len(B)):
        res = logs_client.describe_log_streams(
          logGroupName=B[i])
        seq_token=res['logStreams'][0]['uploadSequenceToken']
        response = logs_client.put_log_events(
        logGroupName=B[i],
        logStreamName=res['logStreams'][0]['logStreamName'],
        logEvents=[
            {
            'timestamp': int(time.time()) * 1000,
            'message': D[i]
            },
        ],
        sequenceToken = seq_token
        )

def create_metricsfilter():
        
    sheet = book['メトリクスフィルター']

    B = []
    C = []
    D = []
    E = []
    
    eng=[B,C,D,E]

    B_column = len(list(sheet.columns)[1])
    print(B)
    for item in eng:
        count = eng.index(item)+2
        for i in range(2,B_column+1):
            if sheet.cell(row=i, column=count).value is not None:
                item.append(sheet.cell(row=i, column=count).value)
    
    for i in range(len(B)):
        logs_client.put_metric_filter(
        logGroupName=B[i],
        filterName=C[i],
        filterPattern=D[i],
        metricTransformations=[
            {
                'metricName': E[i],
                'metricNamespace': 'Logs',
                'metricValue': '1',
            },
        ]
        )

def create_logalarm():
    
    sheet = book['ログアラーム']
    sheet2 = book['メトリクスフィルター']
    
    for i in range(2,100):
        sheet['D'+str(i)] = sheet2['E'+str(i)].value
    
    B = []
    C = []
    D = []
    E = []
    
    eng=[B,C,D,E]

    B_column = len(list(sheet.columns)[1])
    for item in eng:
        count = eng.index(item)+2
        for i in range(2,B_column+1):
            if sheet.cell(row=i, column=count).value is not None:
                item.append(sheet.cell(row=i, column=count).value)

    for i in range(len(B)):
      response=cloudwatch_client.put_metric_alarm(
      AlarmName=B[i],
      AlarmDescription=C[i],
      ActionsEnabled=True,
      AlarmActions=[
        E[i],
      ],
      MetricName=D[i],
      Namespace='Logs',
      Statistic='Sum',
      Period=300,
      Unit='Seconds',
      Threshold=1,
      EvaluationPeriods=1,
      ComparisonOperator='GreaterThanOrEqualToThreshold'
      )

def lambda_handler(event, context):    
    create_metricsfilter()
    put_logevent()
    time.sleep(5)
    create_logalarm()

動作確認

前提条件は以下の通りです。

・メトリクスが保存されている名前空間は「Logs」
・アラーム通知条件は、5分間の合計値が1以上になった場合

エクセルファイル作成用Lmabdaを実行します。
image.png
エクセルファイルをダウンロードします。
image.png
エクセルを記入します
image.png
image.png
エクセルファイルを同じ名前でアップロードします。
image.png
CloudWAtchアラーム作成用Lmabdaを実行します。
image.png
CloudWatchアラームが作成されていることが確認できれば完了。
image.png

終わりに

今回はログアラームをExcelより作成する方法について記載しました。
まだまだ改良点はあると思うので、これからも改善していきたいと思います。
また、その他のメトリクスに関してもExcelファイルから作成できるようにしていきたいと思います。
最後まで拝読いただきありがとうございます。

Discussion