Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3c6b4cf

Browse files
Merge pull request #3 from Moesif/fix-url-and-cleanup
Fix: URL parsing. Lot's of cleanup
2 parents 38fd15d + 238e52d commit 3c6b4cf

File tree

4 files changed

+81
-150
lines changed

4 files changed

+81
-150
lines changed

‎lambda_function.py

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,9 @@
11
from moesif_aws_lambda.middleware import MoesifLogger
22
import os
33

4-
# Moesif Application Id
5-
os.environ["MOESIF_APPLICATION_ID"] = "Your Moesif Application Id"
6-
7-
def identify_user(event, context):
8-
return 'my_user_id'
9-
10-
def identify_company(event, context):
11-
return 'my_company_id'
12-
13-
def get_api_version(event, context):
14-
return '1.0.0'
15-
16-
def get_session_token(event, context):
17-
return '23jdf0owekfmcn4u3qypxg09w4d8ayrcdx8nu2ng]s98y18cx98q3yhwmnhcfx43f'
18-
19-
def get_metadata(event, context):
20-
return { 'foo' : 'aws lambda', 'bar' : 'aws lambda metadata', }
21-
22-
def mask_event(eventmodel):
23-
return eventmodel
24-
25-
def should_skip(event, context):
26-
return "/" in event['path']
27-
284
moesif_options = {
29-
'GET_METADATA': get_metadata,
30-
'IDENTIFY_USER': identify_user,
31-
'IDENTIFY_COMPANY': identify_company,
32-
'GET_SESSION_TOKEN': get_session_token,
33-
'GET_API_VERSION': get_api_version,
34-
'MASK_EVENT_MODEL': mask_event,
355
'LOG_BODY': True,
366
'DEBUG': True,
37-
'SKIP': should_skip,
387
}
398

409
@MoesifLogger(moesif_options)

‎moesif_aws_lambda/middleware.py

Lines changed: 76 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@
66
from moesifapi.models import *
77
from .client_ip import ClientIp
88
from datetime import *
9-
from urllib.parse import urlencode
109
import base64
1110
import json
1211
import os
12+
from pprint import pprint
13+
import base64
14+
try:
15+
from urllib import urlencode
16+
except ImportError:
17+
from urllib.parse import urlencode
1318

1419
def MoesifLogger(moesif_options):
1520
class log_data(LambdaDecorator):
@@ -26,8 +31,10 @@ def __init__(self, handler):
2631
self.DEBUG = self.moesif_options.get('DEBUG', False)
2732
self.event = None
2833
self.context = None
34+
self.start_time = datetime.utcnow()
35+
2936
# Intialized the client
30-
if os.environ["MOESIF_APPLICATION_ID"]:
37+
if os.environ.get("MOESIF_APPLICATION_ID"):
3138
self.api_client = MoesifAPIClient(os.environ["MOESIF_APPLICATION_ID"]).api
3239
else:
3340
raise Exception('Moesif Application ID is required in settings')
@@ -47,10 +54,10 @@ def get_user_id(self, event, context):
4754
username = rc_identity_id
4855
except:
4956
if self.DEBUG:
50-
print("can not fetch apiKey from cognitoIdentityId event, setting userId to None.")
57+
print("MOESIF can not fetch apiKey from cognitoIdentityId event, setting userId to None.")
5158
except Exception as e:
5259
if self.DEBUG:
53-
print("can not execute identify_user function, please check moesif settings.")
60+
print("MOESIF can not execute identify_user function, please check moesif settings.")
5461
print(e)
5562
return username
5663

@@ -63,89 +70,70 @@ def get_company_id(self, event, context):
6370
company_id = identify_company(event, context)
6471
except Exception as e:
6572
if self.DEBUG:
66-
print("can not execute identify_company function, please check moesif settings.")
73+
print("MOESIF can not execute identify_company function, please check moesif settings.")
6774
print(e)
6875
return company_id
6976

70-
def process_request_body(self, raw_request_body):
71-
"""Function to process Request body"""
72-
req_body = None
73-
req_transfer_encoding = None
74-
try:
75-
if 'isBase64Encoded' in raw_request_body and 'body' in raw_request_body and raw_request_body['isBase64Encoded'] and raw_request_body['body']:
76-
req_body = raw_request_body['body']
77-
req_transfer_encoding = 'base64'
78-
else:
79-
if 'body' in raw_request_body and raw_request_body['body'] and isinstance(raw_request_body['body'], str):
80-
req_body = json.loads(raw_request_body['body'])
81-
else:
82-
req_body = raw_request_body['body']
83-
req_transfer_encoding = 'json'
84-
except Exception as e:
85-
if self.DEBUG:
86-
print('Error while parsing request body')
87-
print(e)
88-
return req_body, req_transfer_encoding
77+
def build_uri(self, event):
78+
79+
uri = event['headers'].get('X-Forwarded-Proto', event['headers'].get('x-forwarded-proto', 'http://')) + event['headers'].get('Host', event['headers'].get('host', 'localhost')) + event.get('path', '/')
80+
81+
if event.get('multiValueQueryStringParameters', {}):
82+
uri = uri + '?' + urlencode(event['multiValueQueryStringParameters'], doseq=True)
83+
elif event.get('queryStringParameters', {}):
84+
uri = uri + '?' + urlencode(event['queryStringParameters'])
85+
return uri
8986

90-
def process_response_body(self, raw_response_body):
91-
"""Function to process Response body"""
92-
resp_body = None
93-
resp_transfer_encoding = None
87+
def process_body(self, body_wrapper):
88+
"""Function to process body"""
89+
if not (self.LOG_BODY and body_wrapper.get('body')):
90+
return None, 'json'
91+
92+
body = None
93+
transfer_encoding = None
9494
try:
95-
if 'isBase64Encoded'inraw_response_bodyand'body'inraw_response_bodyandraw_response_body['isBase64Encoded'] andraw_response_body['body']:
96-
resp_body = raw_response_body['body']
97-
resp_transfer_encoding = 'base64'
95+
if body_wrapper.get('isBase64Encoded', False):
96+
body = body_wrapper.get('body')
97+
transfer_encoding = 'base64'
9898
else:
99-
if 'body'inraw_response_bodyandraw_response_body['body'] andisinstance(raw_response_body['body'], str):
100-
resp_body = json.loads(raw_response_body['body'])
99+
if isinstance(body_wrapper['body'], str):
100+
body = json.loads(body_wrapper.get('body'))
101101
else:
102-
resp_body = raw_response_body['body']
103-
resp_transfer_encoding = 'json'
102+
body = body_wrapper.get('body')
103+
transfer_encoding = 'json'
104104
except Exception as e:
105-
if self.DEBUG:
106-
print('Error while parsing response body')
107-
print(e)
108-
return resp_body, resp_transfer_encoding
105+
body = base64.b64encode(body_wrapper['body'].encode("utf-8"))
106+
return str(encodedBytes, "utf-8"), 'json'
107+
return body, transfer_encoding
109108

110109
def before(self, event, context):
111110
"""This function runs before the handler is invoked, is passed the event & context and must return an event & context too."""
111+
112+
# Request Method
113+
request_verb = event.get('httpMethod')
114+
if request_verb is None:
115+
print('MOESIF: [before] AWS Lambda trigger must be a Load Balancer or API Gateway See https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html or https://docs.aws.amazon.com/lambda/latest/dg/with-on-demand-https.html.')
116+
return event, context
117+
112118
# Request headers
113119
req_headers = {}
114120
try:
115121
if 'headers' in event:
116122
req_headers = APIHelper.json_deserialize(event['headers'])
117123
except Exception as e:
118124
if self.DEBUG:
119-
print('Error while fetching request headers')
125+
print('MOESIF Error while fetching request headers')
120126
print(e)
121127

122128
# Request Time
123-
request_time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
124-
125-
# Request URI
126-
try:
127-
request_uri = event['headers']['X-Forwarded-Proto'] + '://' + event['headers']['Host'] + event['path'] + '?' + urlencode(event['queryStringParameters'])
128-
except:
129-
request_uri = '/'
130-
131-
# Request Method
132-
try:
133-
request_verb = event['httpMethod']
134-
except:
135-
if self.DEBUG:
136-
print('Request method should not be empty.')
129+
epoch = event and event.get('request_context', {}).get('requestTimeEpoch')
130+
if epoch is not None:
131+
request_time =datetime.utcfromtimestamp(epoch)
132+
else:
133+
request_time = self.start_time
137134

138135
# Request Body
139-
req_body = None
140-
req_transfer_encoding = None
141-
try:
142-
if self.LOG_BODY and 'body' in event:
143-
if event['body']:
144-
req_body, req_transfer_encoding = self.process_request_body(event)
145-
except Exception as e:
146-
if self.DEBUG:
147-
print('Error while fetching request body')
148-
print(e)
136+
req_body, req_transfer_encoding = self.process_body(event)
149137

150138
# Metadata
151139
try:
@@ -158,14 +146,15 @@ def before(self, event, context):
158146
self.metadata = {
159147
'trace_id': str(context.aws_request_id),
160148
'function_name': context.function_name,
161-
'request_context': event['requestContext']
149+
'request_context': event['requestContext'],
150+
'context': context
162151
}
163152
except:
164153
if self.DEBUG:
165-
print("can not fetch default function_name and request_context from aws context, setting metadata to None.")
154+
print("MOESIF can not fetch default function_name and request_context from aws context, setting metadata to None.")
166155
except Exception as e:
167156
if self.DEBUG:
168-
print("can not execute GET_METADATA function, please check moesif settings.")
157+
print("MOESIF can not execute GET_METADATA function, please check moesif settings.")
169158
print(e)
170159

171160
# User Id
@@ -187,10 +176,10 @@ def before(self, event, context):
187176
self.session_token = rc_api_key
188177
except KeyError:
189178
if self.DEBUG:
190-
print("can not fetch apiKey from aws event, setting session_token to None.")
179+
print("MOESIF can not fetch apiKey from aws event, setting session_token to None.")
191180
except Exception as e:
192181
if self.DEBUG:
193-
print("can not execute GET_SESSION_TOKEN function, please check moesif settings.")
182+
print("MOESIF can not execute GET_SESSION_TOKEN function, please check moesif settings.")
194183
print(e)
195184

196185
# Api Version
@@ -205,74 +194,41 @@ def before(self, event, context):
205194
api_version = context.function_version
206195
except KeyError:
207196
if self.DEBUG:
208-
print("can not fetch default function_version from aws context, setting api_version to None.")
197+
print("MOESIF can not fetch default function_version from aws context, setting api_version to None.")
209198
except Exception as e:
210199
if self.DEBUG:
211-
print("can not execute GET_API_VERSION function, please check moesif settings.")
200+
print("MOESIF can not execute GET_API_VERSION function, please check moesif settings.")
212201
print(e)
213202

214203
# IpAddress
215-
ip_address = None
216-
try:
217-
if 'headers' in event and 'requestContext' in event and 'identity' in event['requestContext'] and 'sourceIp' in event['requestContext']['identity'] and event['requestContext']['identity']['sourceIp']:
218-
ip_address = self.client_ip.get_client_address(event['headers'], event['requestContext']['identity']['sourceIp'])
219-
except Exception as e:
220-
if self.DEBUG:
221-
print("Error while fetching Client Ip address, setting Request Ip address to None.")
222-
print(e)
204+
ip_address = event.get('requestContext', {}).get('identity', {}).get('sourceIp', None)
223205

224206
# Event Request Object
225-
self.event_req = EventRequestModel(time = request_time,
226-
uri = request_uri,
207+
self.event_req = EventRequestModel(time = request_time.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3],
208+
uri = self.build_uri(event),
227209
verb = request_verb,
228210
api_version = api_version,
229-
ip_address = ip_address,
211+
ip_address = self.client_ip.get_client_address(event['headers'], ip_address),
230212
headers = req_headers,
231213
body = req_body,
232214
transfer_encoding = req_transfer_encoding)
233215

234216
# Set/Save event and context for use Skip Event function
235217
self.event = event
236218
self.context = context
237-
219+
238220
# Return event, context
239221
return event, context
240222

241223
def after(self, retval):
242224
"""This function runs after the handler is invoked, is passed the response and must return an response too."""
243225
# Response body
244-
resp_body = None
245-
resp_transfer_encoding = None
246-
try:
247-
if self.LOG_BODY and 'body' in retval:
248-
if retval['body']:
249-
resp_body, resp_transfer_encoding = self.process_response_body(retval)
250-
except Exception as e:
251-
if self.DEBUG:
252-
print('Error while fetching response body')
253-
print(e)
254-
255-
# Response headers
256-
resp_headers = {}
257-
try:
258-
if 'headers' in retval:
259-
resp_headers = retval['headers']
260-
except Exception as e:
261-
if self.DEBUG:
262-
print('Error while fetching response headers')
263-
print(e)
264-
265-
# Response status code
266-
try:
267-
status_code = retval['statusCode']
268-
except:
269-
if self.DEBUG:
270-
print('Response status code should not be empty')
226+
resp_body, resp_transfer_encoding = self.process_body(retval)
271227

272228
# Event Response object
273229
event_rsp = EventResponseModel(time = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3],
274-
status = status_code,
275-
headers = resp_headers,
230+
status = retval.get('statusCode', 599),
231+
headers = retval.get('headers', {}),
276232
body = resp_body,
277233
transfer_encoding = resp_transfer_encoding)
278234

@@ -291,24 +247,28 @@ def after(self, retval):
291247
event_model = mask_event_model(event_model)
292248
except:
293249
if self.DEBUG:
294-
print("Can not execute MASK_EVENT_MODEL function. Please check moesif settings.")
250+
print("MOESIF Can not execute MASK_EVENT_MODEL function. Please check moesif settings.")
295251

296252
# Skip Event
297253
try:
298254
skip_event = self.moesif_options.get('SKIP', None)
299255
if skip_event is not None:
300256
if skip_event(self.event, self.context):
301257
if self.DEBUG:
302-
print('Skip sending event to Moesif')
258+
print('MOESIF Skip sending event to Moesif')
303259
return retval
304260
except:
305261
if self.DEBUG:
306-
print("Having difficulty executing skip_event function. Please check moesif settings.")
262+
print("MOESIF Having difficulty executing skip_event function. Please check moesif settings.")
307263

308264
# Send event to Moesif
265+
if self.DEBUG:
266+
print('Moesif Event Model:')
267+
pprint(self.event)
268+
309269
event_send = self.api_client.create_event(event_model)
310270
if self.DEBUG:
311-
print('Event Sent successfully')
271+
print('MOESIF '+str(event_send))
312272

313273
# Send response
314274
return retval

‎package.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env bash
2-
pip3 install --target ./package moesif_aws_lambda
2+
rm -rf package build dist
3+
pip3 uninstall moesif_aws_lambda
4+
pip3 install --target ./package -r requirements.txt
35
cd package
46
zip -r9 ${OLDPWD}/function.zip .
57
cd $OLDPWD
6-
zip -g function.zip lambda_function.py
8+
zip -g function.zip lambda_function.py moesif_aws_lambda/*

‎setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
# Versions should comply with PEP440. For a discussion on single-sourcing
2929
# the version across setup.py and the project code, see
3030
# https://packaging.python.org/en/latest/single_source_version.html
31-
version='1.0.2',
31+
version='1.0.3',
3232

3333
description='Moesif Middleware to automatically log API calls from AWS Lambda functions',
3434
long_description=long_description,

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /