Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions lambda-logging/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Lambda Logging

This script will enable Lambda function log groups for all regions in your account.

## Why?

Lambda automatically integrates with CloudWatch Logs and pushes all logs from your code to a CloudWatch Logs group associated with a Lambda function, which is named /aws/lambda/[function name]. If the log group associated with a Lambda function is not found, you'll find the following error in AWS console:

```Log group does not exist
The specific log group: /aws/lambda/<function name> does not exist in this account or region.
```

This script will enable the log groups for corresponding Lambda functions if they don't exist in all regions.

## What the script does.

Thsi script iterates through all the regions returned by ec2:DescribeRegions and if logs:describe_log_groups() with the specified log group name doesn't exist calls logs:create_log_group() to enable with the specified log group name.

## Usage

```bash
usage: enable-lambda-log-group.py [-h] [--debug] [--error] [--timestamp]
[--region REGION] [--profile PROFILE]
[--actually-do-it]

optional arguments:
-h, --help show this help message and exit
--debug print debugging info
--error print error info only
--timestamp Output log with timestamp and toolname
--region REGION Only Process Specified Region
--profile PROFILE Use this CLI profile (instead of default or env credentials)
--actually-do-it Actually Perform the action
```

You must specify `--actually-do-it` for the changes to be made. Otherwise the script runs in dry-run mode only.


## AWS Docs

* [EnableEbsEncryptionByDefault API](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EnableEbsEncryptionByDefault.html)
* [boto3 list_functions()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.list_functions)
* [boto3 describe_log_groups()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.describe_log_groups)
* [boto3 create_log_group()](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/logs.html#CloudWatchLogs.Client.create_log_group)


121 changes: 121 additions & 0 deletions lambda-logging/enable-lambda-log-group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#!/usr/bin/env python3

import boto3
from botocore.exceptions import ClientError
import os
import logging


def main(args, logger):
'''Executes the Primary Logic of the Fast Fix'''

# If they specify a profile use it. Otherwise do the normal thing
if args.profile:
session = boto3.Session(profile_name=args.profile)
else:
session = boto3.Session()

# Get all the Regions for this account
for region in get_regions(session, args):
lambda_client = session.client("lambda", region_name=region)
cwlog_client = session.client("logs", region_name=region)

# Create a reusable Paginator
paginator = lambda_client.get_paginator('list_functions')

# Create a PageIterator from the Paginator, parameters here?
page_iterator = paginator.paginate()

for page in page_iterator:
func_list = page['Functions']
for func in func_list:
func_name = func.get('FunctionName')
log_group_name=f"/aws/lambda/{func_name}"
logs = cwlog_client.describe_log_groups(logGroupNamePrefix=log_group_name)
if not logs['logGroups']:
# log group doesn't exist for this lambda function, creat log group
if args.actually_do_it is True:
logger.info(f"Creating log group {log_group_name} in {region}")
create_log_group(cwlog_client, region, log_group_name)
else:
logger.info(f"You Need To create log group {log_group_name} in {region}")



def create_log_group(cwlog_client, region, log_group_name):
'''Actually perform the creation of log group'''
try:
cwlog_client.create_log_group(logGroupName=log_group_name)

except ClientError as e:
logger.error(f"Attempt to create log group {log_group_name} in {region} returned \"{e}\"")



def get_regions(session, args):
'''Return a list of regions with us-east-1 first. If --region was specified, return a list wth just that'''

# If we specifed a region on the CLI, return a list of just that
if args.region:
return([args.region])

# otherwise return all the regions, us-east-1 first
ec2 = session.client('ec2')
response = ec2.describe_regions()
output = ['us-east-1']
for r in response['Regions']:
# return us-east-1 first, but dont return it twice
if r['RegionName'] == "us-east-1":
continue
output.append(r['RegionName'])
return(output)



def do_args():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--debug", help="print debugging info", action='store_true')
parser.add_argument("--error", help="print error info only", action='store_true')
parser.add_argument("--timestamp", help="Output log with timestamp and toolname", action='store_true')
parser.add_argument("--region", help="Only Process Specified Region")
parser.add_argument("--profile", help="Use this CLI profile (instead of default or env credentials)")
parser.add_argument("--actually-do-it", help="Actually Perform the action", action='store_true')

args = parser.parse_args()

return(args)

if __name__ == '__main__':

args = do_args()

# create console handler and set level to debug
logger = logging.getLogger('enable-lambda-log-group')
ch = logging.StreamHandler()
if args.debug:
logger.setLevel(logging.DEBUG)
elif args.error:
logger.setLevel(logging.ERROR)
else:
logger.setLevel(logging.INFO)

# Silence Boto3 & Friends
logging.getLogger('botocore').setLevel(logging.WARNING)
logging.getLogger('boto3').setLevel(logging.WARNING)
logging.getLogger('urllib3').setLevel(logging.WARNING)

# create formatter
if args.timestamp:
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
else:
formatter = logging.Formatter('%(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)

try:
main(args, logger)
except KeyboardInterrupt:
exit(1)