Bonjour. En tant que gestionnaire d'infrastructure chez Mikatus Co., Ltd., je suis en charge de la construction, de l'exploitation et de la maintenance de l'infrastructure, etc. centrée sur AWS. Cette fois, j'écrirai sur la notification à Chatwork des requêtes lentes MySQL.
Notre système utilise Amazon RDS pour MySQL, et nous avons utilisé un outil de surveillance pour surveiller l'occurrence des requêtes lentes, mais Chatwork afin que nous puissions apporter des améliorations continues en notifiant en temps réel. J'ai essayé de notifier. De plus, l'autre jour la version préliminaire de l'AWS CLI v2 a été annoncée, donc c'est un gros problème, donc utiliser CLI v2 AWS J'ai essayé de créer une ressource.
Cet article explique comment utiliser les paramètres AWS Lambda et les paramètres Amazon CloudWatch Logs à l'aide de l'AWS CLI v2. Il ne couvre pas les étapes détaillées de la fonction d'exportation de journaux Amazon RDS et des paramètres de l'API Chatwork.
C'est ce dont Chatwork sera enfin informé. Bot publiera le contenu de la requête lente sur le chat de groupe auquel participent les parties concernées. Fondamentalement, la sortie de contenu vers CloudWatch Logs est sortie telle quelle. Étant donné que le journal des requêtes lentes est sorti en UTC uniquement pour l'heure, il est converti en JST pour notification.
La sortie de RDS vers CloudWatch Logs est la fonction d'exportation de journaux de RDS (https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.Concepts.MySQL.html#USER_LogAccess.MySQLDB.PublishtoCloudWatchLogs ) Est utilisé. CloudWatch Logs utilise des filtres d'abonnement (https://docs.aws.amazon.com/en_jp/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#LambdaFunctionExample) pour envoyer aux fonctions Lambda et écrits en Python. La fonction analyse le message du journal et notifie Chatwork. Le long_query_time du groupe de paramètres RDS peut être utilisé pour contrôler la sortie de requête lente vers CloudWatch Logs, mais le paramètre RDS est relativement lâche et un seuil est défini du côté Lambda afin qu'il puisse être contrôlé. (Cette fois, j'ai défini le RDS long_query_time sur "5" secondes et le seuil Lambda sur "10" secondes.)
Je décrirai le contenu de l'ensemble.
Installez l'AWS CLI v2 sur votre mac. Cliquez ici pour la procédure d'installation Veuillez noter qu'il s'agit toujours d'une version préliminaire, veuillez donc ne pas l'utiliser dans un environnement de production.
L'AWS CLI version 2 est fournie pour l'aperçu et l'évaluation des tests. Pour le moment, nous vous recommandons de ne pas l'utiliser dans un environnement de production.
La version suivante a été installée.
$ aws2 --version
aws-cli/2.0.0dev2 Python/3.7.4 Darwin/17.7.0 botocore/2.0.0dev1
Comme impression, CLI v1 a du temps et des efforts au moment de l'introduction en raison de la dépendance de la version de Python, etc. CLI v2 a rendu l'installation beaucoup plus facile sans Python.
--Nom de rôle
$ IAM_ROLE_POLICY_DOC="iam-role-policy.json"
#Définir Lambda comme une entité de confiance
$ cat <<EOF > ${IAM_ROLE_POLICY_DOC}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
$ IAM_ROLE_NAME="post-slowquery-to-chatwork-LambdaRole"
$ IAM_POLICY_ARN="arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
#Créer un rôle IAM
$ aws2 iam create-role \
--role-name ${IAM_ROLE_NAME} \
--assume-role-policy-document file://./${IAM_ROLE_POLICY_DOC}
#Obtenez l'ARN du rôle IAM que vous avez créé
$ IAM_ROLE_ARN=`aws2 iam get-role \
--role-name ${IAM_ROLE_NAME} \
--query 'Role.Arn' \
--output text`
#Attacher AWSLambdaBasicExecutionRole au rôle IAM
$ aws2 iam attach-role-policy \
--role-name ${IAM_ROLE_NAME} \
--policy-arn ${IAM_POLICY_ARN}
Le runtime utilise python3.7.
lambda_function.py
import json
import base64
import gzip
import re
import os
import datetime
import urllib
import urllib.request
LONG_QUERY_TIME = int(os.environ['LONG_QUERY_TIME'])
chatwork_endpoint = "https://api.chatwork.com/v2"
chatwork_apikey = os.environ['chatwork_apikey']
chatwork_roomid = os.environ['chatwork_roomid']
path = "/rooms/{0}/messages".format(chatwork_roomid)
def lambda_handler(event, context):
print(json.dumps(event))
#Extrayez le contenu car il est encodé en Base64 et compressé au format gzip.
log_events = json.loads(gzip.decompress(base64.b64decode(event['awslogs']['data'])))
db_name = log_events['logStream']
message = log_events['logEvents'][0]['message']
#Extraire l'heure de la requête du journal
query_time = re.search(r'Query_time: ([0-9]+.[0-9]+)', message)
#Lorsqu'il est supérieur au temps spécifié par la variable d'environnement(10 secondes ou plus cette fois)Notifier
if LONG_QUERY_TIME < float(query_time.group(1)):
timestamp = re.search(r'timestamp=([0-9]+);', message)
#Convertir l'horodatage en heure JST
date = datetime.datetime.fromtimestamp(int(timestamp.group(1))) + datetime.timedelta(hours=9)
log_message = re.sub(r'# Time:.*\n', '# Time: %s(JST)\n' % str(date), message)
post_to_chatwork({'body': '[info][title]%s[/title]%s[/info]' % (db_name, log_message)})
def post_to_chatwork(data=None):
try:
if data != None:
data = urllib.parse.urlencode(data).encode('utf-8')
headers = {"X-ChatWorkToken": chatwork_apikey}
req = urllib.request.Request(chatwork_endpoint + path, data=data, headers=headers)
with urllib.request.urlopen(req) as res:
print(res.read().decode("utf-8"))
return
except urllib.error.HTTPError as e:
print('Error code: %s' % (e.code))
sys.exit('post_to_chatwork Error')
$ LAMBDA_FUNCTION_NAME="post-slowquery-to-chatwork"
$ LAMBDA_RUNTIME="python3.7"
$ LAMBDA_ZIP_FILE="${LAMBDA_FUNCTION_NAME}.zip"
$ LAMBDA_HANDLER="lambda_function.lambda_handler"
$ LAMBDA_ENV="{\
LONG_QUERY_TIME=10,\
chatwork_apikey=XXXXX,\
chatwork_roomid=XXXXX}"
#Zip le code
$ zip ${LAMBDA_ZIP_FILE} lambda_function.py
#Créer une fonction Lambda
$ aws2 lambda create-function \
--function-name ${LAMBDA_FUNCTION_NAME} \
--runtime ${LAMBDA_RUNTIME} \
--zip-file fileb://${LAMBDA_ZIP_FILE} \
--handler ${LAMBDA_HANDLER} \
--environment Variables=${LAMBDA_ENV} \
--role ${IAM_ROLE_ARN}
$ LOG_GROUP_NAME="/aws/rds/instance/[rdsinstance]/slowquery"
$ LOG_FILTER_NAME="LambdaStream_post-slowquery-to-chatwork"
$ LAMBDA_ARN=`aws2 lambda get-function \
--function-name ${LAMBDA_FUNCTION_NAME} \
--query 'Configuration.FunctionArn' \
--output text`
$ LOG_ACTION="lambda:InvokeFunction"
$ LOG_PRINCIPAL="logs.ap-northeast-1.amazonaws.com"
$ SOURCE_ACCOUNT=`aws sts get-caller-identity \
--query 'Account' \
--output text`
$ SOURCE_ARN="arn:aws:logs:ap-northeast-1:${SOURCE_ACCOUNT}:log-group:${LOG_GROUP_NAME}:*"
#Donner l'accès à CloudWatch Logs pour exécuter des fonctions
$ aws2 lambda add-permission \
--function-name ${LAMBDA_FUNCTION_NAME} \
--statement-id ${LAMBDA_FUNCTION_NAME} \
--action ${LOG_ACTION} \
--principal ${LOG_PRINCIPAL} \
--source-arn ${SOURCE_ARN} \
--source-account ${SOURCE_ACCOUNT}
#Créez un filtre d'abonnement. Le modèle de filtre est vide("")À
$ aws2 logs put-subscription-filter \
--log-group-name ${LOG_GROUP_NAME} \
--filter-name ${LOG_FILTER_NAME} \
--filter-pattern "" \
--destination-arn ${LAMBDA_ARN}
Ceci termine les réglages.
Cette fois, j'ai utilisé RDS, Lambda et CloudWatch Logs pour notifier les requêtes lentes. Dans le passé, lorsqu'une requête lente se produisait, il était un peu pénible d'aller dans CloudWatch Logs pour voir le journal, il semble donc que la douleur sera atténuée en informant Chatwork de cela. À l'avenir, j'aimerais utiliser pleinement les outils d'analyse des journaux, etc. pour une visualisation plus détaillée, mais j'essaierai de l'implémenter à une autre occasion. En ce qui concerne AWS CLI v2, je n'ai pas profité de beaucoup des avantages liés à son utilisation cette fois, mais je vais l'utiliser activement.