From df571b106829b57bed8a263da497ce0d31257c72 Mon Sep 17 00:00:00 2001 From: Francisco Aranda Date: Tue, 23 Aug 2022 17:04:29 +0200 Subject: [PATCH] wip: define telemetry components --- src/rubrix/server/apis/v0/handlers/users.py | 6 +- src/rubrix/server/commons/telemetry.py | 66 +++++++++++++++++++++ src/rubrix/server/errors/api_errors.py | 3 + src/rubrix/server/settings.py | 2 + 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/rubrix/server/commons/telemetry.py diff --git a/src/rubrix/server/apis/v0/handlers/users.py b/src/rubrix/server/apis/v0/handlers/users.py index 14d5668b2b..178c503071 100644 --- a/src/rubrix/server/apis/v0/handlers/users.py +++ b/src/rubrix/server/apis/v0/handlers/users.py @@ -22,10 +22,7 @@ @router.get( - "/me", - response_model=User, - response_model_exclude_none=True, - operation_id="whoami", + "/me", response_model=User, response_model_exclude_none=True, operation_id="whoami" ) async def whoami(current_user: User = Security(auth.get_user, scopes=[])): """ @@ -41,4 +38,5 @@ async def whoami(current_user: User = Security(auth.get_user, scopes=[])): The current user """ + return current_user diff --git a/src/rubrix/server/commons/telemetry.py b/src/rubrix/server/commons/telemetry.py new file mode 100644 index 0000000000..f1ae59b797 --- /dev/null +++ b/src/rubrix/server/commons/telemetry.py @@ -0,0 +1,66 @@ +import dataclasses +import uuid +from typing import Any, Dict, Optional + +from rubrix.server.errors import RubrixServerError +from rubrix.server.services.tasks.commons import TaskType +from rubrix.server.settings import settings + + +@dataclasses.dataclass +class _TelemetryClient: + + __API_KEY__ = "C6FkcaoCbt78rACAgvyBxGBcMB3dM3nn" + + __server_id__: Optional[uuid.UUID] = dataclasses.field(init=False, default=None) + + __INSTANCE__: "_TelemetryClient" = None + + @classmethod + def get(cls): + if settings.enable_telemetry: + if cls.__INSTANCE__ is None: + cls.__INSTANCE__ = cls() + return cls.__INSTANCE__ + + def __post_init__(self): + import platform + import sys + + import analytics + + from rubrix import __version__ + + analytics.write_key = self.__API_KEY__ + self.__server_id__ = uuid.UUID(int=uuid.getnode()) + self.__system_info__ = { + "system": platform.system(), + "machine": platform.machine(), + "platform": platform.platform(), + "python_version": sys.version, + "sys_version": platform.version(), + "rubrix_version": __version__, + } + + def track_data(self, action: str, data: Dict[str, Any]): + import analytics + + analytics.track(self.__server_id__, action, {**data, **self.__system_info__}) + + +async def track_error(error: RubrixServerError): + client = _TelemetryClient.get() + if client: + client.track_data("ServerError", {"code": error.code}) + + +async def track_bulk(task: TaskType, records: int): + client = _TelemetryClient.get() + if client: + client.track_data("BulkData", {"task": task, records: records}) + + +async def track_login(): + client = _TelemetryClient.get() + if client: + client.track_data("UserLogged", {}) diff --git a/src/rubrix/server/errors/api_errors.py b/src/rubrix/server/errors/api_errors.py index 688f49828d..4b1128110c 100644 --- a/src/rubrix/server/errors/api_errors.py +++ b/src/rubrix/server/errors/api_errors.py @@ -5,6 +5,7 @@ from fastapi.exception_handlers import http_exception_handler from pydantic import BaseModel +from rubrix.server.commons import telemetry from rubrix.server.errors.adapter import exception_to_rubrix_error from rubrix.server.errors.base_errors import RubrixServerError @@ -40,6 +41,8 @@ class APIErrorHandler: async def common_exception_handler(request: Request, error: Exception): """Wraps errors as custom generic error""" rubrix_error = exception_to_rubrix_error(error) + await telemetry.track_error(rubrix_error) + return await http_exception_handler( request, RubrixServerHTTPException(rubrix_error) ) diff --git a/src/rubrix/server/settings.py b/src/rubrix/server/settings.py index 11068f38da..71644beceb 100644 --- a/src/rubrix/server/settings.py +++ b/src/rubrix/server/settings.py @@ -82,6 +82,8 @@ class ApiSettings(BaseSettings): default=50, gt=0, le=100, description="Max number of fields in metadata" ) + enable_telemetry: bool = True + @validator("disable_es_index_template_creation", always=True) def check_index_template_creation_value(cls, value):