From 4c8d47617da5619c8ddcdc1a6f52136435d2fe4d Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Sat, 23 May 2026 02:13:24 +0530 Subject: [PATCH] feat(env): add SURFSENSE_ENV variable for deployment environment and update observability resource attributes --- docker/.env.example | 5 ++++- surfsense_backend/.env.example | 5 ++++- surfsense_backend/app/observability/bootstrap.py | 13 ++++++------- .../tests/unit/observability/test_otel.py | 12 ++++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/docker/.env.example b/docker/.env.example index 2ff15e71d..748f03048 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -7,6 +7,9 @@ # SurfSense version (use "latest" or a specific version like "0.0.14") SURFSENSE_VERSION=latest +# Deployment environment: dev or production +SURFSENSE_ENV=production + # ------------------------------------------------------------------------------ # Core Settings # ------------------------------------------------------------------------------ @@ -309,7 +312,7 @@ STT_SERVICE=local/base # SURFSENSE_ENABLE_OTEL=true # OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 # OTEL_EXPORTER_OTLP_PROTOCOL=grpc -# OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production,service.namespace=surfsense +# OTEL_RESOURCE_ATTRIBUTES=service.namespace=surfsense # # Emergency kill switch. # OTEL_SDK_DISABLED=true diff --git a/surfsense_backend/.env.example b/surfsense_backend/.env.example index 91b03770e..b05369412 100644 --- a/surfsense_backend/.env.example +++ b/surfsense_backend/.env.example @@ -1,5 +1,8 @@ DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/surfsense +# Deployment environment: dev or production +SURFSENSE_ENV=dev + #Celery Config CELERY_BROKER_URL=redis://localhost:6379/0 CELERY_RESULT_BACKEND=redis://localhost:6379/0 @@ -310,7 +313,7 @@ LANGSMITH_PROJECT=surfsense # use http://otel-lgtm:4317 instead. # OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 # OTEL_EXPORTER_OTLP_PROTOCOL=grpc # or http/protobuf -# OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production,service.namespace=surfsense +# OTEL_RESOURCE_ATTRIBUTES=service.namespace=surfsense # OTEL_METRIC_EXPORT_INTERVAL=300000 # ms; 5 minutes # OTEL_SDK_DISABLED=true # emergency kill-switch diff --git a/surfsense_backend/app/observability/bootstrap.py b/surfsense_backend/app/observability/bootstrap.py index f9ed65e7b..70008d43d 100644 --- a/surfsense_backend/app/observability/bootstrap.py +++ b/surfsense_backend/app/observability/bootstrap.py @@ -55,23 +55,22 @@ def _package_version() -> str: def _deployment_environment() -> str: - return ( - os.environ.get("SURFSENSE_ENV") - or os.environ.get("APP_ENV") - or os.environ.get("ENVIRONMENT") - or "dev" - ) + return os.environ.get("SURFSENSE_ENV", "dev") def _build_resource(): from opentelemetry.sdk.resources import Resource + deployment_environment = _deployment_environment() return Resource.create( { "service.name": os.environ.get("OTEL_SERVICE_NAME", "surfsense-backend"), "service.version": _package_version(), "service.instance.id": socket.gethostname(), - "deployment.environment.name": _deployment_environment(), + "deployment.environment.name": deployment_environment, + # Compatibility alias for Grafana onboarding checks that still use + # the older semantic-convention key. + "deployment.environment": deployment_environment, } ) diff --git a/surfsense_backend/tests/unit/observability/test_otel.py b/surfsense_backend/tests/unit/observability/test_otel.py index 52ccba82f..d3718e7b9 100644 --- a/surfsense_backend/tests/unit/observability/test_otel.py +++ b/surfsense_backend/tests/unit/observability/test_otel.py @@ -114,8 +114,20 @@ class TestBootstrapConfig: attrs = dict(resource.attributes) assert attrs["service.name"] == "custom-backend" assert attrs["deployment.environment.name"] == "test" + assert attrs["deployment.environment"] == "test" assert attrs["service.instance.id"] + def test_deployment_environment_uses_surfsense_env_only( + self, monkeypatch: pytest.MonkeyPatch + ) -> None: + monkeypatch.delenv("SURFSENSE_ENV", raising=False) + + assert bootstrap._deployment_environment() == "dev" + + monkeypatch.setenv("SURFSENSE_ENV", "production") + + assert bootstrap._deployment_environment() == "production" + def test_shutdown_is_safe_without_providers(self) -> None: bootstrap.shutdown_otel()