From 925f820bfdd0f7106490fff0e1d0a7fda66e19c1 Mon Sep 17 00:00:00 2001 From: ITQ Date: Thu, 24 Jul 2025 16:57:47 +0300 Subject: [PATCH] feat(backend): added profiling --- services/backend/.gitignore | 3 ++ services/backend/api/v1/ads/views.py | 2 ++ services/backend/config/settings.py | 50 ++++++++++++++++++++++++++++ services/backend/config/urls.py | 2 ++ services/backend/profiles/.gitkeep | 0 services/backend/pyproject.toml | 1 + services/backend/scripts/initdb | 1 + 7 files changed, 59 insertions(+) create mode 100644 services/backend/profiles/.gitkeep diff --git a/services/backend/.gitignore b/services/backend/.gitignore index 657dc4c..06c050f 100644 --- a/services/backend/.gitignore +++ b/services/backend/.gitignore @@ -171,3 +171,6 @@ cython_debug/ # Collected static files static + +# Profile files +*.prof diff --git a/services/backend/api/v1/ads/views.py b/services/backend/api/v1/ads/views.py index b1ced08..07424fc 100644 --- a/services/backend/api/v1/ads/views.py +++ b/services/backend/api/v1/ads/views.py @@ -4,6 +4,7 @@ from uuid import UUID from django.http import Http404, HttpRequest from django.shortcuts import get_object_or_404 from ninja import Router +from silk.profiling.profiler import silk_profile from api.v1 import schemas as global_schemas from api.v1.ads import schemas @@ -21,6 +22,7 @@ router = Router(tags=["ads"]) status.NOT_FOUND: global_schemas.NotFoundError, }, ) +@silk_profile("Get Advertisment") def get_advertisment( request: HttpRequest, client_id: UUID ) -> tuple[status, Campaign]: diff --git a/services/backend/config/settings.py b/services/backend/config/settings.py index 3e02f5f..55e46ed 100644 --- a/services/backend/config/settings.py +++ b/services/backend/config/settings.py @@ -4,6 +4,7 @@ import contextlib import logging from collections.abc import Callable from pathlib import Path +from typing import TYPE_CHECKING import django_stubs_ext import environ @@ -12,6 +13,10 @@ from health_check.plugins import plugin_dir from integrations.yandexai.healthcheck import YandexAIHealthCheck +if TYPE_CHECKING: + from django.contrib.auth.models import User + + BASE_DIR = Path(__file__).resolve().parent.parent env = environ.Env() @@ -287,6 +292,7 @@ INTERNAL_IPS = env( ) MIDDLEWARE = [ + "silk.middleware.SilkyMiddleware", "django_prometheus.middleware.PrometheusBeforeMiddleware", "django_guid.middleware.guid_middleware", "corsheaders.middleware.CorsMiddleware", @@ -450,6 +456,7 @@ INSTALLED_APPS = [ "django_prometheus", "ninja", "minio_storage", + "silk", # Internal apps "apps.core", "apps.advertiser", @@ -522,6 +529,13 @@ SECRET_KEY = env("DJANGO_SECRET_KEY", default="very_insecure_key") SECRET_KEY_FALLBACKS: list[str] = [] +# Auth + +LOGIN_REDIRECT_URL = "/admin/" + +LOGIN_URL = "/admin/" + + # Sessions SESSION_CACHE_ALIAS = "default" @@ -624,3 +638,39 @@ PROMETHEUS_LATENCY_BUCKETS = ( 75.0, float("inf"), ) + + +# django-silk + +SILKY_PYTHON_PROFILER = True + +SILKY_PYTHON_PROFILER_BINARY = True + +SILKY_PYTHON_PROFILER_RESULT_PATH = "./profiles" + +SILKY_PYTHON_PROFILER_EXTENDED_FILE_NAME = True + +SILKY_AUTHENTICATION = True + +SILKY_AUTHORISATION = True + + +def is_allowed_to_use_profiling(user: "User") -> bool: + return user.is_staff + + +SILKY_PERMISSIONS = is_allowed_to_use_profiling + +SILKY_MAX_RECORDED_REQUESTS = 10**3 + +SILKY_MAX_RECORDED_REQUESTS_CHECK_PERCENT = 10 + +SILKY_MAX_REQUEST_BODY_SIZE = 128 + +SILKY_INTERCEPT_PERCENT = 25 + +SILKY_META = True + +SILKY_DYNAMIC_PROFILING = [ + {"module": "api.v1.ads.views", "function": "get_advertisment"} +] diff --git a/services/backend/config/urls.py b/services/backend/config/urls.py index de80844..4cdd0a5 100644 --- a/services/backend/config/urls.py +++ b/services/backend/config/urls.py @@ -18,6 +18,8 @@ urlpatterns = [ path("", include("api.urls")), # Prometheus urls path("", include("django_prometheus.urls")), + # Django-silk + path("silk/", include("silk.urls", namespace="silk")), ] diff --git a/services/backend/profiles/.gitkeep b/services/backend/profiles/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/services/backend/pyproject.toml b/services/backend/pyproject.toml index 7fb3c8a..4501630 100644 --- a/services/backend/pyproject.toml +++ b/services/backend/pyproject.toml @@ -11,6 +11,7 @@ dependencies = [ "django-ninja>=1.3.0,<2.0.0", "django-prometheus>=2.4.1,<3.0.0", "django-redis>=6.0.0,<7.0.0", + "django-silk[formatting]>=5.4.0,<6.0.0", "django-stubs-ext>=5.1.3,<6.0.0", "gunicorn>=23.0.0,<24.0.0", "httpx>=0.28.1,<0.29.0", diff --git a/services/backend/scripts/initdb b/services/backend/scripts/initdb index f9488d1..086d742 100755 --- a/services/backend/scripts/initdb +++ b/services/backend/scripts/initdb @@ -11,3 +11,4 @@ if [ "$DJANGO_CREATE_SUPERUSER" = "True" ]; then fi python manage.py init_cache +python manage.py silk_clear_request_log