Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed broken cloudwatch evidently petfood and petfood-metrics container #271

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion PetAdoptions/petfood-metric/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster
FROM --platform=linux/amd64 python:3.8-slim-buster

WORKDIR /app

Expand Down
71 changes: 28 additions & 43 deletions PetAdoptions/petfood-metric/petfood-metric.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
#!/usr/bin/env python # pylint: disable=C0103

"""Simple microservice to show Evidently features"""

import json
import logging
import os
Expand All @@ -11,27 +7,17 @@
from aws_xray_sdk.core import patch_all, xray_recorder
from flask import Flask, request


app = Flask(__name__)
xray_recorder.configure(service='petfood-metric')
patch_all()
XRayMiddleware(app, xray_recorder)


class StructuredMessage: # pylint: disable=R0903
"""Use to make JSON formatted logging work well for CWL"""
def __init__(self, message, /, **kwargs):
self.message = message
self.kwargs = kwargs

def __str__(self):
return f'{self.message} - {self.kwargs}'


_ = StructuredMessage
logging.basicConfig(level=os.getenv('LOG_LEVEL', 20), format='%(message)s')
logger = logging.getLogger()

logging.basicConfig(
level=os.getenv('LOG_LEVEL', logging.INFO),
format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)

class EvidentlyProject:
"""Base for all Evidently interactions"""
Expand All @@ -40,50 +26,49 @@ def __init__(self):
self.client = boto3.client('evidently')
self.project = os.getenv('EVIDENTLY_PROJECT', 'petfood')

@xray_recorder.capture('evidently_project_exists')
def project_exists(self):
"""Returns False if the project does not currently exist"""
xray_recorder.begin_subsegment('evidently project_exists')
try:
response = self.client.get_project(project=self.project)
logger.info(_('checking for evidently project', response=response))
xray_recorder.end_subsegment()
self.client.get_project(project=self.project)
logger.info("Evidently project '%s' found", self.project)
return True
except self.client.exceptions.ResourceNotFoundException:
logger.warning(_('evidently project not found'))
xray_recorder.end_subsegment()
return None
logger.warning("Evidently project '%s' not found", self.project)
return False

@xray_recorder.capture('evidently_put_metric')
def put_metric(self, entity_id, value):
"""Puts metric into Evidently"""
data = json.dumps({
'userDetails': {'entityId': entity_id},
'details': {'donation': value}
})
'userDetails': {'entityId': entity_id},
'details': {'donation': value}
})
response = self.client.put_project_events(
events=[{'timestamp': time.time(),
'data': data,
'type': 'aws.evidently.custom'}],
events=[{
'timestamp': time.time(),
'data': data,
'type': 'aws.evidently.custom'
}],
project=self.project
)
logger.warning(_('response to put_metric call', response=response))

logger.warning("Response to put_metric call: %s", response)

@app.route('/metric/<entity_id>/<value>')
def root_path(entity_id, value):
"""Base URL for our handler"""
logger.info(_('raw request headers', headers=request.headers))
logger.info("Raw request headers: %s", request.headers)
xray_recorder.begin_segment('petfood-metric')
evidently = EvidentlyProject()
project = evidently.project_exists()
if not project:
return json.dumps({'statusCode': 404, 'body': 'evidently project not found'})
evidently.put_metric(str(entity_id), float(value))
# xray_recorder.end_segment()
if not evidently.project_exists():
xray_recorder.end_segment()
return json.dumps({'statusCode': 404, 'body': 'Evidently project not found'})
evidently.put_metric(entity_id, float(value))
xray_recorder.end_segment()
return json.dumps('ok')


@app.route('/status')
def status_path():
logger.info(_('raw request headers', headers=request.headers))
"""Used for health checks"""
logger.info("Raw request headers: %s", request.headers)
return json.dumps({'statusCode': 200, 'body': 'ok'})
89 changes: 89 additions & 0 deletions PetAdoptions/petfood-metric/petfood-metric.py.orig
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#!/usr/bin/env python # pylint: disable=C0103

"""Simple microservice to show Evidently features"""

import json
import logging
import os
import time
import boto3
from aws_xray_sdk.ext.flask.middleware import XRayMiddleware
from aws_xray_sdk.core import patch_all, xray_recorder
from flask import Flask, request


app = Flask(__name__)
xray_recorder.configure(service='petfood-metric')
patch_all()
XRayMiddleware(app, xray_recorder)


class StructuredMessage: # pylint: disable=R0903
"""Use to make JSON formatted logging work well for CWL"""
def __init__(self, message, /, **kwargs):
self.message = message
self.kwargs = kwargs

def __str__(self):
return f'{self.message} - {self.kwargs}'


_ = StructuredMessage
logging.basicConfig(level=os.getenv('LOG_LEVEL', 20), format='%(message)s')
logger = logging.getLogger()


class EvidentlyProject:
"""Base for all Evidently interactions"""

def __init__(self):
self.client = boto3.client('evidently')
self.project = os.getenv('EVIDENTLY_PROJECT', 'petfood')

def project_exists(self):
"""Returns False if the project does not currently exist"""
xray_recorder.begin_subsegment('evidently project_exists')
try:
response = self.client.get_project(project=self.project)
logger.info(_('checking for evidently project', response=response))
xray_recorder.end_subsegment()
return True
except self.client.exceptions.ResourceNotFoundException:
logger.warning(_('evidently project not found'))
xray_recorder.end_subsegment()
return None

def put_metric(self, entity_id, value):
"""Puts metric into Evidently"""
data = json.dumps({
'userDetails': {'entityId': entity_id},
'details': {'donation': value}
})
response = self.client.put_project_events(
events=[{'timestamp': time.time(),
'data': data,
'type': 'aws.evidently.custom'}],
project=self.project
)
logger.warning(_('response to put_metric call', response=response))


@app.route('/metric/<entity_id>/<value>')
def root_path(entity_id, value):
"""Base URL for our handler"""
logger.info(_('raw request headers', headers=request.headers))
xray_recorder.begin_segment('petfood-metric')
evidently = EvidentlyProject()
project = evidently.project_exists()
if not project:
return json.dumps({'statusCode': 404, 'body': 'evidently project not found'})
evidently.put_metric(str(entity_id), float(value))
# xray_recorder.end_segment()
return json.dumps('ok')


@app.route('/status')
def status_path():
logger.info(_('raw request headers', headers=request.headers))
"""Used for health checks"""
return json.dumps({'statusCode': 200, 'body': 'ok'})
4 changes: 2 additions & 2 deletions PetAdoptions/petfood-metric/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
aws-xray-sdk==2.9.0
Flask==2.0.2
boto3==1.20.21
Flask==2.3.0
boto3==1.34.64
gunicorn==20.1.0
4 changes: 3 additions & 1 deletion PetAdoptions/petfood/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1

FROM python:3.8-slim-buster
FROM --platform=linux/amd64 python:3.8-slim-buster

WORKDIR /app

Expand All @@ -10,4 +10,6 @@ RUN pip3 install -r requirements.txt
COPY . .
ENV FLASK_APP=petfood

ENV EVIDENTLY_PROJECT=petfood

CMD [ "python3", "-m" , "gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "--capture-output", "petfood:app"]
88 changes: 32 additions & 56 deletions PetAdoptions/petfood/petfood.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"""Simple microservice to show Evidently features"""

import json
import logging
import os
Expand All @@ -9,29 +7,19 @@
from aws_xray_sdk.core import patch_all, xray_recorder
from flask import Flask, request


app = Flask(__name__)
plugins = ('EC2Plugin',)
xray_recorder.configure(plugins=plugins, service='petfood')
patch_all()
XRayMiddleware(app, xray_recorder)
xray_recorder.begin_segment('petfood')


class StructuredMessage: # pylint: disable=R0903
"""Use to make JSON formatted logging work well for CWL"""
def __init__(self, message, /, **kwargs):
self.message = message
self.kwargs = kwargs

def __str__(self):
return f'{self.message} - {self.kwargs}'


_ = StructuredMessage
logging.basicConfig(level=os.getenv('LOG_LEVEL', 20), format='%(message)s')
logger = logging.getLogger()

logging.basicConfig(
level=os.getenv('LOG_LEVEL', logging.INFO),
format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)

class EvidentlyProject:
"""Base for all Evidently interactions"""
Expand All @@ -42,18 +30,18 @@ def __init__(self):
self.upsell_feature = 'petfood-upsell'
self.upsell_text_feature = 'petfood-upsell-text'

@xray_recorder.capture('evidently project_exists')
@xray_recorder.capture('evidently_project_exists')
def project_exists(self):
"""Returns False if the project does not currently exist"""
try:
response = self.client.get_project(project=self.project)
logger.info(_('checking for evidently project', response=response))
self.client.get_project(project=self.project)
logger.info("Evidently project '%s' found", self.project)
return True
except self.client.exceptions.ResourceNotFoundException:
logger.warning(_('evidently project not found'))
return None
logger.warning("Evidently project '%s' not found", self.project)
return False

@xray_recorder.capture('evidently get_upsell_evaluation')
@xray_recorder.capture('evidently_get_upsell_evaluation')
def get_upsell_evaluation(self, entity_id):
"""Gets the feature evaluation for petfood-upsell"""
try:
Expand All @@ -67,10 +55,10 @@ def get_upsell_evaluation(self, entity_id):
'variation': response['variation']
}
except self.client.exceptions.ResourceNotFoundException:
logger.warning(_('evidently feature ' + self.upsell_feature + ' not found for project'))
logger.warning("Evidently feature '%s' not found for project '%s'", self.upsell_feature, self.project)
return return_default()

@xray_recorder.capture('evidently get_upsell_text')
@xray_recorder.capture('evidently_get_upsell_text')
def get_upsell_text(self, entity_id):
"""Gets the feature evaluation for petfood-upsell-verbiage"""
try:
Expand All @@ -79,59 +67,47 @@ def get_upsell_text(self, entity_id):
feature=self.upsell_text_feature,
project=self.project
)
logger.info(_('evidently ' + self.upsell_text_feature, response=response))
logger.info("Evidently feature '%s': %s", self.upsell_text_feature, response['value']['stringValue'])
return response['value']['stringValue']
except self.client.exceptions.ResourceNotFoundException:
logger.warning(_('evidently feature ' + self.upsell_text_feature + ' not found for project'))
logger.warning("Evidently feature '%s' not found for project '%s'", self.upsell_text_feature, self.project)
return 'Error getting upsell message - check that your feature exists in Evidently!'


@xray_recorder.capture('return_evidently_response')
def return_evidently_response(evidently):
"""Create a response using an Evidently project"""
logger.info(_('building evidently response'))
logger.info("Building Evidently response")
entity_id = str(random.randint(1, 100))
evaluation = evidently.get_upsell_evaluation(entity_id)
logger.warning(_('response from feature evaluation', evaluation=evaluation))
response = json.dumps(
{
'statusCode': 200,
'message': evidently.get_upsell_text(entity_id),
'variation': evaluation,
'entityId': entity_id
}
)
logger.warning(_('final response to request', response=response))
return response

logger.warning("Response from feature evaluation: %s", evaluation)
return json.dumps({
'statusCode': 200,
'message': evidently.get_upsell_text(entity_id),
'variation': evaluation,
'entityId': entity_id
})

@xray_recorder.capture('return_default_response')
def return_default():
"""Returns the default response to the user"""
logger.warning(_('returning default response to the user'))
text = json.dumps(
{
'message': 'Thank you for supporting our community!',
'statusCode': 200
}
)
return text

logger.warning("Returning default response to the user")
return json.dumps({
'message': 'Thank you for supporting our community!',
'statusCode': 200
})

@app.route('/')
def root_path():
"""Base URL for our handler"""
logger.info(_('raw request headers', headers=request.headers))
logger.info("Raw request headers: %s", request.headers)
evidently = EvidentlyProject()
project = evidently.project_exists()
if not project:
if not evidently.project_exists():
return return_default()
else:
return return_evidently_response(evidently)


@app.route('/status')
def status_path():
"""Used for health checks"""
logger.info(_('raw request headers', headers=request.headers))
logger.info("Raw request headers: %s", request.headers)
return json.dumps({'statusCode': 200, 'body': 'ok'})
Loading