From 0d953df7b0d814e6f0c4d476d2bfb4b42fa61415 Mon Sep 17 00:00:00 2001 From: idosun Date: Tue, 30 Jun 2020 12:39:27 -0700 Subject: [PATCH 1/9] remove sentry-cli variable values --- Makefile | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 0899320..7656659 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,7 @@ -# Must have `sentry-cli` installed globally -# Require SENTRY_AUTH_TOKEN environment variable -# SENTRY_AUTH_TOKEN= - -SENTRY_ORG=testorg-az -SENTRY_PROJECT=django-lr +SENTRY_AUTH_TOKEN= +SENTRY_ORG= +SENTRY_PROJECT= VERSION=`sentry-cli releases propose-version` -REPO=sentry-demos/django deploy: install create_release associate_commits run_django @@ -17,7 +13,7 @@ create_release: associate_commits: sentry-cli releases -o $(SENTRY_ORG) -p $(SENTRY_PROJECT) \ - set-commits $(VERSION) --commit "$(REPO)@$(VERSION)" + set-commits $(VERSION) --auto run_django: VERSION=$(VERSION) python manage.py runserver From 8cb43f1c9b37465ce1a1c8fece10221e419b1acd Mon Sep 17 00:00:00 2001 From: idosun Date: Tue, 30 Jun 2020 14:47:09 -0700 Subject: [PATCH 2/9] update sentry sdk version --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d2afe0a..0fe5fb4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ Django==2.2.3 -sentry-sdk==0.10.2 +sentry-sdk==0.15.1 djangorestframework==3.10.0 django-cors-headers==3.0.2 From 7e2d82314a6f54553c1218d07baefa1b50543239 Mon Sep 17 00:00:00 2001 From: Lovepreet Sangha Date: Wed, 1 Jul 2020 16:16:09 -0700 Subject: [PATCH 3/9] added endpoint for messages and breadcrumbs --- myapp/urls.py | 3 ++- myapp/views.py | 24 +++++++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/myapp/urls.py b/myapp/urls.py index 2e2588e..c1e346a 100644 --- a/myapp/urls.py +++ b/myapp/urls.py @@ -1,11 +1,12 @@ from django.urls import path, include from rest_framework import routers, serializers, viewsets -from .views import InventoreyView, HandledErrorView, UnHandledErrorView +from .views import InventoreyView, HandledErrorView, UnHandledErrorView, CaptureMessageView urlpatterns = [ path('checkout', InventoreyView.as_view()), path('handled', HandledErrorView.as_view()), path('unhandled', UnHandledErrorView.as_view()), + path('message', CaptureMessageView.as_view()), ] diff --git a/myapp/views.py b/myapp/views.py index ace1dcd..52f3585 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -78,9 +78,11 @@ def post(self, request, format=None): class HandledErrorView(APIView): def get(self, request): - -# Comment out the code below to set up capture_message -# sentry_sdk.capture_message("You caught me") + add_breadcrumb( + category='handled', + message='In the handled function', + level='error', + ) try: '2' + 2 except Exception as err: @@ -89,7 +91,23 @@ def get(self, request): class UnHandledErrorView(APIView): def get(self, request): + add_breadcrumb( + category='unhandled', + message='In the unhandled function', + level='error', + ) obj = {} obj['keyDoesntExist'] return Response() +class CaptureMessageView(APIView): + def get(self, request): + add_breadcrumb( + category='message', + message='In the Capture Message function', + level='error', + ) + sentry_sdk.capture_message("You caught me!") + return Response() + + From 87ce5198fa3afcd1a357d34e50e67e3987b8db0f Mon Sep 17 00:00:00 2001 From: idosun Date: Wed, 8 Jul 2020 11:19:55 -0700 Subject: [PATCH 4/9] change allowed hosts settings --- myapp/views.py | 6 +++--- myproject/settings.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/myapp/views.py b/myapp/views.py index ace1dcd..b06d697 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -21,9 +21,9 @@ def find_in_inventory(itemId): def process_order(cart): add_breadcrumb( - category='Process Order', - message='Step taken to process an order', - level='error', + category='Process Order', + message='Step taken to process an order', + level='info', ) global InventoryData tempInventory = InventoryData diff --git a/myproject/settings.py b/myproject/settings.py index 3cf166a..31fafdf 100644 --- a/myproject/settings.py +++ b/myproject/settings.py @@ -25,7 +25,7 @@ # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['dev.getsentry.net', 'localhost'] # Application definition From 135fe289c0b1a5b444baa134b12cbf32c69cc79e Mon Sep 17 00:00:00 2001 From: idosun Date: Thu, 9 Jul 2020 18:04:56 -0700 Subject: [PATCH 5/9] change breadcrumb categories and level --- myapp/views.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/myapp/views.py b/myapp/views.py index 5b80b4e..d137cb5 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -79,9 +79,9 @@ def post(self, request, format=None): class HandledErrorView(APIView): def get(self, request): add_breadcrumb( - category='handled', - message='In the handled function', - level='error', + category='URL Endpoints', + message='In the handled function', + level='info', ) try: '2' + 2 @@ -92,9 +92,9 @@ def get(self, request): class UnHandledErrorView(APIView): def get(self, request): add_breadcrumb( - category='unhandled', - message='In the unhandled function', - level='error', + category='URL Endpoints', + message='In the unhandled function', + level='info', ) obj = {} obj['keyDoesntExist'] @@ -103,11 +103,15 @@ def get(self, request): class CaptureMessageView(APIView): def get(self, request): add_breadcrumb( - category='message', - message='In the Capture Message function', - level='error', + category='URL Endpoints', + message='In the Capture Message function', + level='info', ) sentry_sdk.capture_message("You caught me!") + return Response() + + + From 1ad40bc49d67ea6539cca2061af84f89994dd0af Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 26 Jul 2024 14:42:26 +0200 Subject: [PATCH 6/9] Updated Django version and readme --- .gitignore | 2 + README.md | 64 ++++++++++++------------------ myapp/{init.py => __init__.py} | 0 myapp/views.py | 50 +++++++++++------------ myproject/{init.py => __init__.py} | 0 myproject/settings.py | 13 +++--- requirements.txt | 8 ++-- 7 files changed, 63 insertions(+), 74 deletions(-) rename myapp/{init.py => __init__.py} (100%) rename myproject/{init.py => __init__.py} (100%) diff --git a/.gitignore b/.gitignore index 024a092..39189a7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ migrations/ db.sqlite3 .vscode .DS_Store +.venv/ +.python-version \ No newline at end of file diff --git a/README.md b/README.md index 4d25e97..7d52ef3 100644 --- a/README.md +++ b/README.md @@ -4,35 +4,37 @@ - [Running The Demo](#running-the-demo) - [Cleaning Up](#cleaning-up) + ## Installing Dependencies This project uses Django 2.2 that requires Python 3 -1. Install Python 3: -``` -brew install python3 +1. Install Python: +```bash +brew install python ``` -2. Install `virtualenv` and `virtualenvwrapper` +2. Create virtual environment +```bash +python -m venv .venv ``` -pip3 install virtualenv virtualenvwrapper -echo "source /usr/local/bin/virtualenvwrapper.sh" >> ~/.bashrc -exec bash + +3. Activate virtual environment +```bash +source .venv/bin/activate ``` 3. Install Sentry's command line tool to use release tracking and Github integration for commit data: -``` -npm install -g @sentry/cli +```bash +python -m pip install "sentry-cli" ``` -This demo uses npm, pip, and virtualenv. ## Configuring Sentry -The Sentry client library requires a [DSN generated from Sentry](https://docs.sentry.io/quickstart/#configure-the-dsn) which specifies the project events will be sent to. Add the import and configuration code to `settings.py`: +The Sentry client library requires a [DSN generated from Sentry](https://docs.sentry.io/quickstart/#configure-the-dsn) which specifies the project events will be sent to. Add the import and configuration code to `settings.py`: - ``` +```python import sentry_sdk -from sentry_sdk.integrations.django import DjangoIntegration sentry_sdk.init( dsn="https://yourdsn@sentry.io/1234567" @@ -41,27 +43,12 @@ sentry_sdk.init( Further details on configuring Sentry [here](https://docs.sentry.io/platforms/python/django/). -## Running The Demo - -Create a python-3 virtualenv (see below) and run `deploy` target in `Makefile`. - -### Virtualenv setup - -Setup and activate a Python 3 virtual environment in the project root: -``` -mkvirtualenv --python=python3 sentry-demo-django -``` - -To use virtualenv: -``` -workon sentry-demo-django -``` +## Running The Demo -### Runing Django +Run `deploy` target in `Makefile`. This will install relevant python libraries and run Django server. -Running the following command will install relevant python libraries and run django server -``` +```bash make deploy ``` @@ -69,13 +56,13 @@ make deploy ### Demo Specs This demo uses Django's rest-framework package and offers 3 API endpoints: -1. http://localhost:8000/handled - generates a runtime error excplicitly reported to Sentry though the SDk's captureException +1. http://localhost:8000/handled - generates a runtime error explicitly reported to Sentry though the SDK's `captureException` 2. http://localhost:8000/unhandled - generates an unhandled runtime error reported 3. http://localhost:8000/checkout - can be used with the [Sentry REACT demo store front demo](https://github.com/sentry-demos/react) This endpoint can also be used with directly through the Django REST Framework web UI. To generate an error paste the following JSON payload in the POST payload text area: -``` +```json { "cart": [ {"id": "wrench", "name": "Wrench", "price": 500}, @@ -87,16 +74,17 @@ This demo uses Django's rest-framework package and offers 3 API endpoints: ![Alt Text](django_demo_setup.gif) + ## Cleaning Up Pressing Ctrl-C once in each terminal window should stop Django's development server. -To deactivate the virtualenv sentry-demo-django: -``` +To deactivate the virtual environment: +```bash deactivate ``` -To remove the virtualenv: -``` -rmvirtualenv sentry-demo-django +To remove the virtual environment: +```bash +rm -rf .venv/ ``` diff --git a/myapp/init.py b/myapp/__init__.py similarity index 100% rename from myapp/init.py rename to myapp/__init__.py diff --git a/myapp/views.py b/myapp/views.py index d137cb5..601352c 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -1,17 +1,20 @@ -from __future__ import unicode_literals - -import sentry_sdk import json + from rest_framework.response import Response from rest_framework.views import APIView from .serializers import InventorySerializer from .models import Inventory -from sentry_sdk import add_breadcrumb -InventoryData = [{"name": "wrench", "count": 1}, - {"name": "nails", "count": 1}, - {"name": "hammer", "count": 1}] +import sentry_sdk + + +InventoryData = [ + {"name": "wrench", "count": 1}, + {"name": "nails", "count": 1}, + {"name": "hammer", "count": 1}, +] + def find_in_inventory(itemId): for item in InventoryData: @@ -19,8 +22,9 @@ def find_in_inventory(itemId): return item raise Exception("Item : " + itemId + " not in inventory ") + def process_order(cart): - add_breadcrumb( + sentry_sdk.add_breadcrumb( category='Process Order', message='Step taken to process an order', level='info', @@ -31,12 +35,13 @@ def process_order(cart): itemID = item['id'] inventoryItem = find_in_inventory(itemID) if inventoryItem['count'] <= 0: - raise Exception("Not enough inventory for " + itemID) + raise Exception("Not enough inventory for " + itemID) else: inventoryItem['count'] -= 1 print( 'Success: ' + itemID + ' was purchased, remaining stock is ' + str(inventoryItem['count']) ) InventoryData = tempInventory + class SentryContextMixin(object): def dispatch(self, request, *args, **kwargs): @@ -46,9 +51,9 @@ def dispatch(self, request, *args, **kwargs): with sentry_sdk.configure_scope() as scope: scope.user = { "email" : order["email"] } - + transactionId = request.headers.get('X-Transaction-ID') - + global InventoryData with sentry_sdk.configure_scope() as scope: @@ -60,7 +65,7 @@ def dispatch(self, request, *args, **kwargs): return super(SentryContextMixin, self).dispatch(request, *args, **kwargs) -# Create your views here. + class InventoreyView(SentryContextMixin, APIView): def get(self, request): @@ -73,16 +78,16 @@ def post(self, request, format=None): order = json.loads(body_unicode) cart = order['cart'] process_order(cart) - return Response(InventoryData) + return Response(InventoryData) class HandledErrorView(APIView): def get(self, request): - add_breadcrumb( + sentry_sdk.add_breadcrumb( category='URL Endpoints', message='In the handled function', level='info', - ) + ) try: '2' + 2 except Exception as err: @@ -91,27 +96,22 @@ def get(self, request): class UnHandledErrorView(APIView): def get(self, request): - add_breadcrumb( + sentry_sdk.add_breadcrumb( category='URL Endpoints', message='In the unhandled function', level='info', - ) + ) obj = {} obj['keyDoesntExist'] return Response() class CaptureMessageView(APIView): def get(self, request): - add_breadcrumb( + sentry_sdk.add_breadcrumb( category='URL Endpoints', message='In the Capture Message function', level='info', - ) - sentry_sdk.capture_message("You caught me!") + ) + sentry_sdk.capture_message("You caught me!", "fatal") return Response() - - - - - diff --git a/myproject/init.py b/myproject/__init__.py similarity index 100% rename from myproject/init.py rename to myproject/__init__.py diff --git a/myproject/settings.py b/myproject/settings.py index 31fafdf..185fcd1 100644 --- a/myproject/settings.py +++ b/myproject/settings.py @@ -43,29 +43,28 @@ # Import configure and initialize Sentry SDK import sentry_sdk -from sentry_sdk.integrations.django import DjangoIntegration sentry_sdk.init( - dsn="YOUR_DSN", - integrations=[DjangoIntegration()], + dsn="https://d655584d05f14c58b86e9034aab6817f@o447951.ingest.us.sentry.io/5461230", release=os.environ.get("VERSION"), - environment="Production" + environment="Production", + # Set traces_sample_rate to 1.0 to capture 100% of traces. + # We recommend adjusting this value in production. + traces_sample_rate=1.0, ) MIDDLEWARE = [ - 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', - 'corsheaders.middleware.CorsPostCsrfMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] #Configuration for 'corsheaders.middleware.CorsMiddleware' CORS_ORIGIN_ALLOW_ALL = True -CORS_REPLACE_HTTPS_REFERER = True from corsheaders.defaults import default_headers diff --git a/requirements.txt b/requirements.txt index 0fe5fb4..768991f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django==2.2.3 -sentry-sdk==0.15.1 -djangorestframework==3.10.0 -django-cors-headers==3.0.2 +Django==5.0.7 +sentry-sdk==2.11.0 +djangorestframework==3.15.2 +django-cors-headers==4.4.0 From 4094bd2bb04e60c1dd87984a400647b255cd0a7d Mon Sep 17 00:00:00 2001 From: Anton Pirker Date: Fri, 26 Jul 2024 15:22:48 +0200 Subject: [PATCH 7/9] Formatted with black --- manage.py | 4 +- myapp/apps.py | 2 +- myapp/models.py | 3 +- myapp/urls.py | 15 +++++--- myapp/views.py | 66 +++++++++++++++++--------------- myproject/settings.py | 87 +++++++++++++++++++++---------------------- myproject/urls.py | 3 +- myproject/wsgi.py | 2 +- 8 files changed, 97 insertions(+), 85 deletions(-) diff --git a/manage.py b/manage.py index 6bb3761..95fb3d1 100644 --- a/manage.py +++ b/manage.py @@ -5,7 +5,7 @@ def main(): - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: @@ -17,5 +17,5 @@ def main(): execute_from_command_line(sys.argv) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/myapp/apps.py b/myapp/apps.py index 74d6d13..c976c37 100644 --- a/myapp/apps.py +++ b/myapp/apps.py @@ -2,4 +2,4 @@ class MyappConfig(AppConfig): - name = 'myapp' + name = "myapp" diff --git a/myapp/models.py b/myapp/models.py index e018d4e..26890a4 100644 --- a/myapp/models.py +++ b/myapp/models.py @@ -2,8 +2,9 @@ # Create your models here. + class Inventory(models.Model): - name = models.TextField(), + name = models.TextField() count = models.IntegerField() def __str__(self): diff --git a/myapp/urls.py b/myapp/urls.py index c1e346a..805b6e6 100644 --- a/myapp/urls.py +++ b/myapp/urls.py @@ -1,12 +1,17 @@ from django.urls import path, include from rest_framework import routers, serializers, viewsets -from .views import InventoreyView, HandledErrorView, UnHandledErrorView, CaptureMessageView +from .views import ( + InventoreyView, + HandledErrorView, + UnHandledErrorView, + CaptureMessageView, +) urlpatterns = [ - path('checkout', InventoreyView.as_view()), - path('handled', HandledErrorView.as_view()), - path('unhandled', UnHandledErrorView.as_view()), - path('message', CaptureMessageView.as_view()), + path("checkout", InventoreyView.as_view()), + path("handled", HandledErrorView.as_view()), + path("unhandled", UnHandledErrorView.as_view()), + path("message", CaptureMessageView.as_view()), ] diff --git a/myapp/views.py b/myapp/views.py index 601352c..d487e65 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -12,55 +12,60 @@ InventoryData = [ {"name": "wrench", "count": 1}, {"name": "nails", "count": 1}, - {"name": "hammer", "count": 1}, + {"name": "hammer", "count": 1}, ] def find_in_inventory(itemId): for item in InventoryData: - if item['name'] == itemId: + if item["name"] == itemId: return item raise Exception("Item : " + itemId + " not in inventory ") def process_order(cart): sentry_sdk.add_breadcrumb( - category='Process Order', - message='Step taken to process an order', - level='info', + category="Process Order", + message="Step taken to process an order", + level="info", ) global InventoryData tempInventory = InventoryData for item in cart: - itemID = item['id'] + itemID = item["id"] inventoryItem = find_in_inventory(itemID) - if inventoryItem['count'] <= 0: + if inventoryItem["count"] <= 0: raise Exception("Not enough inventory for " + itemID) else: - inventoryItem['count'] -= 1 - print( 'Success: ' + itemID + ' was purchased, remaining stock is ' + str(inventoryItem['count']) ) + inventoryItem["count"] -= 1 + print( + "Success: " + + itemID + + " was purchased, remaining stock is " + + str(inventoryItem["count"]) + ) InventoryData = tempInventory class SentryContextMixin(object): def dispatch(self, request, *args, **kwargs): - if (request.body): - body_unicode = request.body.decode('utf-8') + if request.body: + body_unicode = request.body.decode("utf-8") order = json.loads(body_unicode) with sentry_sdk.configure_scope() as scope: - scope.user = { "email" : order["email"] } + scope.user = {"email": order["email"]} - transactionId = request.headers.get('X-Transaction-ID') + transactionId = request.headers.get("X-Transaction-ID") global InventoryData with sentry_sdk.configure_scope() as scope: - if(transactionId): + if transactionId: scope.set_tag("transaction_id", transactionId) - if(Inventory): + if Inventory: scope.set_extra("inventory", InventoryData) return super(SentryContextMixin, self).dispatch(request, *args, **kwargs) @@ -72,11 +77,10 @@ def get(self, request): results = InventorySerializer(InventoryData, many=True).data return Response(results) - def post(self, request, format=None): - body_unicode = request.body.decode('utf-8') + body_unicode = request.body.decode("utf-8") order = json.loads(body_unicode) - cart = order['cart'] + cart = order["cart"] process_order(cart) return Response(InventoryData) @@ -84,33 +88,35 @@ def post(self, request, format=None): class HandledErrorView(APIView): def get(self, request): sentry_sdk.add_breadcrumb( - category='URL Endpoints', - message='In the handled function', - level='info', + category="URL Endpoints", + message="In the handled function", + level="info", ) try: - '2' + 2 + "2" + 2 except Exception as err: sentry_sdk.capture_exception(err) return Response() + class UnHandledErrorView(APIView): - def get(self, request): + def get(self, request): sentry_sdk.add_breadcrumb( - category='URL Endpoints', - message='In the unhandled function', - level='info', + category="URL Endpoints", + message="In the unhandled function", + level="info", ) obj = {} - obj['keyDoesntExist'] + obj["keyDoesntExist"] return Response() + class CaptureMessageView(APIView): def get(self, request): sentry_sdk.add_breadcrumb( - category='URL Endpoints', - message='In the Capture Message function', - level='info', + category="URL Endpoints", + message="In the Capture Message function", + level="info", ) sentry_sdk.capture_message("You caught me!", "fatal") diff --git a/myproject/settings.py b/myproject/settings.py index 185fcd1..39e1530 100644 --- a/myproject/settings.py +++ b/myproject/settings.py @@ -20,25 +20,24 @@ # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'h0z^7km9#o2w@eig&z9f-bso6tks@$q*ho#39o&l0z)aux_2t^' +SECRET_KEY = "h0z^7km9#o2w@eig&z9f-bso6tks@$q*ho#39o&l0z)aux_2t^" # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = ['dev.getsentry.net', 'localhost'] +ALLOWED_HOSTS = ["dev.getsentry.net", "localhost"] # Application definition INSTALLED_APPS = [ - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - - 'myapp', - 'rest_framework', - 'corsheaders', + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "myapp", + "rest_framework", + "corsheaders", ] # Import configure and initialize Sentry SDK @@ -48,51 +47,51 @@ dsn="https://d655584d05f14c58b86e9034aab6817f@o447951.ingest.us.sentry.io/5461230", release=os.environ.get("VERSION"), environment="Production", - # Set traces_sample_rate to 1.0 to capture 100% of traces. + # Set traces_sample_rate to 1.0 to capture 100% of traces. # We recommend adjusting this value in production. traces_sample_rate=1.0, ) MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'corsheaders.middleware.CorsMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -#Configuration for 'corsheaders.middleware.CorsMiddleware' +# Configuration for 'corsheaders.middleware.CorsMiddleware' CORS_ORIGIN_ALLOW_ALL = True from corsheaders.defaults import default_headers CORS_ALLOW_HEADERS = list(default_headers) + [ - 'X-Transaction-ID', - 'X-Session-ID', + "X-Transaction-ID", + "X-Session-ID", ] -ROOT_URLCONF = 'myproject.urls' +ROOT_URLCONF = "myproject.urls" REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. - 'DEFAULT_AUTHENTICATION_CLASSES': [], - 'DEFAULT_PERMISSION_CLASSES': [], - 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', - 'UNAUTHENTICATED_USER': None + "DEFAULT_AUTHENTICATION_CLASSES": [], + "DEFAULT_PERMISSION_CLASSES": [], + "EXCEPTION_HANDLER": "rest_framework.views.exception_handler", + "UNAUTHENTICATED_USER": None, } TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", #'django.contrib.auth.context_processors.auth', #'django.contrib.messages.context_processors.messages', ], @@ -100,16 +99,16 @@ }, ] -WSGI_APPLICATION = 'myproject.wsgi.application' +WSGI_APPLICATION = "myproject.wsgi.application" # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": os.path.join(BASE_DIR, "db.sqlite3"), } } @@ -119,16 +118,16 @@ AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -136,9 +135,9 @@ # Internationalization # https://docs.djangoproject.com/en/2.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -150,4 +149,4 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ -STATIC_URL = '/static/' +STATIC_URL = "/static/" diff --git a/myproject/urls.py b/myproject/urls.py index a20d14c..5a57641 100644 --- a/myproject/urls.py +++ b/myproject/urls.py @@ -13,8 +13,9 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.urls import path, include urlpatterns = [ - path(r'', include('myapp.urls')), + path(r"", include("myapp.urls")), ] diff --git a/myproject/wsgi.py b/myproject/wsgi.py index 8ec7b23..c130bcc 100644 --- a/myproject/wsgi.py +++ b/myproject/wsgi.py @@ -11,6 +11,6 @@ from django.core.wsgi import get_wsgi_application -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings') +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproject.settings") application = get_wsgi_application() From 0b37bf31a67a49ae678f59edd28ce2d55a49c01d Mon Sep 17 00:00:00 2001 From: kpujjigit <103009467+kpujjigit@users.noreply.github.com> Date: Fri, 14 Mar 2025 15:05:13 -0700 Subject: [PATCH 8/9] Includes update to SDK version, enabling profiling --- myapp/views.py | 77 +++++++++++++++++++++++++++++++++---------- myproject/settings.py | 17 +++++++--- 2 files changed, 71 insertions(+), 23 deletions(-) diff --git a/myapp/views.py b/myapp/views.py index d487e65..5cad5fa 100644 --- a/myapp/views.py +++ b/myapp/views.py @@ -7,6 +7,8 @@ from .models import Inventory import sentry_sdk +from sentry_sdk import capture_message, set_context, set_tag, set_user +from django.http import JsonResponse InventoryData = [ @@ -54,19 +56,34 @@ def dispatch(self, request, *args, **kwargs): body_unicode = request.body.decode("utf-8") order = json.loads(body_unicode) - with sentry_sdk.configure_scope() as scope: - scope.user = {"email": order["email"]} + # Enhanced user context + user_data = { + "email": order.get("email"), + "ip_address": request.META.get("REMOTE_ADDR"), + "user_agent": request.META.get("HTTP_USER_AGENT"), + } + set_user(user_data) transactionId = request.headers.get("X-Transaction-ID") - - global InventoryData - - with sentry_sdk.configure_scope() as scope: - if transactionId: - scope.set_tag("transaction_id", transactionId) - - if Inventory: - scope.set_extra("inventory", InventoryData) + sessionId = request.headers.get("X-Session-ID") + + # Enhanced context and tags + set_context("request_metadata", { + "transaction_id": transactionId, + "session_id": sessionId, + "http_method": request.method, + "path": request.path, + }) + + set_tag("transaction_type", "inventory") + if sessionId: + set_tag("session_id", sessionId) + + # Add inventory state to context + set_context("inventory_state", { + "current_inventory": InventoryData, + "total_items": sum(item["count"] for item in InventoryData) + }) return super(SentryContextMixin, self).dispatch(request, *args, **kwargs) @@ -74,15 +91,39 @@ def dispatch(self, request, *args, **kwargs): class InventoreyView(SentryContextMixin, APIView): def get(self, request): - results = InventorySerializer(InventoryData, many=True).data - return Response(results) + try: + results = InventorySerializer(InventoryData, many=True).data + return Response(results) + except Exception as e: + sentry_sdk.capture_exception(e) + return Response({"error": "Failed to fetch inventory"}, status=500) def post(self, request, format=None): - body_unicode = request.body.decode("utf-8") - order = json.loads(body_unicode) - cart = order["cart"] - process_order(cart) - return Response(InventoryData) + try: + body_unicode = request.body.decode("utf-8") + order = json.loads(body_unicode) + cart = order["cart"] + + # Add order context + set_context("order_details", { + "cart_items": len(cart), + "order_total": sum(item.get("quantity", 1) for item in cart) + }) + + process_order(cart) + return Response(InventoryData) + except Exception as e: + sentry_sdk.capture_exception(e) + + # Return error with user feedback form + event_id = sentry_sdk.last_event_id() + return JsonResponse({ + "error": str(e), + "sentry": { + "event_id": event_id, + "dsn": "https://d655584d05f14c58b86e9034aab6817f@o447951.ingest.us.sentry.io/5461230" + } + }, status=500) class HandledErrorView(APIView): diff --git a/myproject/settings.py b/myproject/settings.py index 39e1530..ede8bce 100644 --- a/myproject/settings.py +++ b/myproject/settings.py @@ -11,6 +11,10 @@ """ import os +import sentry_sdk +from sentry_sdk.integrations.django import DjangoIntegration +from sentry_sdk.integrations.logging import LoggingIntegration +import logging # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -41,15 +45,18 @@ ] # Import configure and initialize Sentry SDK -import sentry_sdk - sentry_sdk.init( dsn="https://d655584d05f14c58b86e9034aab6817f@o447951.ingest.us.sentry.io/5461230", - release=os.environ.get("VERSION"), environment="Production", - # Set traces_sample_rate to 1.0 to capture 100% of traces. - # We recommend adjusting this value in production. traces_sample_rate=1.0, + integrations=[ + DjangoIntegration(), + LoggingIntegration( + level=logging.INFO, + event_level=logging.ERROR + ), + ], + send_default_pii=True ) MIDDLEWARE = [ From 89a4d5bc8938a9de12422222081adc8f6e53440b Mon Sep 17 00:00:00 2001 From: kpujjigit <103009467+kpujjigit@users.noreply.github.com> Date: Mon, 17 Mar 2025 09:15:34 -0700 Subject: [PATCH 9/9] Includes update to SDK version, enabling profiling --- myproject/settings.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/myproject/settings.py b/myproject/settings.py index ede8bce..3dca2ea 100644 --- a/myproject/settings.py +++ b/myproject/settings.py @@ -47,16 +47,29 @@ # Import configure and initialize Sentry SDK sentry_sdk.init( dsn="https://d655584d05f14c58b86e9034aab6817f@o447951.ingest.us.sentry.io/5461230", + release=os.environ.get("VERSION"), environment="Production", + + # Enable performance monitoring traces_sample_rate=1.0, + profiles_sample_rate=1.0, + + # Configure integrations integrations=[ - DjangoIntegration(), + DjangoIntegration( + transaction_style='url', + middleware_spans=True, + signals_spans=True, + ), LoggingIntegration( level=logging.INFO, event_level=logging.ERROR ), ], - send_default_pii=True + + # Enable request bodies in error reports + send_default_pii=True, + ) MIDDLEWARE = [