はじめに
AWS CloudWatch Logsのput-log-eventsでCloudWatch Logsへログを送り、メトリクスフィルターでログの内容を監視します。
CloudWatch Agentでログを送信した方が素直な実装です。
put-log-events
参考
put-log-events
を行う時のBashスクリプト
#!/bin/bash -
readonly PROCNAME=${0##*/}
function log() {
local fname=${BASH_SOURCE[1]##*/}
echo "$(date '+%Y-%m-%dT%H:%M:%S') ${PROCNAME} (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $@"
}
export SERVICE_NAME=$1 # hello_world.service
# CloudWatchLogs設定
export LOG_GROUP_NAME=$2 # /aws/ec2/service-status
export LOG_STREAM_NAME=$3 # status
export AWS_DEFAULT_REGION=ap-northeast-1
function main() {
log "Start batch program."
# CloudWatchLogsにPUTするメッセージ
message=$(systemctl show $SERVICE_NAME | grep "ActiveState=")
log $message
# put-log-eventに利用するトークン
upload_sequence_token=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" --query 'logStreams[?logStreamName==`'$LOG_STREAM_NAME'`].[uploadSequenceToken]' --output text)
# put-log-eventに利用するタイムスタンプ
time_stamp=$(date +%s%3N)
# put-log-eventsの実行
if [ "$upload_sequence_token" != "None" ]
then
# トークン有りの場合
aws logs put-log-events --log-group-name "$LOG_GROUP_NAME" --log-stream-name "$LOG_STREAM_NAME" --log-events timestamp=$time_stamp,message="$message" --sequence-token $upload_sequence_token --output text
else
# トークン無しの場合(初回のput)
aws logs put-log-events --log-group-name "$LOG_GROUP_NAME" --log-stream-name "$LOG_STREAM_NAME" --log-events timestamp=$time_stamp,message="$message" --output text
fi
log "End batch program."
}
main
このスクリプトに
sudo chmod 755 monitor-by-putting-logs-to-cloudwatch.sh
と実行権限を付ける。cronでスクリプトを定期実行したり、送りたいログをbashの引数として与えて実行すると指定のCloudWatch Logsのロググループへログを送れる。
スクリプトを実行するのに必要なAWSの権限
スクリプト中の describe-log-streams
と put-log-events
を実行するために logs:DescribeLogStreams
と logs:PutLogEvents
の権限が必要となる。 logs:PutLogEvents
は他のCloudWatchLogsへログを追加できる権限となるため、気になる場合は適宜リソースを制限すること。
IAMポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"logs:DescribeLogStreams",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
put-log-eventに利用するトークン
put-log-events
は2回目以降のputではトークンが必要となる。そのため、
upload_sequence_token=$(aws logs describe-log-streams --log-group-name "$LOG_GROUP_NAME" --query 'logStreams[?logStreamName==`'$LOG_STREAM_NAME'`].[uploadSequenceToken]' --output text)
でトークンを取得する必要がある。
put-log-eventに必要なタイムスタンプ
put-log-events
の使用時には必ずミリ秒まで含めた13桁のUNIXタイムが必要となる。13桁のUNIXタイムは下記のdateコマンドで取得できる。
time_stamp=$(date +%s%3N)
メトリクスフィルターなどのCloudFormation
CloudWatch Alarmの通知先のAWS SNS Topicはすでにあるものとする。
作成しているリソース
- CloudWatch Logs
- ロググループ
- ログストリーム
- メトリクスフィルター
- CloudWatch Alarm
- アラーム
AWSTemplateFormatVersion: 2010-09-09
Description: >-
alert crontab result, and monitoring crontab
Parameters:
SNSTopicARN:
Description: SNS Topic ARN for Notification
Type: String
ProjectName:
Description: Project Name
Type: String
Resources:
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-loggroup.html
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/ec2/${ProjectName}-service-status
RetentionInDays: 1
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-logstream.html
LogStream:
Type: AWS::Logs::LogStream
Properties:
LogGroupName: !Ref LogGroup
LogStreamName: "service-status"
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-metricfilter.html
# aws logs describe-metric-filters --output yaml
MetricFilter:
Type: AWS::Logs::MetricFilter
Properties:
FilterPattern: "ActiveState=active" ## 適宜書き換え
LogGroupName: !Ref LogGroup
MetricTransformations:
- DefaultValue: 0.0
MetricName: !Sub ${ProjectName}-filter-active
MetricNamespace: !Sub ${ProjectName}-service-status
MetricValue: 1
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html
# aws cloudwatch describe-alarms --alarm-names "active-alarm" --output yaml
CloudWatchAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
ActionsEnabled: true
AlarmActions:
- Ref: SNSTopicARN
AlarmDescription: >-
Monitor ec2 service status log.
AlarmName: !Sub ${ProjectName}-active-alarm
ComparisonOperator: LessThanOrEqualToThreshold
DatapointsToAlarm: 1
Dimensions: []
EvaluationPeriods: 1
InsufficientDataActions: []
MetricName: !Sub ${ProjectName}-filter-active
Namespace: !Sub ${ProjectName}-service-status
Period: 300
Statistic: Sum
Threshold: 0.0
TreatMissingData: breaching
メトリクスフィルターのフィルターパターン
メトリクスフィルターではフィルターパターンによってログを監視可能なメトリクスに変換している。
公式リファレンス
参考
下記のフィルターパターンの場合、 ActiveState=active
を含むログがあるときメトリクスの値を 1
とする。
MetricFilter:
Type: AWS::Logs::MetricFilter
Properties:
FilterPattern: "ActiveState=active" ## 適宜書き換え
LogGroupName: !Ref LogGroup
MetricTransformations:
- DefaultValue: 0.0
MetricName: !Sub ${ProjectName}-filter-active
MetricNamespace: !Sub ${ProjectName}-service-status
MetricValue: 1
ログのWatchDog
CloudFormationの下記の項目で TreatMissingData: breaching
と設定すると、ログが定期的に送信されなくなった時アラートを送ることができる。
メトリクスが無い状態をどう扱うか設定しており、この設定では Period: 300
(=5分間) メトリクスが無い場合、 INSUFFICIENT_DATA
としてアラートを送信する。
CloudWatchAlarm:
Type: AWS::CloudWatch::Alarm
Properties:
Period: 300
TreatMissingData: breaching
公式リファレンス