Monitor User Activity with Amazon CloudWatch and Lambda

We will send logs from EC2 (Moodle) to Amazon CloudWatch Logs.

  1. Install CloudWatch Agent on EC2
  • Run sudo apt update
  • Run this code to download CloudWatch Agent from AWS S3:
    wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
    
  • Run sudo dpkg -i amazon-cloudwatch-agent.deb to install the downloaded .deb file. Clean
  • Run sudo mkdir -p /opt/aws/amazon-cloudwatch-agent/etc to create the configuration directory.
  • Then run sudo nano /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json to create the CloudWatch Agent configuration file.
  • Copy the code below into the amazon-cloudwatch-agent.json file
    {
      "logs": {
        "logs_collected": {
          "files": {
            "collect_list": [
              {
                "file_path": "/var/log/syslog",
                "log_group_name": "MoodleSyslog",
                "log_stream_name": "{instance_id}-syslog"
              },
              {
                "file_path": "/var/log/apache2/access.log",
                "log_group_name": "MoodleAccessLog",
                "log_stream_name": "{instance_id}-access"
              },
              {
                "file_path": "/var/log/apache2/error.log",
                "log_group_name": "MoodleErrorLog",
                "log_stream_name": "{instance_id}-error"
              }
            ]
          }
        }
      }
    }
    
  • After pasting → Press Ctrl + O, Enter to save → Ctrl + X to exit.
  • Continue to run the commands below to start CloudWatch Agents.
    sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl \
      -a fetch-config \
      -m ec2 \
      -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json \
      -s
    
  • Go to AWS Console, open CloudWatch Agents -> Log Groups to check. Clean
  • You have completed sending system logs to AWS CloudWatch Logs.
  1. Set up alerts if students do not log in for a period using AWS Lambda.
  • Go to IAM > Roles > Create role.
  • Select Lambda as the trusted entity.
  • Attach the CloudWatchLogsFullAccess policy (to write logs).
  • Name the role: LambdaCheckInactiveUsersRole.

Clean Clean Clean

  • Go to AWS Lambda > Create function.

  • Select Author from scratch.

  • Function name: check-inactive-users

  • Runtime: Python 3.12

  • Execution role: Select the role you just created.

  • Click Create Function. Clean

  • After creation, go to Source Code and enter the following code:

    import logging
    from datetime import datetime, timedelta
    
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    def lambda_handler(event, context):
        # This is a simulated user list from the Moodle system
        users = [
            {"username": "alice", "last_login": "2025-07-30"},
            {"username": "bob", "last_login": "2025-07-25"},
        ]
    
        today = datetime.utcnow().date()
        threshold = today - timedelta(days=3)
    
        for user in users:
            last_login = datetime.strptime(user["last_login"], "%Y-%m-%d").date()
            if last_login < threshold:
                logger.info(f"User {user['username']} inactive since {last_login}")
        
        return {"status": "done"}
    

  • Then select Deploy Clean

  • Create an Event Bridge Rule to run Lambda daily

  • Go to Event Bridge on AWS Console -> Rule -> Create rule

  • Name: run-check-inactive-daily

  • Schedule: select Schedule → Continue in EventBridge Scheduler Clean

  • Set as shown in the image below then click next Clean Clean

  • In the Setting section, set as shown in the image below, use the role created for lambda above. Clean

  • Click next -> Create schedule Clean

  1. Send email alerts when students do not log in
  • Go to Amazon SNS from AWS Console.

  • Select Topics → Click Create topic.

  • Name: notify-inactive-students

  • Type: Standard -> Create topic

  • Click Create subscription

  • In protocol -> select Email

  • Enter the email you want to receive alerts -> Create subscription and you will receive a confirmation email. Clean

  • Click Confirm subscription. Clean

  • Update Lambda to publish to SNS

  • Open the Lambda function you created earlier.

  • Update the Lambda code as follows

    import json
    import logging
    import boto3
    from datetime import datetime, timedelta
    
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    # SNS topic ARN (replace this ARN with your actual ARN)
    SNS_TOPIC_ARN = "arn:aws:sns:ap-southeast-1:456202168166:InactiveUsersTopic"
    
    sns_client = boto3.client('sns')
    
    def lambda_handler(event, context):
        # Simulated user list (later can be fetched from Moodle API or DB)
        users = [
            {"username": "alice", "last_login": "2025-07-30"},
            {"username": "bob", "last_login": "2025-07-25"},
            {"username": "charlie", "last_login": "2025-07-20"},
        ]
    
        today = datetime.utcnow().date()
        threshold = today - timedelta(days=3)
    
        inactive_users = []
    
        for user in users:
            last_login = datetime.strptime(user["last_login"], "%Y-%m-%d").date()
            if last_login < threshold:
                logger.info(f"User {user['username']} inactive since {last_login}")
                inactive_users.append(user)
    
        if inactive_users:
            usernames = ", ".join([user['username'] for user in inactive_users])
            message = f"Students inactive for more than 3 days: {usernames}"
            
            # Send SNS
            try:
                response = sns_client.publish(
                    TopicArn=SNS_TOPIC_ARN, # Replace with your topic ARN, e.g. arn:aws:sns:ap-southeast-1:456202168166:notify-inactive-students
                    Message=message,
                    Subject="⚠️ Alert: Inactive Students"
                )
                logger.info(f"Sent alert via SNS: {response}")
            except Exception as e:
                logger.error(f"Error sending SNS message: {e}")
    
        return {
            "statusCode": 200,
            "body": json.dumps(f"Checked {len(users)} users. Inactive: {len(inactive_users)}")
        }
    

  • Redeploy the lambda function

  • Grant the Lambda IAM role the following permission by creating a new policy named AllowPublishToSNS.

  • Go to: IAM → Policies

  • Click “Create policy”

  • Select the Json tab and paste the following content.

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": "sns:Publish",
          "Resource": "arn:aws:sns:ap-southeast-1:456202168166:InactiveUsersTopic"
        }
      ]
    }
    

  • Go back to the Lambda Role, select LambdaCheckInactiveUsersRole and attach the newly created policy Clean

Clean

  1. Test Lambda’s SNS
  • Go to Lambda Console

  • Select the function you want to test (e.g.: check-inactive-users)

  • Click the “Test” button (top right corner)

  • Select “Create new event”

  • Event name: test-inactive-users

  • Event JSON (leave empty if no input):{} Clean

  • Click the “Test” button again Clean

  • If you see the notification above, you have successfully tested the Lambda command, check your email for the Inactive user alert! Clean

-> You have completed installing CloudWatch Agent to monitor system logs, created Lambda to check inactive students, and sent alerts via Amazon SNS if students do not log in for a long period.