ようへいの日々精進XP

よかろうもん

小ネタ道場一本勝負 〜 AWS CLI と jq を使って CloudWatch Logs にログが転送されていることを確認する手順の一つ 〜

たのもう

CloudWatch Logs Agent の設定をしたばってん、ちゃんとログが転送されていることを確認したい。しかも、AWS CLI で。

一本!

例えば、ロググループが oreno-dev-app というロググループにログを飛ばした場合、以下のように確認したい。

_ENV=dev
_APP=app
_AWS_PROFILE=oreno-profile
_AWS_REGION=ap-northeast-1

#
# ロググループを取得(dev と app という文字列を含んだロググループを取得する)
#
_LOG_GROUP=$(aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} logs describe-log-groups \
             |jq -r ".logGroups[]|select(.logGroupName|contains(\"${_ENV}\"))|select(.logGroupName|contains(\"${_APP}\"))|.logGroupName")
echo ${_LOG_GROUP}

#
# ログストリームから最新の lastEventTimestamp を持ったログストリームを取得
#
_LOG_STREAM=$(aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} logs describe-log-streams --log-group-name ${_LOG_GROUP} \
             |jq -r '.logStreams|sort_by(.lastEventTimestamp)|map(.logStreamName)|.[-1]')
echo ${_LOG_STREAM}

#
# ログイベントから最新の timestamp を持ったログイベントを取得
#
aws --profile ${_AWS_PROFILE} --region ${_AWS_REGION} logs get-log-events --log-group-name ${_LOG_GROUP} --log-stream-name ${_LOG_STREAM} \
| jq '.events|sort_by(.timestamp)|.[-1]'

ひとまず、動作確認なのでログイベントは最新の一件が確認出来れば良い。

ありがとうございました!

jq で配列の最後の要素を取り出す方法が解らなくて苦労したけど、以下のように書けば良かった。

$ jq --version
jq-1.5
$ echo '["a", "b", "c"]' | jq .[-1]

小ネタ道場一本勝負 〜 Datadog で取得出来る Amazon SES のメトリクスを確認する 〜

たのもう

  • Datadog で取得出来る Amazon SES のメトリクスを確認する

参考文献

www.datadoghq.com

docs.aws.amazon.com

docs.aws.amazon.com

docs.aws.amazon.com

一本!

https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/monitor-sending-activity.html によると、SES では以下のような送信イベントを監視しているとのこと。

イベント 詳細
バウンス メールが受取人のメールサーバーにより拒否される(ハードバウンス)、Amazon SES が一定期間に再送してもメールを配信できなかった場合はソフトバウンスとなる
苦情(complaints) 受取人がメールをスパムとしてマーク
送信 Amazon SES への API コールに成功したため、Amazon SES がメールの配信を試行
拒否(rejects) Amazon SES は、最初にメールを受け入れた後、ウイルスを検出して拒否
配信 Amazon SES は、受取人のメールサーバーに E メールを正常に配信

Datadog では以下のようなメトリクス名で取得することが出来るとのこと。

メトリクス 詳細
aws.ses.max_24_hour_send Maximum number of emails that can be sent in a 24 hour period(24 時間で送信可能なメール送信数)
aws.ses.sent_last_24_hours The total number of emails sent in the past 24 hours(過去 24 時間で送信されたメール送信数)
aws.ses.bounces The number of hard bounces(ハードバウンスの数)
aws.ses.complaints The number of complaints(苦情の数)
aws.ses.deliveryattempts The number of delivery attempts(配送を試みた数)
aws.ses.rejects Rejected send attempts(拒否した送信試行数)

ハードバウンスについては https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/e-faq-bn.html に以下のように記述されている。

バウンス率には、まだ検証していないドメインに対するハードバウンスのみが含まれます。ハードバウンスは、"アドレスは存在しません" などの永続的な配信障害です。"メールボックスがいっぱいです" などの一時的かつ断続的な障害や、IP アドレスのブロックによるバウンスは、バウンス率にカウントされません。

苦情については https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/e-faq-cm.html に以下のように記述されている。

受取人が E メールの受け取りを希望していないことを報告した場合に、苦情が発生します。受取人は、E メールクライアントで “これはスパムです” などのボタンをクリックした、E メールプロバイダーに苦情を報告した、Amazon SES ディレクトリに通知した、またはその他の方法を使用した可能性があります。

ありがとうございました

ほとんどドキュメントの写経になったけど、改めてドキュメントを読んでみると認識に誤りがあったりしたので、勉強になった。

小ネタ道場一本勝負 〜 Backlog 記法の表でセル内の文字列を改行したい 〜

たのもう

  • Backlog 記法の表でセル内の文字列を改行したい

一本!

以下のように &br; を改行コードとして書けばイケた。

| ほげほげ | ふがふが |h
| あ&br;い | う&br;え|

実際の出力例。

f:id:inokara:20170227234644p:plain

ありがとうございました

要件に始まり、例に終わる。

あざっす。

2017 年 02 月 24 日(金)

プラミアムフライデー

そっかー。そんな試みがあるのかーくらいのレベル感。

そろそろ

先週のフルマラソンの筋肉痛も和らいできた。

練習を再開しなければ。

フルマラソンは 30 キロからが難しいということを Python + Pandas と Excel で理解する(京都マラソン 2017 の結果を利用して)

f:id:inokara:20170224201145p:plain

フルマラソンは 30 キロからが難しい

と言われていますが、本当なのか、そして、俺は何がダメで 3 時間を切れなかったかをランナーズアップデートで公開されている選手 5000 人の結果を利用して分析してみました。

p.kyoto-marathon.com

先日、走ってきた京都マラソン 2017 の結果を利用させて頂きます。

解析結果

5KM ラップタイムの遷移で見る 3 時間を切る人と切れない人

平均

f:id:inokara:20170225083956p:plain

まずは 5 KM ラップタイムを上位 10 人、ギリギリサブスリー 10 人、サブスリーまでもうひと頑張りの 10 人の各セグメントで平均を取って比較してみました。

上位 10 人

f:id:inokara:20170224202158p:plain

ゴールタイムは 2 時間 27 分〜 2 時間 43 分までの上位選手 10 人分。(25 キロは距離が短いので時間が短くなっている)

ギリギリサブスリーの 10 人

f:id:inokara:20170224202210p:plain

ゴールタイムは 2 時間 59 分台の選手 10 人分。(25 キロは距離が短いので時間が短くなっている)

サブスリーまでもうひと頑張りの 10 人

f:id:inokara:20170224202219p:plain

ゴールタイムは 3 時間 5 分台の選手 10 人分。(25 キロは距離が短いので時間が短くなっている)

見解

  • 上位 10 人は最初の 5KM通過時 と 40KM 通過時のラップタイムの差が小さい
  • サブスリーまでもうひと頑張り必要な人は最初の 5KM 通過時と後半の 5KM のラップタイムの差が大きい
  • 3 時間切れない人は一定したペースで 40KM 走りきる為の走力が備わっていないことが考えられる
  • 19 〜 21 分/5KMくらいの間でおさまるように走り切ることが出来ればサブスリー

フルマラソンは 30 キロからが難しい

最初の 5 キロ

f:id:inokara:20170224202323p:plain

最初の 5 キロはバラつきが多い。スタート直後なので自分のペースを探りながら走っているランナーが多いと思われます。(左にいくほど記録が良いランナー)

10 キロ

f:id:inokara:20170224202412p:plain

10 キロになるとペースが落ち着いてきています。(左にいくほど記録が良いランナー)

15 キロ

f:id:inokara:20170224202423p:plain

15 キロ以降は各ランナーは自分のペースを掴んで安定したペースで走り始めます。

20 キロ

f:id:inokara:20170224202432p:plain

25 キロ

f:id:inokara:20170224202439p:plain

30 キロ

f:id:inokara:20170224202447p:plain

フルマラソンの鬼門、30 キロ以降、各ランナーのペースが少しずつ乱れはじめているのがわかります。

35 キロ

f:id:inokara:20170224202455p:plain

40 キロ

f:id:inokara:20170224202716p:plain

35 キロ以降、最後の 10 キロに走力の差が歴然と出て来るように見えます。走力のある選手もラップタイムが下がってきてはいますが、ゴールタイムが遅くなる選手ほど最後の 5 〜 10 キロのタイムがそれまでの 5 キロと比べると下振れが大きくなっている(遅くなっている)ようです。逆に走力のある選手はタイムが上がっている選手もチラホラ見られます。

後半 15 キロのラップタイムの落ち込み

f:id:inokara:20170225084220p:plain

5 KM ラップタイムを上位 10 人、ギリギリサブスリー 10 人、サブスリーまでもうひと頑張りの 10 人の各セグメントで平均の平均を取り、最初の 5KM 通過時のタイムと 30KM と 35KM 及び 40KM 通過時の 5KM ラップの差分を比較してみました。40KM までの 5KM ではトップ選手でもラップタイムが落ち込んでしまっていることがわかります。但し、トップ選手の落ち込みよりも走力の低い選手の落ち込みが大きいように見られます。

見解

  • 通説通り、30 キロ以降は大体のランナーがラップタイムが下振れする(遅くなる)
  • 記録が芳しくないランナー(走力が無いランナー)程 30 キロ以降のラップタイムが大きく下振れする傾向が見られる

5000 人分の結果を csv ファイルに

結果の取得

ランナーズアップデートは各選手のゼッケン番号毎のページが存在していて、以下のように curlwget を使えばページの HTML を取得することが出来ました。

wget http://p.kyoto-marathon.com/numberfile/10265.html -O 10265.html

但し、頻度の高いアクセスは控えましょう

実際の結果ページは以下のようなページです。

f:id:inokara:20170224202842p:plain

Pandas ライブラリ

Pandas というライブラリを使えば HTML ファイルを解析して、テーブルデータに以下のようにアクセス出来るようになります。

$ python
Python 3.6.0 (default, Dec 24 2016, 07:27:52)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pandas
>>> url = 'http://p.kyoto-marathon.com/numberfile/10265.html'
>>> df = pandas.io.html.read_html(url)
>>> df[0]
           0                               1        2         3
0   地点名Point  スプリット (ネットタイム)Split (Net Time)   ラップLap  通過時刻Time
1        5km              00:23:45 (0:23:31)  0:23:31  09:23:45
2       10km              00:44:43 (0:44:29)  0:20:58  09:44:43
3       15km              01:05:07 (1:04:53)  0:20:24  10:05:07
4       20km              01:25:41 (1:25:27)  0:20:34  10:25:41
5        中間点              01:30:08 (1:29:54)  0:04:27  10:30:08
6       25km              01:46:28 (1:46:14)  0:16:20  10:46:28
7       30km              02:07:45 (2:07:31)  0:21:17  11:07:45
8       35km              02:29:29 (2:29:15)  0:21:44  11:29:29
9       40km              02:54:14 (2:54:00)  0:24:45  11:54:14
10    Finish              03:05:17 (3:05:03)  0:11:03  12:05:17
>>>

各要素へのアクセスは以下のように。

>>> df[0][1]
0     スプリット (ネットタイム)Split (Net Time)
1                 00:23:45 (0:23:31)
2                 00:44:43 (0:44:29)
3                 01:05:07 (1:04:53)
4                 01:25:41 (1:25:27)
5                 01:30:08 (1:29:54)
6                 01:46:28 (1:46:14)
7                 02:07:45 (2:07:31)
8                 02:29:29 (2:29:15)
9                 02:54:14 (2:54:00)
10                03:05:17 (3:05:03)
Name: 1, dtype: object

5000 人分の結果を csv ファイルに

wget で取得した 5000 人分のデータを以下のように csv ファイルに書き出しました。

import glob
import pandas
import csv

with open('output.csv', 'a') as c:
    writer = csv.writer(c, lineterminator='\n')

    file_list = glob.glob('./*.html')
    for file in file_list:
        bib_number = file.split('.')[-2].split('/')[-1]
        # print(bib_number)
        with open(file, 'r') as file:
            table = pandas.io.html.read_html(file.read())
            column = []
            for value in table[0][2]:
                column.append(value)

            # 途中でリタイヤした人対応
            if len(table[0][1]) == 11:
                column.append(table[0][1][10].split('\u3000')[0])

            column.insert(1, bib_number)

            print(column[1:])
            writer.writerow(column[1:])

ということで

サブスリーに向けて

現時点で走力が無い自分がどうするべきか。

  • 20 〜 21 分/5KM で走りきるように頑張る
  • 後半の落ち込みを考えると 19 分台で走れればなお良し
  • 京都マラソンでは前半の 5 KM が 23 分掛かっているので、最初から 20 分台、21 分台で押せるように心がける(トイレ注意)

Python + Pandas

ちょー便利です。

特定の EC2 インスタンスのみ操作出来る IAM Policy の一例

要望

A という IAM ユーザーに特定のインスタンスのみ「起動」と「停止」と「再起動」を出来る権限を付与したい。

一例

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "cloudwatch:*",
                "ec2:Describe*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances",
                "ec2:RebootInstances"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:ec2:ap-northeast-1::instance/${操作したいインスタンス ID}"
        }
    ]
}

他にもあるのかしら。

登録例

#
# Policy ドキュメントの作成
#
cat << EOT >> policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "cloudwatch:*",
                "ec2:Describe*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances",
                "ec2:RebootInstances"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:ec2:ap-northeast-1::instance/${操作したいインスタンス ID}"
        }
    ]
}
EOT

#
# Managed Policy にポリシーを登録する
#
_AWS_PROFILE=washino-profile
_POLICY_ARN=$(aws --profile ${_AWS_PROFILE} iam create-policy --policy-name Ec2OpePolicy --policy-document file://policy.json --query Policy.Arn --output text)
echo ${_POLICY_ARN}

#
# A ユーザーにポリシーを適用する
#
_USER_NAME=user_a
aws --profile ${_AWS_PROFILE} iam attach-user-policy --policy-arn ${_POLICY_ARN} --user-name ${_USER_NAME}
aws --profile ${_AWS_PROFILE} iam list-user-policies --user-name ${_USER_NAME}
aws --profile ${_AWS_PROFILE} iam get-user-policy --user-name ${_USER_NAME} --policy-name Ec2OpePolicy

以上

メモでした。

2017 年 02 月 23 日(木)

そら豆

鹿児島から「そら豆」が届く。早速、奥さんに剥いてもらって茹でて食した。

綺麗な緑色で本当に美味しかった。

たんかん

こちらも鹿児島のおばさんから「たんかん」が届く。

有り難い。

そういえば

今日は思ったよりも冷えた一日だった。