Middleware (Python) to automatically log API calls from AWS Lambda functions and sends to Moesif for API analytics and log analysis.
Designed for APIs that are hosted on AWS Lambda using Amazon API Gateway or Application Load Balancer as a trigger.
This middleware expects the Lambda proxy integration type. If you're using AWS Lambda with API Gateway, you are most likely using the proxy integration type.
pip install moesif_aws_lambda
from moesif_aws_lambda.middleware import MoesifLogger
moesif_options = {
'LOG_BODY': True
}
@MoesifLogger(moesif_options)
def lambda_handler(event, context):
return {
'statusCode': 200,
'isBase64Encoded': False,
'body': {
'msg': 'Hello from Lambda!'
},
'headers': {
'Content-Type': 'application/json'
}
}
Add a new environment variable with the name MOESIF_APPLICATION_ID
and the value being your Moesif application id,
which can be found in the Moesif Portal.
After signing up for a Moesif account, your Moesif Application Id will be displayed during the onboarding steps.
You can always find your Moesif Application Id at any time by logging into the Moesif Portal, click on the top right menu, and then clicking Installation.
moesif_aws_lambda/middleware.py
the middleware librarylambda_function.py
sample AWS Lambda function using the middleware
If you want to capture all outgoing API calls from your Python Lambda function to third parties like
Stripe or to your own dependencies, call start_capture_outgoing()
to start capturing. This mechanism works by
patching the Requests
from moesif_aws_lambda.middleware import *
start_capture_outgoing(moesif_options) # moesif_options are the configuration options.
Type: (event, context) => String
IDENTIFY_USER
is a function that takes AWS lambda event
and context
objects as arguments
and returns a user_id. This enables Moesif to attribute API requests to individual unique users
so you can understand who calling your API. This can be used simultaneously with IDENTIFY_COMPANY
to track both individual customers and the companies their a part of.
def identify_user(event, context):
# your code here, must return a string
return event["requestContext"]["identity"]["cognitoIdentityId"]
Type: (event, context) => String
IDENTIFY_COMPANY
is a function that takes AWS lambda event
and context
objects as arguments
and returns a company_id. If your business is B2B, this enables Moesif to attribute
API requests to specific companies or organizations so you can understand which accounts are
calling your API. This can be used simultaneously with IDENTIFY_USER
to track both
individual customers and the companies their a part of.
def identify_company(event, context):
# your code here, must return a string
return '7890'
}
Type: (event, context) => String
GET_SESSION_TOKEN
a function that takes AWS lambda event
and context
objects as arguments and returns a
session token (i.e. such as an API key).
def get_session_token(event, context):
# your code here, must return a string.
return 'XXXXXXXXX'
Type: (event, context) => String
GET_API_VERSION
is a function that takes AWS lambda event
and context
objects as arguments and
returns a string to tag requests with a specific version of your API.
def get_api_version(event, context):
# your code here. must return a string.
return '1.0.0'
Type: (event, context) => String
GET_METADATA
is a function that AWS lambda event
and context
objects as arguments and returns an object that allows you to add custom metadata that will be associated with the request. The metadata must be a simple python object that can be converted to JSON. For example, you may want to save a function_name, a trace_id, or request_context with the request.
def get_metadata(event, context):
# your code here:
return {
'trace_id': context.aws_request_id,
'function_name': context.function_name,
'request_context': event['requestContext']
}
Type: (event, context) => Boolean
SKIP
is a function that takes AWS lambda event
and context
objects as arguments and returns true
if the event should be skipped (i.e. not logged)
The default is shown below and skips requests to the root path "/".
def should_skip(event, context):
# your code here. must return a boolean.
return "/" in event['path']
Type: MoesifEventModel => MoesifEventModel
MASK_EVENT_MODEL
is a function that takes the final Moesif event model (rather than the AWS lambda event/context objects) as an argument before being sent to Moesif. With maskContent, you can make modifications to headers or body such as removing certain header or body fields.
def mask_event(eventmodel):
# remove any field that you don't want to be sent to Moesif.
return eventmodel
Type: Boolean
Set to true to print debug logs if you're having integration issues.
Type: Boolean
LOG_BODY
is default to true, set to false to remove logging request and response body to Moesif.
The options below are applied to outgoing API calls. The request and response objects passed in are Requests request and Response response objects.
(optional) (req, res) => boolean, a function that takes a Requests request and response, and returns true if you want to skip this particular event.
(optional, but highly recommended) (req, res) => string, a function that takes Requests request and response, and returns a string that is the user id used by your system. While Moesif tries to identify users automatically, but different frameworks and your implementation might be very different, it would be helpful and much more accurate to provide this function.
(optional) (req, res) => string, a function that takes Requests request and response, and returns a string that is the company id for this event.
(optional) (req, res) => dictionary, a function that takes Requests request and response, and returns a dictionary (must be able to be encoded into JSON). This allows to associate this event with custom metadata. For example, you may want to save a VM instance_id, a trace_id, or a tenant_id with the request.
(optional) (req, res) => string, a function that takes Requests request and response, and returns a string that is the session token for this event. Again, Moesif tries to get the session token automatically, but if you setup is very different from standard, this function will be very help for tying events together, and help you replay the events.
(optional) boolean, default True, Set to False to remove logging request and response body.
Create or update a user profile in Moesif.
The metadata field can be any customer demographic or other info you want to store.
Only the user_id
field is required.
For details, visit the Python API Reference.
from moesif_aws_lambda.middleware import *
moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}
# Only user_id is required.
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
# See https://www.moesif.com/docs/api#users for campaign schema
# metadata can be any custom object
user = {
'user_id': '12345',
'company_id': '67890', # If set, associate user with a company object
'campaign': {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_campaign': 'adwords',
'utm_term': 'api+tooling',
'utm_content': 'landing'
},
'metadata': {
'email': 'john@acmeinc.com',
'first_name': 'John',
'last_name': 'Doe',
'title': 'Software Engineer',
'sales_info': {
'stage': 'Customer',
'lifetime_value': 24000,
'account_owner': 'mary@contoso.com'
},
}
}
update_user(user, moesif_options)
Similar to update_user, but used to update a list of users in one batch.
Only the user_id
field is required.
For details, visit the Python API Reference.
from moesif_aws_lambda.middleware import *
moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}
userA = {
'user_id': '12345',
'company_id': '67890', # If set, associate user with a company object
'metadata': {
'email': 'john@acmeinc.com',
'first_name': 'John',
'last_name': 'Doe',
'title': 'Software Engineer',
'sales_info': {
'stage': 'Customer',
'lifetime_value': 24000,
'account_owner': 'mary@contoso.com'
},
}
}
userB = {
'user_id': '54321',
'company_id': '67890', # If set, associate user with a company object
'metadata': {
'email': 'mary@acmeinc.com',
'first_name': 'Mary',
'last_name': 'Jane',
'title': 'Software Engineer',
'sales_info': {
'stage': 'Customer',
'lifetime_value': 48000,
'account_owner': 'mary@contoso.com'
},
}
}
update_users_batch([userA, userB], moesif_options)
Create or update a company profile in Moesif.
The metadata field can be any company demographic or other info you want to store.
Only the company_id
field is required.
For details, visit the Python API Reference.
from moesif_aws_lambda.middleware import *
moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}
# Only company_id is required.
# Campaign object is optional, but useful if you want to track ROI of acquisition channels
# See https://www.moesif.com/docs/api#update-a-company for campaign schema
# metadata can be any custom object
company = {
'company_id': '67890',
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'campaign': {
'utm_source': 'google',
'utm_medium': 'cpc',
'utm_campaign': 'adwords',
'utm_term': 'api+tooling',
'utm_content': 'landing'
},
'metadata': {
'org_name': 'Acme, Inc',
'plan_name': 'Free',
'deal_stage': 'Lead',
'mrr': 24000,
'demographics': {
'alexa_ranking': 500000,
'employee_count': 47
},
}
}
update_company(company, moesif_options)
Similar to update_company, but used to update a list of companies in one batch.
Only the company_id
field is required.
For details, visit the Python API Reference.
from moesif_aws_lambda.middleware import *
moesif_options = {
'LOG_BODY': True,
'DEBUG': True,
}
companyA = {
'company_id': '67890',
'company_domain': 'acmeinc.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'metadata': {
'org_name': 'Acme, Inc',
'plan_name': 'Free',
'deal_stage': 'Lead',
'mrr': 24000,
'demographics': {
'alexa_ranking': 500000,
'employee_count': 47
},
}
}
companyB = {
'company_id': '09876',
'company_domain': 'contoso.com', # If domain is set, Moesif will enrich your profiles with publicly available info
'metadata': {
'org_name': 'Contoso, Inc',
'plan_name': 'Free',
'deal_stage': 'Lead',
'mrr': 48000,
'demographics': {
'alexa_ranking': 500000,
'employee_count': 53
},
}
}
update_companies_batch([companyA, companyB], moesif_options)
To view more documentation on integration options, please visit the Integration Options Documentation.