🍰
Elastic Beanstalk 環境で CakePHP のログを CloudWatch Logs で収集する
はじめに
統合された CloudWatch エージェントを使ったサンプルが少なかったので備忘録。
戦略
postdeploy
フックを使用して既存の設定を上書き、エージェントを再起動させる力技。
.platform/hooks/postdeploy
├── 000-cakephp.sh
├── 001-fix_cloudwatch_agent_conf.php
└── 002-restart_cloudwatch_agent.sh
CakePHP の対応
- デプロイ対象のディレクトリ外に logs, tmp 用のディレクトリを作成し、デフォルトのパスにシンボリックリンクを貼る。
- キャッシュのクリア
000-cakephp.sh
#!/bin/bash
set -eu
LOGS_DIR="/var/app/cake/logs"
LOGS_LINK_DIR="/var/app/current/logs"
TMP_DIR="/var/app/cake/tmp"
TMP_LINK_DIR="/var/app/current/tmp"
# logs
if [ ! -d "${LOGS_DIR}" ]; then
mkdir -p "${LOGS_DIR}"
chown -R webapp:webapp "${LOGS_DIR}"
chmod -R 0777 "${LOGS_DIR}"
logger -t eb-cake "mkdir ${LOGS_DIR}"
fi
if [ -d "${LOGS_LINK_DIR}" ] && [ ! -L "${LOGS_LINK_DIR}" ]; then
rm -rf "${LOGS_LINK_DIR}"
logger -t eb-cake "rm ${LOGS_LINK_DIR}"
fi
ln -s "$LOGS_DIR" "$LOGS_LINK_DIR"
logger -t eb-cake "ln ${LOGS_DIR} ${LOGS_LINK_DIR}"
# tmp
if [ ! -d "${TMP_DIR}" ]; then
mkdir -p "${TMP_DIR}/sessions"
mkdir -p "${TMP_DIR}/cache"
mkdir -p "${TMP_DIR}/cache/models"
mkdir -p "${TMP_DIR}/cache/persistent"
mkdir -p "${TMP_DIR}/cache/views"
chown -R webapp:webapp "${TMP_DIR}"
chmod -R 0777 "${TMP_DIR}"
logger -t eb-cake "mkdir ${TMP_DIR}"
fi
if [ -d "${TMP_LINK_DIR}" ] && [ ! -L "${TMP_LINK_DIR}" ]; then
rm -rf "${TMP_LINK_DIR}"
logger -t eb-cake "rm ${TMP_LINK_DIR}"
fi
ln -s "$TMP_DIR" "$TMP_LINK_DIR"
logger -t eb-cake "ln ${TMP_DIR} ${TMP_LINK_DIR}"
# cache
/var/app/current/bin/cake cache clear_all
logger -t eb-cake "clear cache"
既存の設定を上書き
以下の理由から、既存の設定は上書きした方が良さげ。
-
timestamp_format
が設定されてないので CloudWatch Logs のタイムスタンプと大きくズレる可能性がある。 -
multi_line_start_pattern
が未設定のまま、複数行のログが流れて悲しい思いをする。
eb-engine.log とか。
httpd(ログのフォーマットはデフォルトのまま)を使用する想定。
001-fix_cloudwatch_agent_conf.php
#!/usr/bin/env php
<?php
define('TARGET', '/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.d/file_beanstalk.json');
define('HAS_FIXED', '/root/.fixed_cloudwatch_agent_conf');
openlog('eb-cw-agent-conf', LOG_PID, LOG_USER);
if (file_exists(HAS_FIXED)) {
syslog(LOG_INFO, 'already fixed config');
exit;
}
$list = [
[
'file_path' => '/var/log/eb-engine.log',
'log_group_name' => '/aws/elasticbeanstalk/example-env/var/log/eb-engine.log',
'log_stream_name' => '{instance_id}',
'timestamp_format' => '%Y/%m/%d %H:%M:%S.%f',
'multi_line_start_pattern' => '{timestamp_format}',
],
[
'file_path' => '/var/log/eb-hooks.log',
'log_group_name' => '/aws/elasticbeanstalk/example-env/var/log/eb-hooks.log',
'log_stream_name' => '{instance_id}',
'timestamp_format' => '%Y/%m/%d %H:%M:%S.%f',
'multi_line_start_pattern' => '{timestamp_format}',
],
[
'file_path' => '/var/log/httpd/access_log',
'log_group_name' => '/aws/elasticbeanstalk/example-env/var/log/httpd/access_log',
'log_stream_name' => '{instance_id}',
'timestamp_format' => '[%d/%b/%Y:%H:%M:%S %z]',
],
[
'file_path' => '/var/log/httpd/error_log',
'log_group_name' => '/aws/elasticbeanstalk/example-env/var/log/httpd/error_log',
'log_stream_name' => '{instance_id}',
'timestamp_format' => '[%a %b %d %H:%M:%S.%f %Y]',
],
[
'file_path' => '/var/app/cake/logs/error.log',
'log_group_name' => '/aws/elasticbeanstalk/example-env/var/app/cake/error_log',
'log_stream_name' => '{instance_id}',
'timestamp_format' => '%Y-%m-%d %H:%M:%S',
'multi_line_start_pattern' => '{timestamp_format}',
],
];
$tmp = [
'logs' => [
'logs_collected' => [
'files' => [
'collect_list' => $list,
],
],
],
];
$json = json_encode($tmp, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
file_put_contents(TARGET, $json, LOCK_EX);
syslog(LOG_INFO, 'fixed config');
エージェントの再起動
002-restart_cloudwatch_agent.sh
#!/bin/bash
set -eu
HAS_FIXED="/root/.fixed_cloudwatch_agent_conf"
if [ -e "${HAS_FIXED}" ]; then
logger -t eb-cw-agent "already fixed config"
exit 0
fi
systemctl restart amazon-cloudwatch-agent
logger -t eb-cw-agent "restart agent"
touch "${HAS_FIXED}"
logger -t eb-cw-agent "touch fixed config"
注意点
削除するとデプロイに失敗するので、以下のグループは CloudWatch ロググループから削除しない。
- /xxxx/xxx/eb-engine.log
- /xxxx/xxx/eb-hooks.log
- /xxxx/xxx/httpd/access_log
- /xxxx/xxx/httpd/error_log
- /xxxx/xxx/nginx/access.log
- /xxxx/xxx/nginx/error.log
まとめ
相変わらずの力技なので、もっとスマートな方法があるはず。。。
Discussion