コピペで使えるELBのアクセスログ解析による事象分析 (ShellScript, Athena)

アクセスログ解析

ELBのアクセスログの事象分析について、ShellScriptとAthenaを用いた実行例についてまとめます。

ShellScript

CLB

No.1 : レスポンスが正常に受け取れていないELBのレスポンスコード毎のカウント

$ awk '$10 == "-"' * | awk '{print $9}' | sort | uniq -c

No.2 : ELBのレスポンスコード毎の数集計

$ awk '{print $8}' *.log | sort | uniq -c

No.3 : 504のレコード一覧

$ awk '$8 == 504'

No.4 : 504がどのELBノードから多く出力されているか

$ grep ' 504 ' *.log | awk '{print $3}' | sed 's/:.*//' | sort | uniq -c

No.5 : バックエンドから正常に応答が受け取れていない時

$ awk '{if (! int($5) < 0) {print $0}}' * | egrep '2018-01-2[45]'

No.6 : target_processing_time の3つの統計値(最小値、最大値、平均)と -1 の値を取った回数を表示する

$ awk '{ print $4,$8,$9,$6 }' * | sort | sed -e 's/ /!!/' -e 's/ /!!/' | awk '{if(count[$1]==0) min[$1]=100; count[$1]+=1; if(max[$1]<$2&&$2!=-1) max[$1]=$2; if(min[$1]>$2&&$2!=-1) min[$1]=$2; if($2!=-1)sum[$1]+=$2; else minus[$1]+=1;} END{for(k in count)print k,", count:",count[k],", max:",max[k],", min:",min[k],", avg:",sum[k]/count[k],", -1:",minus[k];}' | sort -k4nr

No.7 : response_processing_time の3つの統計値(最小値、最大値、平均)と -1 の値を取った回数を表示する

$ awk '{ print $4,$8,$9,$7 }' * | sort | sed -e 's/ /!!/' -e 's/ /!!/' | awk '{if(count[$1]==0) min[$1]=100; count[$1]+=1; if(max[$1]<$2&&$2!=-1) max[$1]=$2; if(min[$1]>$2&&$2!=-1) min[$1]=$2; if($2!=-1)sum[$1]+=$2; else minus[$1]+=1;} END{for(k in count)print k,", count:",count[k],", max:",max[k],", min:",min[k],", avg:",sum[k]/count[k],", -1:",minus[k];}' | sort -k4nr

No.8 : 最も多いリクエスト元のELBノードIPアドレスのリクエスト数

$ awk '{print $3}' * | awk -F ":" '{print $1}' | sort | uniq -c | sort -r| head -n 10 

No.9 : 時間毎のリクエスト数

grep中の二重引用符内は適宜日付等を入れて絞り込み

grep -r "" . | cut -d [ -f2 | cut -d] -f1 | awk -F: '{print $2":00"}' | sort -n | uniq -c

No.10 : 分単位でのリクエスト数

grep中の二重引用符内は適宜日付等を入れて絞り込み

$ grep "" * | cut -d [ -f2 | cut -d ] -f1 | awk -F: '{print $2":"$3}' | sort -nk1 -nk2 | uniq -c | awk '{ if ($1 > 10) print $0}'

No.11 : ユーザーエージェント毎のランキング

$ awk '{split($0, array, """); agent=array[4]; print agent}' * | sort | uniq -c | sort -nr | head

No.12 : TLSでクライアントが最も使った暗号スイートのランキング

$ awk '{split($0, array, """); afterUserAgent=array[5]; print afterUserAgent}' * | awk '{print $1}' | sort | uniq -c | sort -nr | head -5

No.13 : TLSでクライアントが最も使ったTLSバージョンのランキング

$ awk '{split($0, array, """); afterUserAgent=array[5]; print afterUserAgent}' * | awk '{print $2}' | sort | uniq -c | sort -nr | head

No.14 : TLSでクライアントが最も使ったプロトコルと暗号スイートのランキング

$ awk '{split($0, array, """); proto=array[1]; afterUserAgent=array[5]; print proto afterUserAgent}' * | awk '{print $1 " " $13}' | sort | uniq -c | sort -nr | head

ALB

No.1 : target_processing_time の3つの統計値(最小値、最大値、平均)と -1 の値を取った回数を表示する

 $ awk '{ print $5,$9,$10,$7 }' * | sort | sed -e 's/ /!!/' -e 's/ /!!/' | awk '{if(count[$1]==0) min[$1]=100; count[$1]+=1; if(max[$1]<$2&&$2!=-1) max[$1]=$2; if(min[$1]>$2&&$2!=-1) min[$1]=$2; if($2!=-1)sum[$1]+=$2; else minus[$1]+=1;} END{for(k in count)print k,", count:",count[k],", max:",max[k],", min:",min[k],", avg:",sum[k]/count[k],", -1:",minus[k];}' | sort -k4nr

No.2 : response_processing_time の3つの統計値(最小値、最大値、平均)と -1 の値を取った回数を表示する

$ awk '{ print $5,$9,$10,$8 }' * | sort | sed -e 's/ /!!/' -e 's/ /!!/' | awk '{if(count[$1]==0) min[$1]=100; count[$1]+=1; if(max[$1]<$2&&$2!=-1) max[$1]=$2; if(min[$1]>$2&&$2!=-1) min[$1]=$2; if($2!=-1)sum[$1]+=$2; else minus[$1]+=1;} END{for(k in count)print k,", count:",count[k],", max:",max[k],", min:",min[k],", avg:",sum[k]/count[k],", -1:",minus[k];}' | sort -k4nr

Athena

以下、全て CLB を前提とします。
また、以下のような、デフォルトで生成されている sampledb データベースの elb_logs テーブルを使用します。

CREATE EXTERNAL TABLE `elb_logs`(
  `request_timestamp` string COMMENT '', 
  `elb_name` string COMMENT '', 
  `request_ip` string COMMENT '', 
  `request_port` int COMMENT '', 
  `backend_ip` string COMMENT '', 
  `backend_port` int COMMENT '', 
  `request_processing_time` double COMMENT '', 
  `backend_processing_time` double COMMENT '', 
  `client_response_time` double COMMENT '', 
  `elb_response_code` string COMMENT '', 
  `backend_response_code` string COMMENT '', 
  `received_bytes` bigint COMMENT '', 
  `sent_bytes` bigint COMMENT '', 
  `request_verb` string COMMENT '', 
  `url` string COMMENT '', 
  `protocol` string COMMENT '', 
  `user_agent` string COMMENT '', 
  `ssl_cipher` string COMMENT '', 
  `ssl_protocol` string COMMENT '')
ROW FORMAT SERDE 
  'org.apache.hadoop.hive.serde2.RegexSerDe' 
WITH SERDEPROPERTIES ( 
  'input.regex'='([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*):([0-9]*) ([.0-9]*) ([.0-9]*) ([.0-9]*) (-|[0-9]*) (-|[0-9]*) ([-0-9]*) ([-0-9]*) \"([^ ]*) ([^ ]*) (- |[^ ]*)\" ("[^"]*") ([A-Z0-9-]+) ([A-Za-z0-9.-]*)$') 
STORED AS INPUTFORMAT 
  'org.apache.hadoop.mapred.TextInputFormat' 
OUTPUTFORMAT 
  'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
  's3://athena-examples-us-west-2/elb/plaintext'
TBLPROPERTIES (
  'transient_lastDdlTime'='1480278335');

HTTPステータスコードが200のレコード一覧

SELECT * 
FROM elb_logs
WHERE elb_response_code <> '200'
ORDER BY request_timestamp;

ELB毎のリクエスト数

SELECT elb_name,
         count(*) AS request_count
FROM elb_logs
GROUP BY elb_name
ORDER BY request_count DESC;

ELB毎のリクエスト数(期間指定)

SELECT elb_name,
         count(*) AS request_count
FROM elb_logs
WHERE request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp < '2016-01-01T00:00:00Z'
GROUP BY elb_name
ORDER BY request_count DESC;

ELB毎のリクエスト数(期間+ELB 指定)

SELECT elb_name,
         count(*) AS request_count
FROM elb_logs
WHERE elb_name LIKE 'elb_demo_008'
        AND request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp < '2016-01-01T00:00:00Z'
GROUP BY elb_name
ORDER BY request_count DESC;

ELB毎の5XXエラーのリクエスト数

SELECT elb_name,
         backend_response_code,
         count(*) AS request_count
FROM elb_logs
WHERE backend_response_code >= '500'
GROUP BY backend_response_code, elb_name
ORDER BY backend_response_code, elb_name;

ELB毎の5XXエラーのリクエスト数(ELB指定)

SELECT elb_name,
         backend_response_code,
         count(*) AS request_count
FROM elb_logs
WHERE elb_name LIKE 'elb_demo_008'
        AND backend_response_code >= '500'
GROUP BY backend_response_code, elb_name
ORDER BY backend_response_code, elb_name;

ELB毎の5XXエラーのリクエスト数(期間+ELB 指定)

SELECT elb_name,
         backend_response_code,
         count(*) AS request_count
FROM elb_logs
WHERE elb_name LIKE 'elb_demo_008'
        AND backend_response_code >= '500'
        AND request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp < '2016-01-01T00:00:00Z'
GROUP BY backend_response_code, elb_name
ORDER BY backend_response_code, elb_name;

ELB毎の5XXエラーのリクエスト数(期間+ELB+URL 指定)

SELECT count(*) AS request_count,
         elb_name,
         url,
         elb_response_code,
         backend_response_code
FROM elb_logs
WHERE elb_name LIKE 'elb_demo_008'
        AND backend_response_code >= '500'
        AND url LIKE 'http://www.example.com/jobs/%'
        AND request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp < '2016-01-01T00:00:00Z'
GROUP BY elb_name,url,elb_response_code,backend_response_code
ORDER BY request_count DESC limit 10;

ELB毎の5XXエラーのリクエスト数(期間+ELB+URL+UserAgent 指定)

SELECT count(*) AS request_count,
         elb_name,
         url,
         elb_response_code,
         backend_response_code,
         user_agent
FROM elb_logs
WHERE elb_name LIKE 'elb_demo_008'
        AND backend_response_code >= '500'
        AND url LIKE 'http://www.example.com/jobs/%'
        AND user_agent LIKE '%Mozilla/5.0%'
        AND request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp < '2016-01-01T00:00:00Z'
GROUP BY elb_name,url,elb_response_code,backend_response_code,user_agent
ORDER BY request_count DESC limit 10;

送信元IPのリクエスト数ランキング

SELECT request_ip,
         url,
         count(*) AS request_count
FROM elb_logs
WHERE elb_name LIKE 'elb_demo_008'
        AND request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp < '2016-01-01T00:00:00Z'
GROUP BY request_ip,url
ORDER BY request_count DESC limit 5;

日付ごとのリクエスト数

SELECT date(from_iso8601_timestamp(request_timestamp)),
         count(*)
FROM elb_logs
WHERE url LIKE '%/jobs/%'
        AND date(from_iso8601_timestamp(request_timestamp)) >= date('2014-12-01')
GROUP BY  1
ORDER BY  1;

直近1年の500エラー発生のリクエスト数

SELECT elb_response_code,
         count(*)
FROM elb_logs
WHERE from_iso8601_timestamp(request_timestamp) >= date_add('day', -365 * 1, now())
        AND elb_response_code >= '500'
GROUP BY  1
ORDER BY  1;

レスポンスに1.0s以上時間がかかっているリクエスト

SELECT url,
         count(*) AS count,
         backend_processing_time
FROM elb_logs
WHERE backend_processing_time >= 1.0
GROUP BY  url, backend_processing_time
ORDER BY backend_processing_time DESC;

任意のエントリ取得(期間+リクエスト元IP 指定)

SELECT *
FROM elb_logs
WHERE request_ip = '245.85.197.169'
        AND request_timestamp >= '2014-01-01T00:00:00Z'
        AND request_timestamp <= '2016-01-01T00:00:00Z';

あるページからの遷移先ページ傾向

SELECT d.*
FROM 
    (SELECT b.request_ip,
         min(b.request_timestamp) AS request_timestamp
    FROM 
        (SELECT *
        FROM elb_logs
        WHERE url LIKE '%/jobs/%') a
        JOIN elb_logs b
            ON a.request_timestamp < b.request_timestamp
        GROUP BY  1 ) c
    JOIN elb_logs d
    ON c.request_ip = d.request_ip
        AND c.request_timestamp = d.request_timestamp
ORDER BY  d.request_timestamp;

参考

ELB アクセスログ

Classic Load Balancer のアクセスログ – Elastic Load Balancing
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/classic/access-log-collection.html#access-log-entry-syntax
Application Load Balancer のアクセスログ – Elastic Load Balancing
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-access-logs.html#access-log-entry-syntax

Athena

Querying Classic Load Balancer Logs – Amazon Athena
https://docs.aws.amazon.com/ja_jp/athena/latest/ug/elasticloadbalancer-classic-logs.html
Querying Application Load Balancer Logs – Amazon Athena
https://docs.aws.amazon.com/athena/latest/ug/application-load-balancer-logs.html

Amazon AthenaでELBのログを調査するときに使ったSQL
https://dev.classmethod.jp/cloud/amazon-athena-sql-for-elb/
Amazon AthenaでELBログをSQLで解析する #reinvent
https://dev.classmethod.jp/cloud/aws/amazon-athena-sql-elb-log-reinvent/
Amazon Athenaではじめるログ分析入門
https://qiita.com/miyasakura_/items/174dc73f706e8951dbdd

続きを読む

Amazon Echo(Alexa)スキル「レトロソフト検索」申請が通ったまでの経緯と愚痴

Amazon Echo(Alexa)スキル「レトロソフト検索」を公開しました。

■犯行までの動機

Alexaスキルを作ろうと思い始めたのが12月半ば、っても何を作って良いのか解らず、何が出来るのかもよくわかんない。
とりあえずそんなに件数が多くないデータベースを検索する機能がやりたかった為、ファミコンソフト(1254本)
のソフト検索を作成。
実用性は、、、ないかもな。

そんなこんなで、echo dotが年末に届き、やっと実機で動作確認。
正月明けくらいから、ほぼ毎日Amazonへスキル申請→リジェクト→修正、申請→リジェクト、、、
6回目でやっと通ったよ(´ω`)

リジェクトされた内容をまとめましたので、参考になればこれ幸いかと。

■「レトロソフト検索」スキル仕様

・AWS Lambda(python3)
・DBはsqlite、テーブルは1テーブルのみの簡単なもの。

ユーザーがゲームタイトル、メーカー名、発売日(MM/DD)を発話することで、アレクサが検索結果を返します。
3件以上あった場合は上位3件のみアレクサが発話し、リストをカードに表示。
カードに表示された番号をユーザーが発話することで、該当ゲームの詳細データをアレクサが発話します。

要はDBのLike検索でひっぱってきてるだけな簡単なお仕事です。

■■■怒濤のリジェクト内容■■■

■スキル開始サンプル発話不具合

1.コンパニオンアプリでユーザーへの提示用に選ばれたサンプルフレーズは、現在、サポートされていない
起動フレーズを使用しています。
サンプルフレーズ:アレクサ、レトロソフト検索、開始

修正例:アレクサ、レトロソフト検索を開いて

対応内容:テスト画面で「レトロソフト検索、開始」でやっていたのでそのまま入力したが、だめらしい。
開始発話を「アレクサ、レトロソフト検索を開いて」に直して対応

■Lambda側バグ

再現手順:
ユーザー:アレクサ、レトロソフト検索を開いて
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名で検索します。
~中略~
スキル:スキルからの応答に問題があります
((セッションクローズ))

対応内容:Lambda側エラーで落ちてたよ。Lambdaを修正。

■アレクサ発話内容修正

ユーザーがスキル内の「ヘルプ」をリクエストした際、
スキルはユーザーにスキルのコア機能の操作方法を示すプロンプトを返す必要があります。
また、ヘルププロンプトはユーザーへの質問で終わり、
応答を受信するまでセッションを開いたままにしておく必要があります。

1.再現手順:
ユーザー:ヘルプ
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名で検索します。
((セッションオープン))

修正例:
ユーザー:ヘルプ
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名を言ってみてください。
((セッションオープン))

2.再現手順:
ユーザー:アレクサ、レトロソフト検索を開いて。
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名で検索します。
((セッションオープン))

修正例:
ユーザー:アレクサ、レトロソフト検索を開いて。
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名で検索します。どうぞ。
((セッションオープン))

対応内容:同じ内容のリジェクトを3回ほど食らっており、最初は何ってんのか判らなかったが、ユーザーに発話させるタイミングを、アレクサ側から伝える必要があるらしい。文末に「言ってみてください」「どうぞ」を追加し対応。
そいや、アレクサ発話中にはユーザー発話は受け付けないのか(不便)

■サンプル発話修正

データのフォーマットが弊社の規定に沿っていません。サンプル発話、スロット値のデータは、
全て日本語で表示する必要があります(頭文字、イニシャリズム、アクロニムを除く)。
以下を削除の上、再度ご申請ください。

intent_SelectGameSeqNO   NO {slot_no}

対応内容:ユーザー発話として「NO(ナンバー)XX」を予測し入れていたが、ナンバーを「NO」と英語で記述しちゃダメらしい、上記サンプル発話を削除し対応。

複数のインテントに同一のサンプル発話が含まれています。
ユーザーのリクエストが正しいインテントへ送られるように、各インテントに独自のサンプル発話が必要です。
問題点:
AMAZON.StopIntent    止めて
AMAZON.StopIntent    とめて
AMAZON.CancelIntent 止めて
サンプル発話の作成について詳しくは、下記のリンク先をご参照ください。

対応内容:サンプル発話で、同じ命令「止めて」が違うインテントで被ってると、何処で認識できるのかわからなくなる模様。「AMAZON.CancelIntent 止めて」を削除し対応。

複数のインテントに類似の発話例が含まれています。
ユーザーのリクエストが正しいインテントへ送られるように、各インテントに独自の発話例が必要です。

該当箇所: AMAZON.CancelIntent  中止

注)AMAZON.StopIntent に「中止」が定義されているため、
発話例にAMAZON.CancelIntentで「中止」を入れることにより、
アレクサが混乱し違うインテントに入ってしまっています。そのため、上記の該当箇所を削除してください。

対応内容:「AMAZON.StopIntent」にはデフォルトで「中止」が含まれている為、他のインテントで定義しちゃだめらしい。(しらんがな)「AMAZON.CancelIntent  中止」を削除し対応。

■スキル説明メッセージ記述ミス

スキルの詳細ページには、タイポや文法的な誤りがないようにしてください。文法にとらわれない自由な表現は、
ブランド固有のものに限り可能です。

問題点:
該当データは複数ある場合には → 該当データが複数ある場合には

問題点:
上位3件の実お伝えします → 上位3件のみお伝えします

対応内容:ワイの記述ミス、すまんかった。

■DB検索処理不具合

再現手順:
ユーザー:アレクサ、レトロソフト検索を開い て.
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名で検索します。どうぞ

ユーザー:カケフくんのジャンプ天国スピード地獄 を探して.
スキル:該当結果はありません。発売日、ゲームタイトル、又はメーカー名を言ってください。どうぞ

想定される結果:
ユーザー:アレクサ、レトロソフト検索を開い て.
スキル:レトロソフト検索にようこそ。発売日、ゲームタイトル、又はメーカー名で検索します。どうぞ 

ユーザー:カケフくんのジャンプ天国スピード地獄を探して.
スキル:検索結果は1件あります。1.カケフ くん の ジャンプ 天国
スピード 地獄詳細は該当の番号を指定願います。又「戻る」で再度検索します。どうぞ

注:同様の問題が他のスロットの値でも起こらないよう全てのスロットの値を確認してください。

対応内容:DB上検索するデータが「カケフくんのジャンプ天国 スピード地獄」とスペースが入っており
フェッチできなかった。DBデータからスペースを削除し、検索に引っかかるように対応。

■サンプル発話内容不足

言い回しの異なるサンプル発話が不足しています。
スキルを確実に起動させ、多くのユーザーのリクエストに対応するためには、サンプル発話を充実させる必要があります。
今回ご提示いただいたサンプル発話のみでは、スキルが確実に起動しない可能性があります。
以下のようなサンプル発話を追加して、再度ご申請ください。

intent_GameTitle    {GameName} で検索して
intent_MakerName    {MakerName} のゲームを検索して
intent_MakerName    {MakerName} のゲームを教えて
など

対応内容:ゲームタイトル、メーカー名のサンプル発話が足りなかった模様。
むしゃくしゃしたから以下の様に追加してやったぜぇ。ワイルドだろう?

intent_GameTitle {GameName}
intent_GameTitle {GameName} の検索
intent_GameTitle {GameName} を検索
intent_GameTitle {GameName} で検索
intent_GameTitle {GameName} を検索して
intent_GameTitle {GameName} で検索して
intent_GameTitle {GameName} を検索してね
intent_GameTitle {GameName} で検索してね
intent_GameTitle {GameName} を探して
intent_GameTitle {GameName} で探して
intent_GameTitle {GameName} を探せ
intent_GameTitle {GameName} で探せ
intent_GameTitle {GameName} を探そう
intent_GameTitle {GameName} で探そう
intent_GameTitle {GameName} を探そうか
intent_GameTitle {GameName} で探そうか

intent_MakerName {MakerName}
intent_MakerName {MakerName} のゲームは
intent_MakerName {MakerName} のソフトは
intent_MakerName {MakerName} のカセットは
intent_MakerName {MakerName} のタイトルは
intent_MakerName {MakerName} の検索
intent_MakerName {MakerName} を検索
intent_MakerName {MakerName} で検索
intent_MakerName {MakerName} の検索して
intent_MakerName {MakerName} を検索して
intent_MakerName {MakerName} で検索して
intent_MakerName {MakerName} の検索してね
intent_MakerName {MakerName} を検索してね
intent_MakerName {MakerName} で検索してね
intent_MakerName {MakerName} のを探して
intent_MakerName {MakerName} を探して
intent_MakerName {MakerName} で探して
intent_MakerName {MakerName} のを探せ
intent_MakerName {MakerName} を探せ
intent_MakerName {MakerName} で探せ
intent_MakerName {MakerName} を探そう
intent_MakerName {MakerName} で探そう
intent_MakerName {MakerName} を探そうか
intent_MakerName {MakerName} で探そうか
intent_MakerName {MakerName} のゲームを検索して
intent_MakerName {MakerName} のゲームを教えて
intent_MakerName {MakerName} のゲームタイトルは
intent_MakerName {MakerName} のゲームタイトルを教えて

■■■怒濤の愚痴その他■■■

アレクサ認識について

・アレクサが数値(Amazon.Number)を認識すると、全角の「1」「2」や、日本語読みの「一」「二」
で認識する。半角じゃねえのかよ。

・ゲームタイトルやメーカー名のサンプル発話で、スロットに10個程入れれば、後は自動で認識してくれるもんだ、
あーAIってすばらしい、楽ちん。とそんなふうに考えていた時期が僕にもありました。

結局、ゲームタイトル、メーカーも全部入れないと、メーカー名なのにゲームタイトルと認識しちゃったりするんだぜぇ。
むしゃくしゃしたから、ゲームタイトル1254、メーカー名100も全部スロットに突っ込んでやったぜぇ。

1254個もスロットに突っ込むと、スキルビルダー(ベータ版)で表示したときに重くてやんなるぜぇ。
こんなので本当に1スロットに5万もはいるのかいな。

アレクサ数値発話について

・アレクサに数値を発話させる際、ゲームタイトルにより
「ドラゴンクエスト2」(ツー)
「スーパーマリオブラザーズ3」(スリー)
の様に、表示は数字だけど英語読みで発話させたい場合や、
「魂斗羅」を「コントラ」と読ませたいが、そのままでは「たましいとら」と発話したり
「源平討魔伝」(げんぺいとうまでん)を発話させると「げんぺいうちまでん」と発話したり
もう大変。

前半の数値読みはSSMLで対応してもいいんですが、後半の別名読みは日本語対応のSSMLでなさそう。
(英語ではあるみたい)

その為、DB側で表示用と発話用のカラムを分けています。
又、「2」を「つう」としていますが「ツー」と発話するよりもそれっぽい感じになります。

ゲームタイトル(表示用) ゲームタイトル(発話用)
ドラゴンクエスト2 ドラゴンクエストつう
ドラゴンクエスト4 ドラゴンクエストフォー
ロックマン6 ロックマンシックス

・「スーパーマリオ」を発話させると、どこかのスーパーマーケット店みたいな発音されるが
日本語SSMLでアクセント対応してないので、どうにもならず。

スキルの名前は大切

「ファミコン検索」とかにしたかったのですが、たぶん著作権的にダメだろうと思い
当初は「レトロゲーム検索」としてたのですが、実機でテストした際、アレクサがどうも
「レトロ ゲーム 検索」
と認識し、Amazonの買い物サイトで勝手にカートへ「レトロゲーム」を入れたがっていたので、
誤検知しない様にこの名前にしました。
ちゃんと実機でテストしないと、言いにくい名前だったりするので、名前は大切。

カード改行の謎

カードに表示させる際、改行コード”\r”で行っていますが、スマホアプリでは綺麗に改行されますが
PCのスキルポータルサイトでは改行されねえよ。

かといって、”\r\n”だと、PCのスキルポータルサイトではなんとか改行されるが、
スマホアプリでは無駄に行間が空いてどっちにしろ見づらいよ。
その為、現行は”\r”にしてます。

テストについて

はっきり言って一人だけでは、ゲームソフトすべて(1254本+メーカー+日付)のテストはむりぽよです。
あとめんどくさい(´ω`)
検索できないタイトルや、不具合がありましたら、スキル画面から申請ください(´・ω・`)。

あとスキルポータルサイトで、このスキルの起動発話が文字化けしてますが、。Alexa Skill Kitの申請画面ではちゃんと表示されているので謎です。Amazonには問い合わせています。

続きを読む

【CPUの脆弱性対応】古いAmazon Linuxのkernelを最新版にアップデートする

AWSで管理しているAmazon Linuxが古いバージョンのまま放置していることありませんか?

CPUの脆弱性対応におけるAWSの公式ドキュメント

Customers with existing Amazon Linux AMI instances should run the following command to ensure they receive the updated package: sudo yum update kernel.

カーネルをアップデートして最新のカーネルにするように書いてあるのですが、
Amazon Linuxのバージョンが古いインスタンスでは、
単にカーネルのアップデートだけでは、最新のカーネルにアップデートされません。

この記事ではその際の対応手順を説明します。

※ 説明のためにコミュニティAMIにある古いAMIを使って進めます。

対象のマシンにsshし、インフォメーションをチェック

しばらくOSをアップデートされていないインスタンスにsshします。
OSが更新されていない場合は、以下のように

$ ssh hogehost

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2016.03-release-notes/
Amazon Linux version 2017.09 is available.

Amazon Linux version 2017.09 is available.
Amazon Linux version 2017.09が利用できます

と表示されていますね。
あまり意識しないと見逃しがちですが、このような情報もしっかり確認しましょう。

さらにカーネルのバージョンを確認します。

$ uname -srv
Linux 4.4.5-15.26.amzn1.x86_64 #1 SMP Wed Mar 16 17:15:34 UTC 2016

カーネルも2016年に作られたバージョンのままになっていますね。

yum.confをチェックし、AMIを特定のバージョンに固定されていないか確認する

AMIを特定のバージョンに固定するにはどうすればよいですか?

上記の公式ドキュメントに書かれているようにAmazon Linuxのマシーンイメージでは、1つのバージョンから次のバージョンへ連続的な更新を提供するように設定されていますが、過去のバージョンでは/etc/yum.confreleasever変数がなかったり、リリースバージョンが固定されていることがあります。

その場合は単にyum updateだけでは最新のパッケージに更新されません。

今回対象のyum.confを見てみると

$ cat /etc/yum.conf
[main]
cachedir=/var/cache/yum/$basearch/$releasever
keepcache=0
debuglevel=2
logfile=/var/log/yum.log
distroverpkg=system-release
exactarch=1
obsoletes=1
gpgcheck=1
plugins=1
installonly_limit=3
deltarpm=0

# by default the yum configuration will point to the latest release
# of Amazon Linux AMI. If you prefer not to automatically move to
# new releases, comment out this line.
releasever=2016.03

#  This is the default, if you make this bigger yum won't see if the metadata
# is newer on the remote and so you'll "gain" the bandwidth of not having to
# download the new metadata and "pay" for it by yum not having correct
# information.
#  It is esp. important, to have correct metadata, for distributions like
# Fedora which don't keep old packages around. If you don't like this checking
# interupting your command line usage, it's much better to have something
# manually check the metadata once an hour (yum-updatesd will do this).
# metadata_expire=90m

# PUT YOUR REPOS HERE OR IN separate files named file.repo
# in /etc/yum.repos.d

releasever2016.03に固定されています。

この状態では、カーネルをアップデートしても変更されません。

$ sudo yum update kernel
Loaded plugins: priorities, update-motd, upgrade-helper
No packages marked for update

そこで更新させるためには以下のように変更する必要があります。

releasever=latest

releaseverを「latest」に変更して、カーネルをアップデート

先ほどのyum.confのリリースサーバーを最新に更新します。

$ cp -ip /etc/yum.conf  /tmp/
$ sudo vi /etc/yum.conf
$ diff /etc/yum.conf /tmp/yum.conf
17c17
< releasever=latest
---
> releasever=2016.03
#更新しました

# kernelをアップデートする
$ sudo yum update kernel
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main/latest                                                                                                                                                                                                                 | 2.1 kB     00:00
amzn-updates/latest                                                                                                                                                                                                              | 2.3 kB     00:00
Resolving Dependencies
--> Running transaction check
---> Package kernel.x86_64 0:4.9.51-10.52.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

========================================================================================================================================================================================================================================================
 Package                                                 Arch                                                    Version                                                               Repository                                                  Size
========================================================================================================================================================================================================================================================
Installing:
 kernel                                                  x86_64                                                  4.9.51-10.52.amzn1                                                    amzn-main                                                   17 M

Transaction Summary
========================================================================================================================================================================================================================================================
Install  1 Package

Total download size: 17 M
Installed size: 71 M
Is this ok [y/d/N]: y
Downloading packages:
kernel-4.9.51-10.52.amzn1.x86_64.rpm                                                                                                                                                                                             |  17 MB     00:01
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : kernel-4.9.51-10.52.amzn1.x86_64                                                                                                                                                                                                     1/1
  Verifying  : kernel-4.9.51-10.52.amzn1.x86_64                                                                                                                                                                                                     1/1

Installed:
  kernel.x86_64 0:4.9.51-10.52.amzn1

Complete!

先ほどは、アップデートするカーネルはありませんでしたが、今回はアップデートされました。

再起動後に再度インスタンスにアクセスして、カーネルがアップデートされたか確認します。

$ ssh hogehost
Last login: Sat Jan 20 02:10:39 2018 

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2016.03-release-notes/
No packages needed for security; 138 packages available
Run "sudo yum update" to apply all updates.
Amazon Linux version 2017.09 is available.

$ uname -srv
Linux 4.9.51-10.52.amzn1.x86_64 #1 SMP Fri Sep 29 01:16:19 UTC 2017

カーネルは4.4.5から4.9.51に上がったようですね。ところがまだ最新ではないです。

またsshを行ったら、早速情報が更新されています。

No packages needed for security; 138 packages available
Run “sudo yum update” to apply all updates.

カーネルのアップデートではなく、パッケージのアップデートを勧められています。

全てのパッケージアップデートする

そこでカーネルだけれはなく全てのパッケージをアップデートさせます。

パッケージを全てアップデートすると既存で動いているサービスに影響を与えることがあるので、バージョンの依存関係があるパッケージについては除外しましょう

今回はカーネルを最新にアップデートさせることが目標なので、上記を考慮せずに全てのパッケージをアップデートします。

$ sudo yum update
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package acpid.x86_64 0:1.0.10-2.1.6.amzn1 will be updated
---> Package acpid.x86_64 0:2.0.19-6.7.amzn1 will be an update
・・・(省略)

# インストールとアップデートをするパッケージが一覧されるのでチェック
========================================================================================================================================================================================================================================================
 Package                                                                Arch                                            Version                                                                Repository                                          Size
========================================================================================================================================================================================================================================================
Updating:
 acpid                                                                  x86_64                                          2.0.19-6.7.amzn1                                                       amzn-main                                           73 k
 at                                                                     x86_64                                          3.1.10-48.15.amzn1                                                     amzn-main                                           66 k
 audit                                                                  x86_64                                          2.6.5-3.28.amzn1                                                       amzn-main                                          272 k
 audit-libs                                                             x86_64                                          2.6.5-3.28.amzn1                                                       amzn-main                                           96 k
・・・(省略)
Installing for dependencies:
 libXcomposite                                                          x86_64                                          0.4.3-4.6.amzn1                                                        amzn-main                                           21 k
 libidn2                                                                x86_64                                          0.16-1.2.amzn1                                                         amzn-main                                          103 k
 libnghttp2                                                             x86_64                                          1.21.1-1.4.amzn1                                                       amzn-main                                           73 k
 libseccomp                                                             x86_64                                          2.3.1-2.4.amzn1                                                        amzn-main                                           79 k
 libunistring                                                           x86_64                                          0.9.3-6.1.amzn1                                                        amzn-main                                          419 k
 perl-Time-HiRes                                                        x86_64                                          4:1.9725-272.5.amzn1                                                   amzn-main                                           46 k
 python27-futures                                                       noarch                                          3.0.3-1.3.amzn1                                                        amzn-main                                           30 k

Transaction Summary
========================================================================================================================================================================================================================================================
Install               ( 7 Dependent packages)
Upgrade  138 Packages

Total download size: 192 M

yum updateでは、インストールを始める前に、インストールとアップデートをするパッケージが一覧されます。
その後にアップデートするか選べるので、パッケージを確認してから、動いているサービスに影響がないか確認するといいと思います。

このままアップデートを実行します。

Is this ok [y/d/N]: y

Downloading packages:
(1/145): acpid-2.0.19-6.7.amzn1.x86_64.rpm                                                                                                                                                                                       |  73 kB     00:00
(2/145): at-3.1.10-48.15.amzn1.x86_64.rpm                                                                                                                                                                                        |  66 kB     00:00
・・・(省略)
  xfsprogs.x86_64 0:4.5.0-9.21.amzn1                              yum.noarch 0:3.4.3-150.70.amzn1                            yum-metadata-parser.x86_64 0:1.1.4-10.20.amzn1                  yum-plugin-priorities.noarch 0:1.1.31-40.29.amzn1
  yum-plugin-upgrade-helper.noarch 0:1.1.31-40.29.amzn1           yum-utils.noarch 0:1.1.31-40.29.amzn1

Complete!

全てのパッケージをアップデートしました。再起動を行い、再度sshします。

$ ssh hogehost
Last login: Sat Jan 20 02:17:24 2018 

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/
10 package(s) needed for security, out of 34 available
Run "sudo yum update" to apply all updates.

$ uname -srv
Linux 4.9.51-10.52.amzn1.x86_64 #1 SMP Fri Sep 29 01:16:19 UTC 2017

カーネルのバージョンはかわっていませんが、

10 package(s) needed for security, out of 34 available
Run “sudo yum update” to apply all updates.

バージョンアップ後、さらにセキュリティ問題のためアップデートするように警告されていますね。

すべでのパッケージをアップデートしたことで、最新のカーネルにアップデートできるようになりました。

パッケージ全てをアップデートする(2回目)

最新のカーネルにアップデートするべく、再度アップデートします。

$ sudo yum update
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
・・・(省略)

Installed:
  kernel.x86_64 0:4.9.77-31.58.amzn1

Dependency Installed:
  libtool-ltdl.x86_64 0:2.4.2-20.4.8.5.32.amzn1                                                                                     nss-pem.x86_64 0:1.0.3-4.3.amzn1

Updated:
  aws-cfn-bootstrap.noarch 0:1.4-27.19.amzn1      aws-cli.noarch 0:1.14.9-1.48.amzn1         curl.x86_64 0:7.53.1-13.80.amzn1               docker.x86_64 0:17.09.1ce-1.111.amzn1            docker-storage-setup.noarch 0:0.6.0-1.18.giteb688d4.amzn1
  ec2-net-utils.noarch 0:0.5-1.34.amzn1           ec2-utils.noarch 0:0.5-1.34.amzn1          ecs-init.x86_64 0:1.16.2-1.amzn1               irqbalance.x86_64 2:1.3.0-1.26.amzn1             java-1.7.0-openjdk.x86_64 1:1.7.0.161-2.6.12.0.75.amzn1
  kernel-tools.x86_64 0:4.9.77-31.58.amzn1        krb5-libs.x86_64 0:1.15.1-8.43.amzn1       libcurl.x86_64 0:7.53.1-13.80.amzn1            nss.x86_64 0:3.28.4-12.80.amzn1                  nss-softokn.x86_64 0:3.28.3-8.41.amzn1
  nss-softokn-freebl.x86_64 0:3.28.3-8.41.amzn1   nss-sysinit.x86_64 0:3.28.4-12.80.amzn1    nss-tools.x86_64 0:3.28.4-12.80.amzn1          nss-util.x86_64 0:3.28.4-3.53.amzn1              openssl.x86_64 1:1.0.2k-8.106.amzn1
  python27.x86_64 0:2.7.12-2.121.amzn1            python27-boto.noarch 0:2.48.0-1.2.amzn1    python27-botocore.noarch 0:1.8.13-1.66.amzn1   python27-devel.x86_64 0:2.7.12-2.121.amzn1       python27-libs.x86_64 0:2.7.12-2.121.amzn1
  ruby20.x86_64 0:2.0.0.648-1.30.amzn1            ruby20-irb.noarch 0:2.0.0.648-1.30.amzn1   ruby20-libs.x86_64 0:2.0.0.648-1.30.amzn1      rubygem20-bigdecimal.x86_64 0:1.2.0-1.30.amzn1   rubygem20-psych.x86_64 0:2.0.0-1.30.amzn1
  rubygems20.noarch 0:2.0.14.1-1.30.amzn1         system-release.noarch 0:2017.09-0.1        wget.x86_64 0:1.18-3.28.amzn1

Complete!

再起動してアップデートを反映させます。


$ ssh hogehost
Last login: Sat Jan 20 02:21:06 2018

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2017.09-release-notes/

$ uname -srv
Linux 4.9.77-31.58.amzn1.x86_64 #1 SMP Thu Jan 18 22:15:23 UTC 2018

カーネルもCPU脆弱性の対応がされた最新のバージョンになりました。

まとめ

今回2016年のAmazon LinuxのKernelを最新版にアップデートにするには以下のような流れです。

  • yum.conf更新(リリースバージョンを最新にする)
  • yum update(1回目。2016 → 2017にコミットされたバージョンをあげる)
  • yum update(2回目。2017 → 最新の2018にコミットされたバージョンをあげる。)

何回 yum updateが必要なのかは、管理しているインスタンスのバージョンによりますが、
OSのバージョンアップは早いうちからやっていた方が明らかに楽ですし、
パッケージを全てアップデートする場合は既存のサービスに影響を与える可能性もあります。

改めてセキュリティ対策は、コツコツアップデートしていかなければという学びを得ました。

また、sshの情報にしっかり目を通すことで、どうアップデートすべきかわかるので最新のOSに保ちつつ管理していきましょう。

続きを読む

AWS CodeDeploy logs that you should watch.

We have a web service with AWS, located in like below environment. (This time in case of using AmazonLinux) WebServer: – Production: – ALB * 1 – EC2 * 2 – Dev: – EC2 * 1 DB: – Production: Aurora * 1 – Dev: Aurora * 1. Our source code is managed by github organization account. And we’re going to … 続きを読む

sagemakerで簡易電力予測ページを作ってみた

前回エンドポイント作るまではできたけどそこからどうやってそのエンドポイントを使ったらいいかわからず1日うーーーんってやってたらできたので記事にしてみました。

できたもの

FireShot Capture 36 - 消費電力予測 - http___localhost_8000_.png
作ったものはすごくシンプルでこのフォームに好きな数字を入れて送信ボタンを押下したら

電力予測結果.png
こんな感じで予測消費電力が返って来るっていうもの

ハマったとこ

このページ自体はflaskを使っていて
フォーム作ったりフォームの内容をPOSTして〜ってところは
色々調べていたらできたのですがハマったのは
どうやったら予測消費電力が返って来るか、というところ
読解力が乏しいので色んな記事やら読んでも理解できず……
AWSのブログにlambdaにこうやったら使えるよっていうのが
書いてあったのでそれを使ってみることに…

import boto3

sagemaker = boto3.client('sagemaker-runtime')
result = sagemaker.invoke_endpoint(
      EndpointName='test',
      Body=pre_data
    )

でもデータの形をどうすればいいかわからず(モデル作成はcsvファイルでやってました)
配列を渡したり適当にオブジェクトにしたりcsvに変換してs3に落としてみたり….色々やっていたのですがずっとエラーが出っ放しでした。
特に出てたエラーが

Received client error (400) from model with message "unable to evaluate payload provided". See https://us-east-1.console.aws.amazon.com/cloudwatch/~~~ (Service: AmazonSageMakerRuntime; Status Code: 424; Error Code: ModelError; Request ID: null)

全然意味がわかんないしCloudWatch見ても訳がわからん状態でした。
色々調べてたらsagemaker.invoke_endpointの引数にContentType='text/csv'って入れたらいいよってここに書いてあったので入れたけど結局データの形をどうしたらいいかわからずまたエラー

Invalid type for parameter Body, value: [12, 0, 12, 12.0, 0], type: <class 'list'>, valid types: <class 'bytes'>, <class 'bytearray'>, file-like object

エラーを読んでみるとfile-like objectにしろって書いてある…
でもfile-like objectが何かわからないで調べていたら

ファイルオブジェクトには実際には 3 種類あります: 生の バイナリーファイル、バッファされた バイナリーファイル、そして テキストファイル です。

ってここにありました。
テキストファイルってことは、モデル作るときcsvだったしカンマ区切りか!って思ってカンマ区切りでデータを送ったら

from flask import Flask, render_template, request, redirect
import json
import boto3

app = Flask(__name__)
@app.route('/')
def index():
  return render_template('/sagemaker.html')

@app.route('/predict', methods=['POST'])
def predict():
  if request.method == 'POST':
    month = request.form['month']
    week = request.form['week']
    time = request.form['time']
    temp = request.form['temp']
    weather = request.form['weather']
    pre_data_str = month + "," + week + "," + time + "," + temp + "," + weather
    sagemaker = boto3.client('sagemaker-runtime', region_name='us-east-1')
    result = sagemaker.invoke_endpoint(
      ContentType='text/csv',
      EndpointName='test',
      Body=pre_data_str
    )
    result_body = json.load(result['Body'])
    pre = int(float(result_body['predictions'][0]['score']))
    return render_template('/predict.html', predict=pre)
  else:
    return redirect('/')

if __name__ == '__main__':
  app.run(port=8000, debug=True)

いけました!
わからんすぎて本当に投げそうになったけど最後まで頑張ってよかったです。

これを次はlambdaで使ってみて、その後カスタムでやってみようと思います。

続きを読む