ターミナルから直感的にCloudWatch Logsを検索できるawslogsコマンドの紹介

CloudWatch

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、中山です。

先日AWS Summit Tokyo 2016に参加してきました。セッションを聴講している際にスピーカーの方が面白そうなツールを紹介されていました。awslogsというPython製のツールです。これはAmazon CloudWatch Logsをターミナルから直感的に検索するためのツールです。早速使用してみたのでレポートします。

検証環境

awslogsコマンドを利用するためにCloudWatch Logsの設定が必要です。検証環境構築用のコードをGitHubに上げておきました。以下のコマンドで実行可能です。

$ git clone https://github.com/knakayama/awslogs-demo.git
$ cd awslogs-demo
$ ssh-keygen -f site_key -N ''
$ terraform apply

このコードでは2つのEC2インスタンス起動後、awslogsエージェント(awslogsコマンドではない)が起動しNginxのログ、「/var/log/nginx/access.log」をCloudWatch Logsに送ります。ロググループ名は「/var/log/nginx/access_log」で、ストリーム名が「<instance-id>_nginx_access_log」です。また、cronで1分毎にlocalhostにアクセスさせているので、ログが随時書き込まれていきます。

こちらのコードを利用すれば検証環境が構築可能です。もちろん既存の環境がある場合はこのコードを利用する必要はありません。が、説明を簡易化させるために以下の内容はこの検証環境を前提として進めます。

では、環境も整ったところで早速使ってみましょう。

インストール方法

READMEに詳しいですがpipで簡単に導入可能です。

$ pip install awslogs

OS X El Capitanの場合は以下のように --ignore-installed six を指定してsixパッケージをインストールせずに導入する必要があります。理由はこちらのコメントに詳しいですが、どうやらEl Capitanからはsixパッケージの1.4.1がデフォルトで入っているため、awslogsが依存しているbotocoreがさらに依存しているpython-dateutilがsixパッケージ1.5以上を要求するので、pip経由でインストールさせるとうまく動作しない場合があるようです。

$ pip install awslogs --ignore-installed six

サブコマンド

awslogsには以下の3つのサブコマンドがあります。

サブコマンド 用途
groups CloudWatch Logsのロググループ名を表示
streams CloudWatch Logsのストリーム名を表示
get CloudWatch Logsのストリームに発生したイベントを表示

以下ではそれぞれのサブコマンドについて解説します。

groups

groups サブコマンドはCloudWatch Logsのロググループ名を標準出力に表示します。書式は以下の通りです。

awslogs groups [-h]
               [--aws-access-key-id AWS_ACCESS_KEY_ID]
               [--aws-secret-access-key AWS_SECRET_ACCESS_KEY]
               [--aws-session-token AWS_SESSION_TOKEN]
               [--profile AWS_PROFILE]
               [--aws-region AWS_REGION]

お馴染みのクレデンシャル系オプションを指定できるようですが、このサブコマンド特有のオプションはないようです。早速使ってみましょう。

$ awslogs groups
<snip>
/var/log/nginx/access_log

「/var/log/nginx/access_log」というロググループ名が表示されました。 groups サブコマンドにはこれ以外の機能がなく、非常にシンプルなものになっています。

streams

streams サブコマンドはCloudWatch Logsのストリーム名を標準出力に表示します。書式は以下の通りです。

awslogs streams [-h]
                [--aws-access-key-id AWS_ACCESS_KEY_ID]
                [--aws-secret-access-key AWS_SECRET_ACCESS_KEY]
                [--aws-session-token AWS_SESSION_TOKEN]
                [--profile AWS_PROFILE]
                [--aws-region AWS_REGION]
                [-s START] [-e END]
                log_group_name

オプションに -s/--start-e/--end が加わっています。また、引数に「log_group_name」を指定する必要があります。早速使ってみましょう。

$ awslogs streams /var/log/nginx/access_log
i-904d2d0f_nginx_access_log
i-e54c2c7a_nginx_access_log

設定したストリーム名が表示されました。 groups サブコマンド同様こちらも非常にシンプルな機能になっています。 -s/--start-e/--end オションの用途は、それぞれ -s/--start 以降にイベントが発生したストリーム、 -e/--end 以前にイベントが発生したストリームに絞って表示してくれます。オプションの指定方法は他のサブコマンドと同様なので get サブコマンドの方で説明します。

get

get サブコマンドはCloudWatch Logsのストリームに発生したイベントを標準出力に表示させます。この機能がawslogsコマンドの要です。書式は以下の通りです。

awslogs get [-h]
            [--aws-access-key-id AWS_ACCESS_KEY_ID]
            [--aws-secret-access-key AWS_SECRET_ACCESS_KEY]
            [--aws-session-token AWS_SESSION_TOKEN]
            [--profile AWS_PROFILE]
            [--aws-region AWS_REGION]
            [-f FILTER_PATTERN] [-w] [-G]
            [-S] [--timestamp]
            [--ingestion-time] [-s START]
            [-e END] [--no-color]
            [log_group_name]
            [log_stream_name]

このサブコマンドにはさまざまなオプションを指定できるようですね。それぞれ見ていきましょう。

getサブコマンドの基本

まずは基本的なコマンドの使用方法を解説します。ロググループ名とストリーム名のみ指定する形式がそれになります。

$ awslogs get /var/log/nginx/access_log i-904d2d0f_nginx_access_log
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:25:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:26:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:27:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

いい感じにログが表示されていますね。お伝えできなくて恐縮ですがしっかりと色付きで表示されています。標準出力に表示してくれるということは当然 grep などのお馴染みのツールで特定のログを抜き出せます。

$ awslogs get /var/log/nginx/access_log i-904d2d0f_nginx_access_log | grep -F '02:27:01'
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:27:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

ちなみにストリーム名は省略可能です。その場合ロググループに含まれる全てのストリームが表示されます(ALLまたは .* を指定した場合と同じ)。また、ストリーム名には正規表現が指定できます。

$ awslogs get /var/log/nginx/access_log 'i-\d{3}d'
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:11:17:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:11:18:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:11:19:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:11:20:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:11:21:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

続いてオプションについて解説します。

-w/--watch オプション

このオプションはログを表示し続けます。いわゆる tail -f ですね。

$ awslogs get /var/log/nginx/access_log --watch
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:25:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:25:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
# ここでプロンプトが返らずログを表示し続ける

-G/--no-group オプション

ロググループ名を省略して表示させます。

$ awslogs get /var/log/nginx/access_log --no-group
i-e54c2c7a_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:27:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:27:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-e54c2c7a_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:28:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:28:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-e54c2c7a_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:29:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:29:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-e54c2c7a_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:30:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:30:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-e54c2c7a_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:31:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
i-904d2d0f_nginx_access_log 127.0.0.1 - - [04/Jun/2016:02:31:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

-S/--no-stream オプション

ストリーム名を省略して表示させます。

$ awslogs get /var/log/nginx/access_log --no-stream
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:27:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:27:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:28:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:28:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:29:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:29:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:30:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:30:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:31:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log 127.0.0.1 - - [04/Jun/2016:02:31:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

--timestamp オプション

ストリームにイベントが発生した時間を表示します。

$ awslogs get /var/log/nginx/access_log --timestamp
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:28:01.858Z 127.0.0.1 - - [04/Jun/2016:02:28:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:28:02.339Z 127.0.0.1 - - [04/Jun/2016:02:28:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:29:01.878Z 127.0.0.1 - - [04/Jun/2016:02:29:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:29:02.358Z 127.0.0.1 - - [04/Jun/2016:02:29:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:30:01.896Z 127.0.0.1 - - [04/Jun/2016:02:30:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:30:02.376Z 127.0.0.1 - - [04/Jun/2016:02:30:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:31:01.915Z 127.0.0.1 - - [04/Jun/2016:02:31:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:31:02.395Z 127.0.0.1 - - [04/Jun/2016:02:31:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:32:01.414Z 127.0.0.1 - - [04/Jun/2016:02:32:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:32:01.935Z 127.0.0.1 - - [04/Jun/2016:02:32:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

--ingestion-time オプション

ストリームにイベントが発生してingestされた時間を表示します。

$ awslogs get /var/log/nginx/access_log --ingestion-time
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:33:07.225Z 127.0.0.1 - - [04/Jun/2016:02:33:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:33:07.927Z 127.0.0.1 - - [04/Jun/2016:02:33:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:34:07.308Z 127.0.0.1 - - [04/Jun/2016:02:34:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:34:07.026Z 127.0.0.1 - - [04/Jun/2016:02:34:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:35:07.388Z 127.0.0.1 - - [04/Jun/2016:02:35:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:35:07.121Z 127.0.0.1 - - [04/Jun/2016:02:35:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:36:07.467Z 127.0.0.1 - - [04/Jun/2016:02:36:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:36:07.211Z 127.0.0.1 - - [04/Jun/2016:02:36:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-904d2d0f_nginx_access_log 2016-06-03T17:37:06.547Z 127.0.0.1 - - [04/Jun/2016:02:37:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 2016-06-03T17:37:07.290Z 127.0.0.1 - - [04/Jun/2016:02:37:01 +0900] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"

-s/--start START オプション

ストリームにイベントが発生した時間以降のログを表示させます。日付処理にはPythonのdateutilモジュールが使われています。以下ではREADMEを参考にしてこのオプションの使い方を解説します。

  • 分毎に指定する場合( Xm / X minute / X minutes は同じ動作)
# 2分前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2m'
# 1分前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='1 minute'
# 5分前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='5 minutes'
  • 時間毎に指定する( Xh / X hour / X hours は同じ動作)
# 2時間前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2h'
# 1時間前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='1 hour'
# 5時間前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='5 hours'
  • 日毎に指定する( Xd / X day / X days は同じ動作)
# 2日前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2d'
# 1日前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='1 day'
# 5日前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='5 days'
  • 週毎に指定する( Xw / X week / X weeks は同じ)
# 2週間前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2w'
# 1週間前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='1 week'
# 5週間前以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='5 weeks'
  • より詳細な指定をする
# 2016/06/04 03:00以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='4/6/2016 03:00'
# 2016/06/04以降のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='4/6/2016'
# UTCで2003/10/11(土) 17:13:46以降のイベント(2016/06/04時点dateutil単体ではパースできているようだが、エラーが表示される)
$ awslogs get /var/log/nginx/access_log ALL --start='Sat Oct 11 17:13:46 UTC 2003'

-e/--end END オプション

ストリームにイベントが発生した以前のログを表示させます。このオプションの指定方法は -s/--start と同じです。以下ではこの2つのオションを組み合わせた例を紹介します。

# 2分前以降かつ1分前以前のイベント
$ awslogs get /var/log/nginx/access_log --start='2m' --end='1m'
# 2時間前以降かつ1時間前以前のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2h' --end='1h'

--no-color オプション

その名の通り色を表示させません。

-f FILTER_PATTERN オプション

CloudWatch Logsのフィルターパターンを指定してより詳細なログの抽出を実施できます。

  • 「Nmap」という文字列が含まれるイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2h' --filter-pattern='Nmap'
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 45.33.30.46 - - [04/Jun/2016:08:50:02 +0900] "GET / HTTP/1.1" 200 3770 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 45.33.30.46 - - [04/Jun/2016:08:50:02 +0900] "OPTIONS / HTTP/1.1" 405 172 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 45.33.30.46 - - [04/Jun/2016:08:50:02 +0900] "GET /robots.txt HTTP/1.1" 404 3696 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)" "-"
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 45.33.30.46 - - [04/Jun/2016:08:50:02 +0900] "GET /favicon.ico HTTP/1.1" 404 3696 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)" "-"
  • HTTPステータスコードが405のイベント
$ awslogs get /var/log/nginx/access_log ALL --start='2h' --filter-pattern='[ip, user, username, timestamp, request, status_code = 405, ...]'
/var/log/nginx/access_log i-e54c2c7a_nginx_access_log 45.33.30.46 - - [04/Jun/2016:08:50:02 +0900] "OPTIONS / HTTP/1.1" 405 172 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)" "-"

まとめ

いかがだったでしょうか。

イベント自体はawscliでも見れますが、より直感的な操作かつ慣れ親しんだUnix系ツールを利用できる点がいいなと思いました。今後も使っていきたいツールの一つになりそうです。

本エントリがみなさんの参考になれば幸いです。

AWS Cloud Roadshow 2017 福岡