From 37f06bb5cba27c9b512452866dc35756c3c89fd6 Mon Sep 17 00:00:00 2001 From: Tim McCormack Date: Fri, 7 Mar 2025 14:33:28 +0000 Subject: [PATCH 1/2] fix: Allow newrelic import to fail We should remove newrelic references entirely and replace them with edx-django-utils calls. This change just unblocks removing newrelic as a direct dependency. --- notesapi/v1/views/common.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/notesapi/v1/views/common.py b/notesapi/v1/views/common.py index 0e4e308a..3ea279da 100644 --- a/notesapi/v1/views/common.py +++ b/notesapi/v1/views/common.py @@ -1,7 +1,6 @@ # pylint:disable=possibly-used-before-assignment import json import logging -import newrelic.agent from django.conf import settings from django.core.exceptions import ValidationError from django.db.models import Q @@ -12,6 +11,11 @@ from rest_framework.response import Response from rest_framework.views import APIView +try: + import newrelic.agent +except ImportError: # pragma: no cover + newrelic = None # pylint: disable=invalid-name + from notesapi.v1.models import Note from notesapi.v1.serializers import NoteSerializer @@ -399,7 +403,8 @@ def post(self, *args, **kwargs): note.full_clean() # Gather metrics for New Relic so we can slice data in New Relic Insights - newrelic.agent.add_custom_parameter("notes.count", total_notes) + if newrelic: # pragma: no cover + newrelic.agent.add_custom_parameter("notes.count", total_notes) except ValidationError as error: log.debug(error, exc_info=True) return Response(status=status.HTTP_400_BAD_REQUEST) From b0375999ad9591ad7a3e4a769f8794e33db60b5a Mon Sep 17 00:00:00 2001 From: Tim McCormack Date: Mon, 10 Mar 2025 14:27:31 +0000 Subject: [PATCH 2/2] fix: Use edx-django-utils API instead of calling newrelic directly These changes will cause telemetry to start being reported when annotations are created. (No change for whether notesserver heartbeat calls emit telemetry, as that is currently only supported for New Relic anyhow.) This also removes the newrelic dependency, though it is still pulled in by edx-django-utils indirectly, for now. --- notesapi/v1/views/common.py | 11 +++-------- notesserver/views.py | 9 ++------- requirements/base.in | 1 - requirements/base.txt | 4 +--- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/notesapi/v1/views/common.py b/notesapi/v1/views/common.py index 3ea279da..944c82d5 100644 --- a/notesapi/v1/views/common.py +++ b/notesapi/v1/views/common.py @@ -1,21 +1,18 @@ # pylint:disable=possibly-used-before-assignment import json import logging + from django.conf import settings from django.core.exceptions import ValidationError from django.db.models import Q from django.urls import reverse from django.utils.translation import gettext as _ +from edx_django_utils.monitoring import set_custom_attribute from rest_framework import status from rest_framework.generics import GenericAPIView, ListAPIView from rest_framework.response import Response from rest_framework.views import APIView -try: - import newrelic.agent -except ImportError: # pragma: no cover - newrelic = None # pylint: disable=invalid-name - from notesapi.v1.models import Note from notesapi.v1.serializers import NoteSerializer @@ -402,9 +399,7 @@ def post(self, *args, **kwargs): note = Note.create(self.request.data) note.full_clean() - # Gather metrics for New Relic so we can slice data in New Relic Insights - if newrelic: # pragma: no cover - newrelic.agent.add_custom_parameter("notes.count", total_notes) + set_custom_attribute("notes.count", total_notes) except ValidationError as error: log.debug(error, exc_info=True) return Response(status=status.HTTP_400_BAD_REQUEST) diff --git a/notesserver/views.py b/notesserver/views.py index bf2026fb..795113bb 100644 --- a/notesserver/views.py +++ b/notesserver/views.py @@ -4,16 +4,12 @@ from django.db import connection from django.http import JsonResponse from django.http import HttpResponse +from edx_django_utils.monitoring import ignore_transaction from rest_framework import status from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import AllowAny from rest_framework.response import Response -try: - import newrelic.agent -except ImportError: # pragma: no cover - newrelic = None # pylint: disable=invalid-name - from notesapi.v1.views import get_annotation_search_view_class from notesapi.v1.views import SearchViewRuntimeError @@ -45,8 +41,7 @@ def heartbeat(request): """ ElasticSearch and database are reachable and ready to handle requests. """ - if newrelic: # pragma: no cover - newrelic.agent.ignore_transaction() + ignore_transaction() # no need to record telemetry for heartbeats try: db_status() except Exception: # pylint: disable=broad-exception-caught diff --git a/requirements/base.in b/requirements/base.in index 0a9b7105..8be8c0bc 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -16,7 +16,6 @@ PyJWT gunicorn # MIT path.py python-dateutil -newrelic edx-django-release-util edx-django-utils edx-drf-extensions diff --git a/requirements/base.txt b/requirements/base.txt index 2951410f..74a32629 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -109,9 +109,7 @@ meilisearch==0.34.0 mysqlclient==2.2.7 # via -r requirements/base.in newrelic==10.7.0 - # via - # -r requirements/base.in - # edx-django-utils + # via edx-django-utils packaging==24.2 # via # django-nine