こんにちは!!こんにちは!!
インフラエンジニアのyamamotoです。
最近、しいたけ栽培セット にハマっています。モリモリしいたけが生えてくるのでとっても面白いです!
生のしいたけというのも普段なかなかお目にかかれないので、秋の味覚を楽しめてイイですよ!
しいたk…ログがちゃんと出力されているか?
当社のあるプロダクトではAWSを使用していますが、ログをAthenaで読むために、S3に日毎のフォルダーに分けて出力するようにしています。
ログの出力のしかたについては過去の記事をご参照ください。
tech.actindi.net
ログって使わないときはつい放置しがちになりますよねー。いつの間にか出力が止まっていたりしても気づかなかったり。
そこで、ログが毎日ちゃんと出力されているか監視するために、スクリプトを書いてLambdaで監視するようにしてみました。
コードの説明
ざっくり、コードはこんな感じになりました。
const { S3_BUCKET_NAME, S3_CHECK_PATTERN1, S3_CHECK_PATTERN2, S3_CHECK_PATTERN3, SNS_TOPICARN, SNS_REGION, SNS_MESSAGE_TITLE, SLACK_URL, SLACK_CHANNEL, } = process.env; const AWS = require('aws-sdk'); const s3 = new AWS.S3(); const sns = new AWS.SNS({ apiVersion: '2010-03-31', region: SNS_REGION, }); const checkPattern = [S3_CHECK_PATTERN1, S3_CHECK_PATTERN2, S3_CHECK_PATTERN3]; function formatDate(date, format) { let ret = format; if (!ret) ret = 'YYYY-MM-DD'; ret = ret.replace(/YYYY/g, date.getFullYear()); ret = ret.replace(/MM/g, `0${(date.getMonth() + 1)}`.slice(-2)); ret = ret.replace(/DD/g, `0${date.getDate()}`.slice(-2)); return ret; } async function checkS3Object(bucket, pat) { const params = { Prefix: formatDate(new Date(), pat), Bucket: bucket, MaxKeys: 1, StartAfter: formatDate(new Date(), pat), }; console.info(`Checking S3 log directory ${bucket}/${params.Prefix}`); const res = await s3.listObjectsV2(params).promise(); if (res.KeyCount === 0) { console.info('Data listobj: ', res); return 1; } return 0; } async function checkS3Status(bucket, pattern) { let ret = 0; let res = 0; for (let i = 0; i < pattern.length; i += 1) { if (pattern[i]) { res = await checkS3Object(bucket, pattern[i]); if (res === 1) { ret = `${bucket}/${pattern[i]}`; break; } } } return ret; } async function publishSNS(arn, title, message) { const params = { Message: message, Subject: title, TopicArn: arn, }; try { await sns.publish(params).promise(); } catch (err) { console.error('Error publishing: ', err); } } async function publishSlack(slackurl, slackchannel, message) { const { IncomingWebhook } = require('@slack/webhook'); const slackwebhook = new IncomingWebhook(slackurl, { channel: slackchannel, }); try { await slackwebhook.send(message); } catch (err) { console.error('Error Slack: ', err); } } exports.handler = async () => { const ret = await checkS3Status(S3_BUCKET_NAME, checkPattern); if (ret !== 0) { const msg = `Error! S3 log directory ${ret} is not known!`; await publishSNS(SNS_TOPICARN, SNS_MESSAGE_TITLE, msg); if (SLACK_URL !== '') { await publishSlack(SLACK_URL, SLACK_CHANNEL, msg); } console.error(msg); } };
フォルダー名の形式を受け取って、それにマッチしたものが無いとSNS→メールと、Slackで通知するようになっています。
当社の例ではフォルダー名は「/year={年}/month={月}/day={日}/ 」なので、日付をフォーマットに当て込む関数を簡易的に使っています。
また、AWSのオブジェクトは非同期で扱うのでasync・awaitを使って受け渡しています。
意外と迷ったのが、フォルダーの存在有無をどう確認するか、というところです。
S3のフォルダーの有無を確認するには、s3.listObjectV2()
メソッドを使用しています。
あと、SlackのWebhookを使った通知については、下記を参照しました。
https://slack.dev/node-slack-sdk/webhook
Lambdaに仕込む
これを、Lambdaに仕込みます。
トリガーとして CloudWatch Event を使い、毎日特定の時間に実行するようにします。日毎の場合、日付が変わってある程度時間が過ぎてからにしています。
リソースについては、監視するS3オブジェクトに対する s3:ListBucket
権限と、SNSの sns:Publish
権限が追加で必要になります。
あと、コードの冒頭にある環境変数を設定する必要があります。
さいごに
アクトインディでは、しいt…Webエンジニアを募集しています! actindi.net