From ef611631d094b67c78f3183226f919384d8138e8 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Fri, 17 Apr 2026 23:58:50 +0100 Subject: [PATCH 01/12] feat(OTel): add backend event catalogue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generates `docs/.../events.md` via `flagsmith docgen events` — the new subcommand shipped in Flagsmith/flagsmith-common#202. The catalogue lists every structured event the backend emits, the log level each is emitted at, its source locations, and the attributes it carries, so product and ops can curate the OTel allowlist without grepping the codebase. Wired into `make generate-docs` so the catalogue stays in sync with the source on the existing pre-commit hook — any PR that adds or changes an emit surfaces the diff in review. Points `flagsmith-common` at the PR branch for smoke testing; switch to a released version before merging. beep boop --- api/Makefile | 1 + api/poetry.lock | 81 +++--- api/pyproject.toml | 4 +- .../platform-configuration/events.md | 243 ++++++++++++++++++ 4 files changed, 288 insertions(+), 41 deletions(-) create mode 100644 docs/docs/administration-and-security/platform-configuration/events.md diff --git a/api/Makefile b/api/Makefile index d3748d0f1936..9e93284b522d 100644 --- a/api/Makefile +++ b/api/Makefile @@ -165,6 +165,7 @@ integrate-private-tests: .PHONY: generate-docs generate-docs: generate-flagsmith-sdk-openapi poetry run flagsmith docgen metrics > ../docs/docs/administration-and-security/platform-configuration/metrics.md + poetry run flagsmith docgen events > ../docs/docs/administration-and-security/platform-configuration/events.md .PHONY: add-known-sdk-version add-known-sdk-version: diff --git a/api/poetry.lock b/api/poetry.lock index caf301439f5b..4c7bf6313e7d 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "annotated-types" @@ -2058,48 +2058,52 @@ name = "flagsmith-common" version = "3.7.0" description = "Flagsmith's common library" optional = false -python-versions = "<4.0,>=3.11" +python-versions = ">=3.11,<4.0" groups = ["main", "dev", "licensing", "workflows"] -files = [ - {file = "flagsmith_common-3.7.0-py3-none-any.whl", hash = "sha256:96013812c926df779f9f960759d15607cb724656a1ccd921b923887774aa8f1b"}, - {file = "flagsmith_common-3.7.0.tar.gz", hash = "sha256:b0a87ba4d4039970b4aedb8baa207f970cf48514386be6b3874961803980b56d"}, -] - -[package.dependencies] -backoff = {version = ">=2.2.1,<3.0.0", optional = true, markers = "extra == \"task-processor\""} -django = {version = ">4,<6", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -django-health-check = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -djangorestframework = {version = "*", optional = true, markers = "extra == \"common-core\""} -djangorestframework-recursive = {version = "*", optional = true, markers = "extra == \"common-core\""} -drf-spectacular = {version = ">=0.28.0,<1", optional = true, markers = "extra == \"common-core\""} -drf-writable-nested = {version = "*", optional = true, markers = "extra == \"common-core\""} -environs = {version = "<15", optional = true, markers = "extra == \"common-core\""} -flagsmith-flag-engine = {version = ">6", optional = true, markers = "extra == \"flagsmith-schemas\""} -gunicorn = {version = ">=19.1", optional = true, markers = "extra == \"common-core\""} -inflection = {version = "*", optional = true, markers = "extra == \"common-core\""} -opentelemetry-api = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} -opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} -opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} -opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} -opentelemetry-sdk = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} -prometheus-client = {version = ">=0.0.16", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -psycopg2-binary = {version = ">=2.9,<3", optional = true, markers = "extra == \"common-core\""} -pyfakefs = {version = ">=5,<6", optional = true, markers = "extra == \"test-tools\""} -pytest-django = {version = ">=4,<5", optional = true, markers = "extra == \"test-tools\""} -redis = {version = ">=5,<6", optional = true, markers = "extra == \"common-core\""} -requests = {version = "*", optional = true, markers = "extra == \"common-core\""} -sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true, markers = "extra == \"common-core\""} -simplejson = {version = ">=3,<4", optional = true, markers = "extra == \"common-core\" and extra == \"flagsmith-schemas\""} -structlog = {version = ">=24.4,<26", optional = true, markers = "extra == \"common-core\""} -typing-extensions = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"flagsmith-schemas\""} +files = [] +develop = false + +[package.dependencies] +backoff = {version = ">=2.2.1,<3.0.0", optional = true} +django = {version = ">4,<6", optional = true} +django-health-check = {version = "*", optional = true} +djangorestframework = {version = "*", optional = true} +djangorestframework-recursive = {version = "*", optional = true} +drf-spectacular = {version = ">=0.28.0,<1", optional = true} +drf-writable-nested = {version = "*", optional = true} +environs = {version = "<15", optional = true} +flagsmith-flag-engine = {version = ">6", optional = true} +gunicorn = {version = ">=19.1", optional = true} +inflection = {version = "*", optional = true} +opentelemetry-api = {version = ">=1.25,<2", optional = true} +opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true} +opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true} +opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true} +opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true} +opentelemetry-sdk = {version = ">=1.25,<2", optional = true} +prometheus-client = {version = ">=0.0.16", optional = true} +psycopg2-binary = {version = ">=2.9,<3", optional = true} +pyfakefs = {version = ">=5,<6", optional = true} +pytest-django = {version = ">=4,<5", optional = true} +redis = {version = ">=5,<6", optional = true} +requests = {version = "*", optional = true} +sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true} +simplejson = {version = ">=3,<4", optional = true} +structlog = {version = ">=24.4,<26", optional = true} +typing_extensions = {version = "*", optional = true} [package.extras] -common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing-extensions"] -flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing-extensions"] +common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing_extensions"] +flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing_extensions"] task-processor = ["backoff (>=2.2.1,<3.0.0)", "django (>4,<6)", "django-health-check", "opentelemetry-api (>=1.25,<2)", "prometheus-client (>=0.0.16)"] test-tools = ["pyfakefs (>=5,<6)", "pytest-django (>=4,<5)"] +[package.source] +type = "git" +url = "https://github.com/Flagsmith/flagsmith-common.git" +reference = "feat/docgen-events-scanner" +resolved_reference = "d1669ef0f9f01cb2f515b5fe08acb3a6fc58803e" + [[package]] name = "flagsmith-flag-engine" version = "10.0.3" @@ -4587,7 +4591,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -6022,4 +6025,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.11,<3.14" -content-hash = "ae5e279244c9c4b4e8eeff86d7c62cf7559501c3c2317969eb5e28ead8a14153" +content-hash = "6cde8e5e9d176dfcee62210357b2eede3129debe4353433710b47e970f0737eb" diff --git a/api/pyproject.toml b/api/pyproject.toml index 7e3d676f2dfe..e9c9a483cc7a 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -178,7 +178,7 @@ pygithub = "~2.8" hubspot-api-client = "^12.0.0" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" -flagsmith-common = { version = ">=3.5.0,<4", extras = [ +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-events-scanner", extras = [ "common-core", "flagsmith-schemas", "task-processor", @@ -263,7 +263,7 @@ types-psycopg2 = "^2.9.21.20250121" types-python-dateutil = "^2.9.0.20241206" types-pytz = "^2025.1.0.20250204" ruff = "^0.9.7" -flagsmith-common = { version = "*", extras = ["test-tools"] } +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-events-scanner", extras = ["test-tools"] } pytest-responses = "^0.5.1" diff-cover = "^10.1.0" django-debug-toolbar = "*" diff --git a/docs/docs/administration-and-security/platform-configuration/events.md b/docs/docs/administration-and-security/platform-configuration/events.md new file mode 100644 index 000000000000..e02d795d6c10 --- /dev/null +++ b/docs/docs/administration-and-security/platform-configuration/events.md @@ -0,0 +1,243 @@ +--- +title: Events +sidebar_label: Events +sidebar_position: 30 +--- + +Flagsmith backend emits [OpenTelemetry events](https://opentelemetry.io/docs/specs/otel/logs/data-model/#events) +that can be ingested to downstream observability systems and/or a data warehouse of your choice via OTLP. +To learn how to configure this, see [OpenTelemetry](deployment-self-hosting/scaling-and-performance/opentelemetry). + +## Event catalog + +### `app_analytics.no-analytics-database-configured` + +Logged at `warning` from: + - `api/app_analytics/analytics_db_service.py:74` + - `api/app_analytics/analytics_db_service.py:210` + +Attributes: + - `details` + +### `code_references.cleanup_issues.created` + +Logged at `info` from: + - `api/integrations/github/views.py:388` + +Attributes: + - `issues_created.count` + - `organisation.id` + +### `code_references.scan.created` + +Logged at `info` from: + - `api/projects/code_references/views.py:41` + +Attributes: + - `code_references.count` + - `feature.count` + - `organisation.id` + +### `dynamodb.environment-document-compressed` + +Logged at `info` from: + - `api/environments/dynamodb/wrappers/environment_wrapper.py:92` + +Attributes: + - `environment_api_key` + - `environment_id` + +### `feature_health.feature-health-event-dismissal-not-supported` + +Logged at `warning` from: + - `api/features/feature_health/services.py:127` + +Attributes: + - `feature_health_event_external_id` + - `feature_health_event_id` + - `feature_health_event_type` + - `provider_name` + +### `feature_health.feature-health-provider-error` + +Logged at `error` from: + - `api/features/feature_health/services.py:50` + +Attributes: + - `exc_info` + - `provider_id` + - `provider_name` + +### `feature_health.invalid-feature-health-webhook-path-requested` + +Logged at `warning` from: + - `api/features/feature_health/providers/services.py:30` + +Attributes: + - `path` + +### `gitlab.api-call-failed` + +Logged at `error` from: + - `api/integrations/gitlab/views/browse_gitlab.py:58` + +Attributes: + - `exc_info` + +### `gitlab.configuration-created` + +Logged at `info` from: + - `api/integrations/gitlab/views/configuration.py:26` + +Attributes: + - `gitlab_instance_url` + - `organisation.id` + - `project.id` + +### `gitlab.configuration-updated` + +Logged at `info` from: + - `api/integrations/gitlab/views/configuration.py:34` + +Attributes: + - `gitlab_instance_url` + - `organisation.id` + - `project.id` + +### `gitlab.issues-fetched` + +Logged at `info` from: + - `api/integrations/gitlab/views/browse_gitlab.py:133` + +Attributes: + - `gitlab_project_id` + - `project.id` + +### `gitlab.merge-requests-fetched` + +Logged at `info` from: + - `api/integrations/gitlab/views/browse_gitlab.py:159` + +Attributes: + - `gitlab_project_id` + - `project.id` + +### `gitlab.projects-fetched` + +Logged at `info` from: + - `api/integrations/gitlab/views/browse_gitlab.py:108` + +Attributes: + - `project.id` + +### `launch_darkly.import-failed` + +Logged at `exception` from: + - `api/integrations/launch_darkly/tasks.py:36` + +Attributes: + - `import_request_id` + - `ld_project_key` + - `organisation_id` + - `project_id` + +### `launch_darkly.import-rate-limit-reached` + +Logged at `warning` from: + - `api/integrations/launch_darkly/tasks.py:26` + +Attributes: + - `error_message` + - `import_request_id` + - `ld_project_key` + - `organisation_id` + - `project_id` + - `retry_at` + +### `platform_hub.no-analytics-database-configured` + +Logged at `warning` from: + - `api/platform_hub/services.py:116` + - `api/platform_hub/services.py:206` + - `api/platform_hub/services.py:428` + +Attributes: + +### `segments.serializers.segment-revision-created` + +Logged at `info` from: + - `api/segments/serializers.py:141` + +Attributes: + - `revision_id` + - `segment_id` + +### `sentry_change_tracking.integration-error` + +Logged at `warning` from: + - `api/integrations/sentry/change_tracking.py:112` + +Attributes: + - `feature_name` + - `sentry_action` + - `sentry_response_body` + - `sentry_response_status` + +### `sentry_change_tracking.request-failure` + +Logged at `warning` from: + - `api/integrations/sentry/change_tracking.py:102` + +Attributes: + - `error` + - `feature_name` + - `sentry_action` + +### `sentry_change_tracking.sending` + +Logged at `debug` from: + - `api/integrations/sentry/change_tracking.py:87` + +Attributes: + - `feature_name` + - `headers` + - `payload` + - `sentry_action` + - `url` + +### `sentry_change_tracking.success` + +Logged at `info` from: + - `api/integrations/sentry/change_tracking.py:109` + +Attributes: + - `feature_name` + - `sentry_action` + +### `workflows.change_request.committed` + +Logged at `info` from: + - `api/core/workflows_services.py:39` + +Attributes: + - `environment.id` + - `feature_states.count` + - `organisation.id` + +### `workflows.missing-live-segment` + +Logged at `warning` from: + - `api/core/workflows_services.py:114` + +Attributes: + - `draft_segment` + +### `workflows.segment-revision-created` + +Logged at `info` from: + - `api/core/workflows_services.py:119` + +Attributes: + - `revision_id` + - `segment_id` + From d3f70e7f0553a3611d1c36b3a323123fad4d04c1 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 12:05:26 +0100 Subject: [PATCH 02/12] chore: Bump flagsmith-common to 3.8.0 Switch back from the branch pin now that the docgen events subcommand is released. beep boop --- api/poetry.lock | 80 ++++++++++++++++++++++------------------------ api/pyproject.toml | 4 +-- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 4c7bf6313e7d..c8d64f7275e5 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -2055,55 +2055,51 @@ resolved_reference = "b7fa1f42c333b443763548ea1fe0054f07cdf641" [[package]] name = "flagsmith-common" -version = "3.7.0" +version = "3.8.0" description = "Flagsmith's common library" optional = false -python-versions = ">=3.11,<4.0" +python-versions = "<4.0,>=3.11" groups = ["main", "dev", "licensing", "workflows"] -files = [] -develop = false - -[package.dependencies] -backoff = {version = ">=2.2.1,<3.0.0", optional = true} -django = {version = ">4,<6", optional = true} -django-health-check = {version = "*", optional = true} -djangorestframework = {version = "*", optional = true} -djangorestframework-recursive = {version = "*", optional = true} -drf-spectacular = {version = ">=0.28.0,<1", optional = true} -drf-writable-nested = {version = "*", optional = true} -environs = {version = "<15", optional = true} -flagsmith-flag-engine = {version = ">6", optional = true} -gunicorn = {version = ">=19.1", optional = true} -inflection = {version = "*", optional = true} -opentelemetry-api = {version = ">=1.25,<2", optional = true} -opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true} -opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true} -opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true} -opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true} -opentelemetry-sdk = {version = ">=1.25,<2", optional = true} -prometheus-client = {version = ">=0.0.16", optional = true} -psycopg2-binary = {version = ">=2.9,<3", optional = true} -pyfakefs = {version = ">=5,<6", optional = true} -pytest-django = {version = ">=4,<5", optional = true} -redis = {version = ">=5,<6", optional = true} -requests = {version = "*", optional = true} -sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true} -simplejson = {version = ">=3,<4", optional = true} -structlog = {version = ">=24.4,<26", optional = true} -typing_extensions = {version = "*", optional = true} +files = [ + {file = "flagsmith_common-3.8.0-py3-none-any.whl", hash = "sha256:0c319a0ec3230070bd7b81d437ef706ed570432b3f01b4c9fda3351e611f8cd7"}, + {file = "flagsmith_common-3.8.0.tar.gz", hash = "sha256:70b3f74113c54eb147d0097e4f878bd6cd800d951781a3a7b3f061d0ab12fa64"}, +] + +[package.dependencies] +backoff = {version = ">=2.2.1,<3.0.0", optional = true, markers = "extra == \"task-processor\""} +django = {version = ">4,<6", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +django-health-check = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +djangorestframework = {version = "*", optional = true, markers = "extra == \"common-core\""} +djangorestframework-recursive = {version = "*", optional = true, markers = "extra == \"common-core\""} +drf-spectacular = {version = ">=0.28.0,<1", optional = true, markers = "extra == \"common-core\""} +drf-writable-nested = {version = "*", optional = true, markers = "extra == \"common-core\""} +environs = {version = "<15", optional = true, markers = "extra == \"common-core\""} +flagsmith-flag-engine = {version = ">6", optional = true, markers = "extra == \"flagsmith-schemas\""} +gunicorn = {version = ">=19.1", optional = true, markers = "extra == \"common-core\""} +inflection = {version = "*", optional = true, markers = "extra == \"common-core\""} +opentelemetry-api = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} +opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} +opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} +opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} +opentelemetry-sdk = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} +prometheus-client = {version = ">=0.0.16", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +psycopg2-binary = {version = ">=2.9,<3", optional = true, markers = "extra == \"common-core\""} +pyfakefs = {version = ">=5,<6", optional = true, markers = "extra == \"test-tools\""} +pytest-django = {version = ">=4,<5", optional = true, markers = "extra == \"test-tools\""} +redis = {version = ">=5,<6", optional = true, markers = "extra == \"common-core\""} +requests = {version = "*", optional = true, markers = "extra == \"common-core\""} +sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true, markers = "extra == \"common-core\""} +simplejson = {version = ">=3,<4", optional = true, markers = "extra == \"common-core\" and extra == \"flagsmith-schemas\""} +structlog = {version = ">=24.4,<26", optional = true, markers = "extra == \"common-core\""} +typing-extensions = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"flagsmith-schemas\""} [package.extras] -common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing_extensions"] -flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing_extensions"] +common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing-extensions"] +flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing-extensions"] task-processor = ["backoff (>=2.2.1,<3.0.0)", "django (>4,<6)", "django-health-check", "opentelemetry-api (>=1.25,<2)", "prometheus-client (>=0.0.16)"] test-tools = ["pyfakefs (>=5,<6)", "pytest-django (>=4,<5)"] -[package.source] -type = "git" -url = "https://github.com/Flagsmith/flagsmith-common.git" -reference = "feat/docgen-events-scanner" -resolved_reference = "d1669ef0f9f01cb2f515b5fe08acb3a6fc58803e" - [[package]] name = "flagsmith-flag-engine" version = "10.0.3" @@ -6025,4 +6021,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.11,<3.14" -content-hash = "6cde8e5e9d176dfcee62210357b2eede3129debe4353433710b47e970f0737eb" +content-hash = "34ad926c324e6b573a325c9292804e19d357baaf96e2baa8053f2035386d44c7" diff --git a/api/pyproject.toml b/api/pyproject.toml index e9c9a483cc7a..b255dc67873a 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -178,7 +178,7 @@ pygithub = "~2.8" hubspot-api-client = "^12.0.0" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-events-scanner", extras = [ +flagsmith-common = { version = ">=3.8.0,<4", extras = [ "common-core", "flagsmith-schemas", "task-processor", @@ -263,7 +263,7 @@ types-psycopg2 = "^2.9.21.20250121" types-python-dateutil = "^2.9.0.20241206" types-pytz = "^2025.1.0.20250204" ruff = "^0.9.7" -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-events-scanner", extras = ["test-tools"] } +flagsmith-common = { version = "*", extras = ["test-tools"] } pytest-responses = "^0.5.1" diff-cover = "^10.1.0" django-debug-toolbar = "*" From 26ec57132b2dac8f47fbf8c8db97818a379d0ea4 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 12:07:44 +0100 Subject: [PATCH 03/12] chore: Regenerate events.md against flagsmith-common 3.8.0 beep boop --- .../platform-configuration/events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/administration-and-security/platform-configuration/events.md b/docs/docs/administration-and-security/platform-configuration/events.md index e02d795d6c10..a265ac86a4b7 100644 --- a/docs/docs/administration-and-security/platform-configuration/events.md +++ b/docs/docs/administration-and-security/platform-configuration/events.md @@ -8,7 +8,7 @@ Flagsmith backend emits [OpenTelemetry events](https://opentelemetry.io/docs/spe that can be ingested to downstream observability systems and/or a data warehouse of your choice via OTLP. To learn how to configure this, see [OpenTelemetry](deployment-self-hosting/scaling-and-performance/opentelemetry). -## Event catalog +## Event catalogue ### `app_analytics.no-analytics-database-configured` From b63508d362154c7def865915ef25df3bda1548e9 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 16:51:17 +0100 Subject: [PATCH 04/12] chore: Bump flagsmith-common to 3.8.1 and regenerate events.md 3.8.1 normalises legacy kebab-case event names to snake_case in the catalogue. beep boop --- api/poetry.lock | 9 +++-- api/pyproject.toml | 2 +- .../platform-configuration/events.md | 38 +++++++++---------- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index c8d64f7275e5..df2ba6e1079f 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -2055,14 +2055,14 @@ resolved_reference = "b7fa1f42c333b443763548ea1fe0054f07cdf641" [[package]] name = "flagsmith-common" -version = "3.8.0" +version = "3.8.1" description = "Flagsmith's common library" optional = false python-versions = "<4.0,>=3.11" groups = ["main", "dev", "licensing", "workflows"] files = [ - {file = "flagsmith_common-3.8.0-py3-none-any.whl", hash = "sha256:0c319a0ec3230070bd7b81d437ef706ed570432b3f01b4c9fda3351e611f8cd7"}, - {file = "flagsmith_common-3.8.0.tar.gz", hash = "sha256:70b3f74113c54eb147d0097e4f878bd6cd800d951781a3a7b3f061d0ab12fa64"}, + {file = "flagsmith_common-3.8.1-py3-none-any.whl", hash = "sha256:a0c59af22105cd645beb1dfd8039d807159e4823c592c32e8d7239cf67fe4b2f"}, + {file = "flagsmith_common-3.8.1.tar.gz", hash = "sha256:45c3c86a7f0d778153367740ed4534dbb959ce8ccb649b6ad043e6e93f302dc9"}, ] [package.dependencies] @@ -4587,6 +4587,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -6021,4 +6022,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.11,<3.14" -content-hash = "34ad926c324e6b573a325c9292804e19d357baaf96e2baa8053f2035386d44c7" +content-hash = "08eec71a36c217755510b16c0583926730755121fbcdfd823af4bef23e195f65" diff --git a/api/pyproject.toml b/api/pyproject.toml index b255dc67873a..33c319872bd9 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -178,7 +178,7 @@ pygithub = "~2.8" hubspot-api-client = "^12.0.0" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" -flagsmith-common = { version = ">=3.8.0,<4", extras = [ +flagsmith-common = { version = ">=3.8.1,<4", extras = [ "common-core", "flagsmith-schemas", "task-processor", diff --git a/docs/docs/administration-and-security/platform-configuration/events.md b/docs/docs/administration-and-security/platform-configuration/events.md index a265ac86a4b7..ee33a3774afb 100644 --- a/docs/docs/administration-and-security/platform-configuration/events.md +++ b/docs/docs/administration-and-security/platform-configuration/events.md @@ -10,7 +10,7 @@ To learn how to configure this, see [OpenTelemetry](deployment-self-hosting/scal ## Event catalogue -### `app_analytics.no-analytics-database-configured` +### `app_analytics.no_analytics_database_configured` Logged at `warning` from: - `api/app_analytics/analytics_db_service.py:74` @@ -38,7 +38,7 @@ Attributes: - `feature.count` - `organisation.id` -### `dynamodb.environment-document-compressed` +### `dynamodb.environment_document_compressed` Logged at `info` from: - `api/environments/dynamodb/wrappers/environment_wrapper.py:92` @@ -47,7 +47,7 @@ Attributes: - `environment_api_key` - `environment_id` -### `feature_health.feature-health-event-dismissal-not-supported` +### `feature_health.feature_health_event_dismissal_not_supported` Logged at `warning` from: - `api/features/feature_health/services.py:127` @@ -58,7 +58,7 @@ Attributes: - `feature_health_event_type` - `provider_name` -### `feature_health.feature-health-provider-error` +### `feature_health.feature_health_provider_error` Logged at `error` from: - `api/features/feature_health/services.py:50` @@ -68,7 +68,7 @@ Attributes: - `provider_id` - `provider_name` -### `feature_health.invalid-feature-health-webhook-path-requested` +### `feature_health.invalid_feature_health_webhook_path_requested` Logged at `warning` from: - `api/features/feature_health/providers/services.py:30` @@ -76,7 +76,7 @@ Logged at `warning` from: Attributes: - `path` -### `gitlab.api-call-failed` +### `gitlab.api_call_failed` Logged at `error` from: - `api/integrations/gitlab/views/browse_gitlab.py:58` @@ -84,7 +84,7 @@ Logged at `error` from: Attributes: - `exc_info` -### `gitlab.configuration-created` +### `gitlab.configuration_created` Logged at `info` from: - `api/integrations/gitlab/views/configuration.py:26` @@ -94,7 +94,7 @@ Attributes: - `organisation.id` - `project.id` -### `gitlab.configuration-updated` +### `gitlab.configuration_updated` Logged at `info` from: - `api/integrations/gitlab/views/configuration.py:34` @@ -104,7 +104,7 @@ Attributes: - `organisation.id` - `project.id` -### `gitlab.issues-fetched` +### `gitlab.issues_fetched` Logged at `info` from: - `api/integrations/gitlab/views/browse_gitlab.py:133` @@ -113,7 +113,7 @@ Attributes: - `gitlab_project_id` - `project.id` -### `gitlab.merge-requests-fetched` +### `gitlab.merge_requests_fetched` Logged at `info` from: - `api/integrations/gitlab/views/browse_gitlab.py:159` @@ -122,7 +122,7 @@ Attributes: - `gitlab_project_id` - `project.id` -### `gitlab.projects-fetched` +### `gitlab.projects_fetched` Logged at `info` from: - `api/integrations/gitlab/views/browse_gitlab.py:108` @@ -130,7 +130,7 @@ Logged at `info` from: Attributes: - `project.id` -### `launch_darkly.import-failed` +### `launch_darkly.import_failed` Logged at `exception` from: - `api/integrations/launch_darkly/tasks.py:36` @@ -141,7 +141,7 @@ Attributes: - `organisation_id` - `project_id` -### `launch_darkly.import-rate-limit-reached` +### `launch_darkly.import_rate_limit_reached` Logged at `warning` from: - `api/integrations/launch_darkly/tasks.py:26` @@ -154,7 +154,7 @@ Attributes: - `project_id` - `retry_at` -### `platform_hub.no-analytics-database-configured` +### `platform_hub.no_analytics_database_configured` Logged at `warning` from: - `api/platform_hub/services.py:116` @@ -163,7 +163,7 @@ Logged at `warning` from: Attributes: -### `segments.serializers.segment-revision-created` +### `segments.serializers.segment_revision_created` Logged at `info` from: - `api/segments/serializers.py:141` @@ -172,7 +172,7 @@ Attributes: - `revision_id` - `segment_id` -### `sentry_change_tracking.integration-error` +### `sentry_change_tracking.integration_error` Logged at `warning` from: - `api/integrations/sentry/change_tracking.py:112` @@ -183,7 +183,7 @@ Attributes: - `sentry_response_body` - `sentry_response_status` -### `sentry_change_tracking.request-failure` +### `sentry_change_tracking.request_failure` Logged at `warning` from: - `api/integrations/sentry/change_tracking.py:102` @@ -224,7 +224,7 @@ Attributes: - `feature_states.count` - `organisation.id` -### `workflows.missing-live-segment` +### `workflows.missing_live_segment` Logged at `warning` from: - `api/core/workflows_services.py:114` @@ -232,7 +232,7 @@ Logged at `warning` from: Attributes: - `draft_segment` -### `workflows.segment-revision-created` +### `workflows.segment_revision_created` Logged at `info` from: - `api/core/workflows_services.py:119` From 11c06ae733f3ebc7fbbc965d0e303a80a5a1e471 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 17:05:50 +0100 Subject: [PATCH 05/12] docs: Move metrics, events, monitoring, and OpenTelemetry into a new Observability category MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These four files are operator observability artefacts, not Flagsmith-tenant settings — they shared a category (Platform Configuration) with environment-settings.md that was aimed at a different audience, and monitoring.md already linked cross-tree to the metrics reference. Lifts all four under a new `deployment-self-hosting/observability/` category, updates inbound references in the docs tree and in `api/{Makefile,README.md}`, updates the parent `deployment-self-hosting/index.md` to surface the new section, and adds redirects in `vercel.json` so the old URLs continue to work. beep boop --- api/Makefile | 4 ++-- api/README.md | 2 +- .../docs/administration-and-security/index.mdx | 2 +- .../environment-variables.md | 2 +- docs/docs/deployment-self-hosting/index.md | 10 +++++++++- .../observability/_category_.json | 5 +++++ .../observability}/events.md | 0 .../observability}/metrics.md | 0 .../monitoring.md | 2 +- .../opentelemetry.md | 0 docs/vercel.json | 18 +++++++++++++++++- 11 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 docs/docs/deployment-self-hosting/observability/_category_.json rename docs/docs/{administration-and-security/platform-configuration => deployment-self-hosting/observability}/events.md (100%) rename docs/docs/{administration-and-security/platform-configuration => deployment-self-hosting/observability}/metrics.md (100%) rename docs/docs/deployment-self-hosting/{scaling-and-performance => observability}/monitoring.md (96%) rename docs/docs/deployment-self-hosting/{scaling-and-performance => observability}/opentelemetry.md (100%) diff --git a/api/Makefile b/api/Makefile index 9e93284b522d..d8d5c280a521 100644 --- a/api/Makefile +++ b/api/Makefile @@ -164,8 +164,8 @@ integrate-private-tests: .PHONY: generate-docs generate-docs: generate-flagsmith-sdk-openapi - poetry run flagsmith docgen metrics > ../docs/docs/administration-and-security/platform-configuration/metrics.md - poetry run flagsmith docgen events > ../docs/docs/administration-and-security/platform-configuration/events.md + poetry run flagsmith docgen metrics > ../docs/docs/deployment-self-hosting/observability/metrics.md + poetry run flagsmith docgen events > ../docs/docs/deployment-self-hosting/observability/events.md .PHONY: add-known-sdk-version add-known-sdk-version: diff --git a/api/README.md b/api/README.md index 0d710878ef7b..cc12ac6dff34 100644 --- a/api/README.md +++ b/api/README.md @@ -35,7 +35,7 @@ We use the Given When Then structure in all our tests. ### Code guidelines: metrics -Flagsmith's backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](../docs/docs/administration-and-security/platform-configuration/metrics.md). Metrics code is hosted in `metrics.py` modules. +Flagsmith's backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](../docs/docs/deployment-self-hosting/observability/metrics.md). Metrics code is hosted in `metrics.py` modules. Name metrics `flagsmith_{domain}_{entity}_{unit}` and give them a comprehensive description. diff --git a/docs/docs/administration-and-security/index.mdx b/docs/docs/administration-and-security/index.mdx index 1a2243e49035..65beff5d9296 100644 --- a/docs/docs/administration-and-security/index.mdx +++ b/docs/docs/administration-and-security/index.mdx @@ -149,7 +149,7 @@ Configure environment-specific settings and platform-wide options for your Flags
-

Platform Metrics

+

Platform Metrics

System monitoring and performance metrics

diff --git a/docs/docs/deployment-self-hosting/core-configuration/environment-variables.md b/docs/docs/deployment-self-hosting/core-configuration/environment-variables.md index d8f0ba0ebef5..c6e56f008b45 100644 --- a/docs/docs/deployment-self-hosting/core-configuration/environment-variables.md +++ b/docs/docs/deployment-self-hosting/core-configuration/environment-variables.md @@ -53,7 +53,7 @@ relevant section below for more details. - `PREVENT_SIGNUP`: Determines whether to prevent new signups. - `ENABLE_EMAIL_ACTIVATION`: New user registration will go via email activation flow, default False. - `OTEL_EXPORTER_OTLP_ENDPOINT`: Base OTLP/HTTP endpoint (e.g. `http://collector:4318`). If unset, OTel is disabled. See - [OpenTelemetry](/deployment-self-hosting/scaling-and-performance/opentelemetry). + [OpenTelemetry](/deployment-self-hosting/observability/opentelemetry). - `OTEL_SERVICE_NAME`: The `service.name` resource attribute attached to all OTel telemetry. Defaults to `flagsmith-api`. - `OTEL_TRACING_EXCLUDED_URL_PATHS`: Comma-separated URL paths to exclude from OTel tracing (e.g. diff --git a/docs/docs/deployment-self-hosting/index.md b/docs/docs/deployment-self-hosting/index.md index 952db1dd7eea..9eb217187e51 100644 --- a/docs/docs/deployment-self-hosting/index.md +++ b/docs/docs/deployment-self-hosting/index.md @@ -50,11 +50,19 @@ Once deployed, you'll need to configure your Flagsmith instance: As your usage grows, you'll need to consider scaling and performance: - **[Sizing and Scaling](/deployment-self-hosting/scaling-and-performance/sizing-and-scaling)**: Understand resource requirements and scaling strategies -- **[Monitoring](/deployment-self-hosting/scaling-and-performance/monitoring)**: Set up monitoring and alerting for your deployment - **[Asynchronous Task Processor](/deployment-self-hosting/scaling-and-performance/asynchronous-task-processor)**: Configure background task processing - **[Using InfluxDB for Analytics](/deployment-self-hosting/scaling-and-performance/using-influxdb-for-analytics)**: Set up analytics storage - **[Load Testing](/deployment-self-hosting/scaling-and-performance/load-testing)**: Test your deployment under load +## Observability + +Monitor the health and behaviour of your deployment: + +- **[Monitoring](/deployment-self-hosting/observability/monitoring)**: Set up monitoring and alerting +- **[Metrics](/deployment-self-hosting/observability/metrics)**: Prometheus metrics exported by the backend +- **[Events](/deployment-self-hosting/observability/events)**: Structured events emitted by the backend +- **[OpenTelemetry](/deployment-self-hosting/observability/opentelemetry)**: Export traces and logs via OTLP + ## Administration and Maintenance Ongoing administration tasks to keep your deployment running smoothly: diff --git a/docs/docs/deployment-self-hosting/observability/_category_.json b/docs/docs/deployment-self-hosting/observability/_category_.json new file mode 100644 index 000000000000..28bba6dc0db8 --- /dev/null +++ b/docs/docs/deployment-self-hosting/observability/_category_.json @@ -0,0 +1,5 @@ +{ + "label": "Observability", + "position": 6, + "collapsed": true +} diff --git a/docs/docs/administration-and-security/platform-configuration/events.md b/docs/docs/deployment-self-hosting/observability/events.md similarity index 100% rename from docs/docs/administration-and-security/platform-configuration/events.md rename to docs/docs/deployment-self-hosting/observability/events.md diff --git a/docs/docs/administration-and-security/platform-configuration/metrics.md b/docs/docs/deployment-self-hosting/observability/metrics.md similarity index 100% rename from docs/docs/administration-and-security/platform-configuration/metrics.md rename to docs/docs/deployment-self-hosting/observability/metrics.md diff --git a/docs/docs/deployment-self-hosting/scaling-and-performance/monitoring.md b/docs/docs/deployment-self-hosting/observability/monitoring.md similarity index 96% rename from docs/docs/deployment-self-hosting/scaling-and-performance/monitoring.md rename to docs/docs/deployment-self-hosting/observability/monitoring.md index 2007f6dd6c01..a5a762153bbe 100644 --- a/docs/docs/deployment-self-hosting/scaling-and-performance/monitoring.md +++ b/docs/docs/deployment-self-hosting/observability/monitoring.md @@ -86,7 +86,7 @@ If you need additional AppDynamics setup options, you can find the other environ To enable the Prometheus `/metrics` endpoint, set the `PROMETHEUS_ENABLED` environment variable to `true`. -For the full list of metrics, see the [Metrics reference](/administration-and-security/platform-configuration/metrics). +For the full list of metrics, see the [Metrics reference](/deployment-self-hosting/observability/metrics). ## StatsD diff --git a/docs/docs/deployment-self-hosting/scaling-and-performance/opentelemetry.md b/docs/docs/deployment-self-hosting/observability/opentelemetry.md similarity index 100% rename from docs/docs/deployment-self-hosting/scaling-and-performance/opentelemetry.md rename to docs/docs/deployment-self-hosting/observability/opentelemetry.md diff --git a/docs/vercel.json b/docs/vercel.json index 6effd3867468..fb9721bdc8d7 100644 --- a/docs/vercel.json +++ b/docs/vercel.json @@ -66,7 +66,23 @@ }, { "source": "/integrations/apm/appdynamics", - "destination": "https://docs.flagsmith.com/deployment-self-hosting/scaling-and-performance/monitoring#appdynamics" + "destination": "https://docs.flagsmith.com/deployment-self-hosting/observability/monitoring#appdynamics" + }, + { + "source": "/administration-and-security/platform-configuration/metrics", + "destination": "/deployment-self-hosting/observability/metrics" + }, + { + "source": "/administration-and-security/platform-configuration/events", + "destination": "/deployment-self-hosting/observability/events" + }, + { + "source": "/deployment-self-hosting/scaling-and-performance/monitoring", + "destination": "/deployment-self-hosting/observability/monitoring" + }, + { + "source": "/deployment-self-hosting/scaling-and-performance/opentelemetry", + "destination": "/deployment-self-hosting/observability/opentelemetry" }, { "source": "/integrations/datadog/", From ff17462fecda00cbbfa8fdc4d44b9ac8f38a0b3a Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 17:26:28 +0100 Subject: [PATCH 06/12] refactor(docs): Split events and metrics pages into MDX + generated partial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flagsmith-common docgen templates used to emit a full Docusaurus page — frontmatter, intro prose, a section heading, and the catalogue entries. The intro links and framing were necessarily site-specific, which meant upstream owned URLs that only made sense for one consumer and silently broke on docs-tree moves (see Flagsmith/flagsmith-common#210). Switch to an MDX + partial pattern. The `docgen events` and `docgen metrics` commands now write only the catalogue entries to underscore-prefixed partial files (`_events-catalogue.md`, `_metrics-catalogue.md`) — Docusaurus ignores these from routing. The page shell moves to hand-authored `events.mdx` and `metrics.mdx` that import the partials, owning the frontmatter, intro prose, and internal links. Pins flagsmith-common to the PR branch temporarily; swap for a version pin once that lands and releases. beep boop --- api/Makefile | 4 +- api/poetry.lock | 78 ++++++++++--------- api/pyproject.toml | 4 +- .../{events.md => _events-catalogue.md} | 11 --- .../{metrics.md => _metrics-catalogue.md} | 14 ---- .../observability/events.mdx | 15 ++++ .../observability/metrics.mdx | 17 ++++ 7 files changed, 77 insertions(+), 66 deletions(-) rename docs/docs/deployment-self-hosting/observability/{events.md => _events-catalogue.md} (91%) rename docs/docs/deployment-self-hosting/observability/{metrics.md => _metrics-catalogue.md} (84%) create mode 100644 docs/docs/deployment-self-hosting/observability/events.mdx create mode 100644 docs/docs/deployment-self-hosting/observability/metrics.mdx diff --git a/api/Makefile b/api/Makefile index d8d5c280a521..432e019d8b4e 100644 --- a/api/Makefile +++ b/api/Makefile @@ -164,8 +164,8 @@ integrate-private-tests: .PHONY: generate-docs generate-docs: generate-flagsmith-sdk-openapi - poetry run flagsmith docgen metrics > ../docs/docs/deployment-self-hosting/observability/metrics.md - poetry run flagsmith docgen events > ../docs/docs/deployment-self-hosting/observability/events.md + poetry run flagsmith docgen metrics > ../docs/docs/deployment-self-hosting/observability/_metrics-catalogue.md + poetry run flagsmith docgen events > ../docs/docs/deployment-self-hosting/observability/_events-catalogue.md .PHONY: add-known-sdk-version add-known-sdk-version: diff --git a/api/poetry.lock b/api/poetry.lock index df2ba6e1079f..29f42880b5ff 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -2058,48 +2058,52 @@ name = "flagsmith-common" version = "3.8.1" description = "Flagsmith's common library" optional = false -python-versions = "<4.0,>=3.11" +python-versions = ">=3.11,<4.0" groups = ["main", "dev", "licensing", "workflows"] -files = [ - {file = "flagsmith_common-3.8.1-py3-none-any.whl", hash = "sha256:a0c59af22105cd645beb1dfd8039d807159e4823c592c32e8d7239cf67fe4b2f"}, - {file = "flagsmith_common-3.8.1.tar.gz", hash = "sha256:45c3c86a7f0d778153367740ed4534dbb959ce8ccb649b6ad043e6e93f302dc9"}, -] - -[package.dependencies] -backoff = {version = ">=2.2.1,<3.0.0", optional = true, markers = "extra == \"task-processor\""} -django = {version = ">4,<6", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -django-health-check = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -djangorestframework = {version = "*", optional = true, markers = "extra == \"common-core\""} -djangorestframework-recursive = {version = "*", optional = true, markers = "extra == \"common-core\""} -drf-spectacular = {version = ">=0.28.0,<1", optional = true, markers = "extra == \"common-core\""} -drf-writable-nested = {version = "*", optional = true, markers = "extra == \"common-core\""} -environs = {version = "<15", optional = true, markers = "extra == \"common-core\""} -flagsmith-flag-engine = {version = ">6", optional = true, markers = "extra == \"flagsmith-schemas\""} -gunicorn = {version = ">=19.1", optional = true, markers = "extra == \"common-core\""} -inflection = {version = "*", optional = true, markers = "extra == \"common-core\""} -opentelemetry-api = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} -opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} -opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} -opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} -opentelemetry-sdk = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} -prometheus-client = {version = ">=0.0.16", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} -psycopg2-binary = {version = ">=2.9,<3", optional = true, markers = "extra == \"common-core\""} -pyfakefs = {version = ">=5,<6", optional = true, markers = "extra == \"test-tools\""} -pytest-django = {version = ">=4,<5", optional = true, markers = "extra == \"test-tools\""} -redis = {version = ">=5,<6", optional = true, markers = "extra == \"common-core\""} -requests = {version = "*", optional = true, markers = "extra == \"common-core\""} -sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true, markers = "extra == \"common-core\""} -simplejson = {version = ">=3,<4", optional = true, markers = "extra == \"common-core\" and extra == \"flagsmith-schemas\""} -structlog = {version = ">=24.4,<26", optional = true, markers = "extra == \"common-core\""} -typing-extensions = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"flagsmith-schemas\""} +files = [] +develop = false + +[package.dependencies] +backoff = {version = ">=2.2.1,<3.0.0", optional = true} +django = {version = ">4,<6", optional = true} +django-health-check = {version = "*", optional = true} +djangorestframework = {version = "*", optional = true} +djangorestframework-recursive = {version = "*", optional = true} +drf-spectacular = {version = ">=0.28.0,<1", optional = true} +drf-writable-nested = {version = "*", optional = true} +environs = {version = "<15", optional = true} +flagsmith-flag-engine = {version = ">6", optional = true} +gunicorn = {version = ">=19.1", optional = true} +inflection = {version = "*", optional = true} +opentelemetry-api = {version = ">=1.25,<2", optional = true} +opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true} +opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true} +opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true} +opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true} +opentelemetry-sdk = {version = ">=1.25,<2", optional = true} +prometheus-client = {version = ">=0.0.16", optional = true} +psycopg2-binary = {version = ">=2.9,<3", optional = true} +pyfakefs = {version = ">=5,<6", optional = true} +pytest-django = {version = ">=4,<5", optional = true} +redis = {version = ">=5,<6", optional = true} +requests = {version = "*", optional = true} +sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true} +simplejson = {version = ">=3,<4", optional = true} +structlog = {version = ">=24.4,<26", optional = true} +typing_extensions = {version = "*", optional = true} [package.extras] -common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing-extensions"] -flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing-extensions"] +common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing_extensions"] +flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing_extensions"] task-processor = ["backoff (>=2.2.1,<3.0.0)", "django (>4,<6)", "django-health-check", "opentelemetry-api (>=1.25,<2)", "prometheus-client (>=0.0.16)"] test-tools = ["pyfakefs (>=5,<6)", "pytest-django (>=4,<5)"] +[package.source] +type = "git" +url = "https://github.com/Flagsmith/flagsmith-common.git" +reference = "feat/docgen-templates-header-partial" +resolved_reference = "4cee5266249e354441cfd052a831f5a7b31103ed" + [[package]] name = "flagsmith-flag-engine" version = "10.0.3" @@ -6022,4 +6026,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.11,<3.14" -content-hash = "08eec71a36c217755510b16c0583926730755121fbcdfd823af4bef23e195f65" +content-hash = "3bb49789aefc37e6a3d0d4074d60010b107e0614a9231ade551d8966b221860b" diff --git a/api/pyproject.toml b/api/pyproject.toml index 33c319872bd9..fb3dc2cb01a2 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -178,7 +178,7 @@ pygithub = "~2.8" hubspot-api-client = "^12.0.0" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" -flagsmith-common = { version = ">=3.8.1,<4", extras = [ +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-templates-header-partial", extras = [ "common-core", "flagsmith-schemas", "task-processor", @@ -263,7 +263,7 @@ types-psycopg2 = "^2.9.21.20250121" types-python-dateutil = "^2.9.0.20241206" types-pytz = "^2025.1.0.20250204" ruff = "^0.9.7" -flagsmith-common = { version = "*", extras = ["test-tools"] } +flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-templates-header-partial", extras = ["test-tools"] } pytest-responses = "^0.5.1" diff-cover = "^10.1.0" django-debug-toolbar = "*" diff --git a/docs/docs/deployment-self-hosting/observability/events.md b/docs/docs/deployment-self-hosting/observability/_events-catalogue.md similarity index 91% rename from docs/docs/deployment-self-hosting/observability/events.md rename to docs/docs/deployment-self-hosting/observability/_events-catalogue.md index ee33a3774afb..6b10112bd465 100644 --- a/docs/docs/deployment-self-hosting/observability/events.md +++ b/docs/docs/deployment-self-hosting/observability/_events-catalogue.md @@ -1,14 +1,3 @@ ---- -title: Events -sidebar_label: Events -sidebar_position: 30 ---- - -Flagsmith backend emits [OpenTelemetry events](https://opentelemetry.io/docs/specs/otel/logs/data-model/#events) -that can be ingested to downstream observability systems and/or a data warehouse of your choice via OTLP. -To learn how to configure this, see [OpenTelemetry](deployment-self-hosting/scaling-and-performance/opentelemetry). - -## Event catalogue ### `app_analytics.no_analytics_database_configured` diff --git a/docs/docs/deployment-self-hosting/observability/metrics.md b/docs/docs/deployment-self-hosting/observability/_metrics-catalogue.md similarity index 84% rename from docs/docs/deployment-self-hosting/observability/metrics.md rename to docs/docs/deployment-self-hosting/observability/_metrics-catalogue.md index 2055304b7fe5..6cae297b29e4 100644 --- a/docs/docs/deployment-self-hosting/observability/metrics.md +++ b/docs/docs/deployment-self-hosting/observability/_metrics-catalogue.md @@ -1,17 +1,3 @@ ---- -title: Metrics -sidebar_label: Metrics -sidebar_position: 20 ---- - -## Prometheus - -To enable the Prometheus `/metrics` endpoint, set the `PROMETHEUS_ENABLED` environment variable to `true`. - -When enabled, Flagsmith serves the `/metrics` endpoint on port 9100. - -The metrics provided by Flagsmith are described below. - ### `flagsmith_build_info` diff --git a/docs/docs/deployment-self-hosting/observability/events.mdx b/docs/docs/deployment-self-hosting/observability/events.mdx new file mode 100644 index 000000000000..5cc7e6f1e746 --- /dev/null +++ b/docs/docs/deployment-self-hosting/observability/events.mdx @@ -0,0 +1,15 @@ +--- +title: Events +sidebar_label: Events +sidebar_position: 30 +--- + +import EventCatalogue from './_events-catalogue.md'; + +Flagsmith backend emits [OpenTelemetry events](https://opentelemetry.io/docs/specs/otel/logs/data-model/#events) +that can be ingested to downstream observability systems and/or a data warehouse of your choice via OTLP. +To learn how to configure this, see [OpenTelemetry](/deployment-self-hosting/observability/opentelemetry). + +## Event catalogue + + diff --git a/docs/docs/deployment-self-hosting/observability/metrics.mdx b/docs/docs/deployment-self-hosting/observability/metrics.mdx new file mode 100644 index 000000000000..d82e412cec74 --- /dev/null +++ b/docs/docs/deployment-self-hosting/observability/metrics.mdx @@ -0,0 +1,17 @@ +--- +title: Metrics +sidebar_label: Metrics +sidebar_position: 20 +--- + +import MetricsCatalogue from './_metrics-catalogue.md'; + +## Prometheus + +To enable the Prometheus `/metrics` endpoint, set the `PROMETHEUS_ENABLED` environment variable to `true`. + +When enabled, Flagsmith serves the `/metrics` endpoint on port 9100. + +The metrics provided by Flagsmith are described below. + + From 94f47ee6e105f2c4243f2b0fb3908f9fba11d845 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 17:29:14 +0100 Subject: [PATCH 07/12] chore: Assign events catalogue to the product team via CODEOWNERS The generated events catalogue partial is the authoritative list of structured events the backend emits. Routing it through the product team means new events automatically summon product review at PR time. beep boop --- CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 69caaa040b16..79c4d1ffd786 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -6,3 +6,6 @@ /frontend/ @flagsmith/flagsmith-front-end /infrastructure/ @flagsmith/flagsmith-infrastructure /docs/ @flagsmith/flagsmith-docs + +# Specific rules based on file +/docs/docs/deployment-self-hosting/observability/_events-catalogue.md @flagsmith/flagsmith-product From 91a0a5138c423ba971b39b78846cd754d03000a2 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 18:11:17 +0100 Subject: [PATCH 08/12] fix(docs): Use absolute docs URL for metrics link in api/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The README is imported as a component into the docs site via docs/docs/project-and-community/development.md. Relative paths written from api/README.md's perspective on disk don't resolve when the README is rendered at /project-and-community/development — Docusaurus treats them as literal URL paths, which fail the broken-link check. Use an absolute docs.flagsmith.com URL so the link works both when reading the README on GitHub and when the README is composed into the docs site. beep boop --- api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/README.md b/api/README.md index cc12ac6dff34..d418636a4dfe 100644 --- a/api/README.md +++ b/api/README.md @@ -35,7 +35,7 @@ We use the Given When Then structure in all our tests. ### Code guidelines: metrics -Flagsmith's backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](../docs/docs/deployment-self-hosting/observability/metrics.md). Metrics code is hosted in `metrics.py` modules. +Flagsmith's backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](https://docs.flagsmith.com/deployment-self-hosting/observability/metrics). Metrics code is hosted in `metrics.py` modules. Name metrics `flagsmith_{domain}_{entity}_{unit}` and give them a comprehensive description. From 09420ce2e393a3f3bc56a04dbbabde96d137cbe2 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 18:32:24 +0100 Subject: [PATCH 09/12] docs: Reorder Observability sidebar and expand StatsD section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move Monitoring and OpenTelemetry above Metrics and Events in the Observability category — the walkthrough pages should come before the references. Flesh out the StatsD section in Monitoring with the env vars that enable Gunicorn's built-in access log metrics, and cross-link it from the Metrics page so readers looking for StatsD metrics find their way there. Add a pointer from the OpenTelemetry logs section to the Events reference. beep boop --- .../deployment-self-hosting/observability/events.mdx | 2 +- .../deployment-self-hosting/observability/metrics.mdx | 7 ++++++- .../deployment-self-hosting/observability/monitoring.md | 9 ++++++++- .../observability/opentelemetry.md | 4 ++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/docs/docs/deployment-self-hosting/observability/events.mdx b/docs/docs/deployment-self-hosting/observability/events.mdx index 5cc7e6f1e746..62ade0c12383 100644 --- a/docs/docs/deployment-self-hosting/observability/events.mdx +++ b/docs/docs/deployment-self-hosting/observability/events.mdx @@ -1,7 +1,7 @@ --- title: Events sidebar_label: Events -sidebar_position: 30 +sidebar_position: 40 --- import EventCatalogue from './_events-catalogue.md'; diff --git a/docs/docs/deployment-self-hosting/observability/metrics.mdx b/docs/docs/deployment-self-hosting/observability/metrics.mdx index d82e412cec74..09e11f743fca 100644 --- a/docs/docs/deployment-self-hosting/observability/metrics.mdx +++ b/docs/docs/deployment-self-hosting/observability/metrics.mdx @@ -1,7 +1,7 @@ --- title: Metrics sidebar_label: Metrics -sidebar_position: 20 +sidebar_position: 30 --- import MetricsCatalogue from './_metrics-catalogue.md'; @@ -15,3 +15,8 @@ When enabled, Flagsmith serves the `/metrics` endpoint on port 9100. The metrics provided by Flagsmith are described below. + +## StatsD + +Flagsmith's Gunicorn worker emits per-request access log metrics (request counts, durations, HTTP statuses) to StatsD +when configured. See [StatsD](/deployment-self-hosting/observability/monitoring#statsd) for setup. diff --git a/docs/docs/deployment-self-hosting/observability/monitoring.md b/docs/docs/deployment-self-hosting/observability/monitoring.md index a5a762153bbe..5501ec3d1344 100644 --- a/docs/docs/deployment-self-hosting/observability/monitoring.md +++ b/docs/docs/deployment-self-hosting/observability/monitoring.md @@ -1,5 +1,6 @@ --- title: Monitoring +sidebar_position: 10 description: Setting up monitoring integrations like AppDynamics and StatsD. --- @@ -90,7 +91,13 @@ For the full list of metrics, see the [Metrics reference](/deployment-self-hosti ## StatsD -There is currently no specific documentation for setting up StatsD. +Set `STATSD_HOST` to enable. Optional: + +- `STATSD_PORT` — defaults to `8125`. +- `STATSD_PREFIX` — defaults to `flagsmith.api`. + +See the [Gunicorn instrumentation docs](https://gunicorn.org/instrumentation/) for the full list of +metrics. ## Task Processor Monitoring diff --git a/docs/docs/deployment-self-hosting/observability/opentelemetry.md b/docs/docs/deployment-self-hosting/observability/opentelemetry.md index 42f00e716bcb..a8f5c37b91ab 100644 --- a/docs/docs/deployment-self-hosting/observability/opentelemetry.md +++ b/docs/docs/deployment-self-hosting/observability/opentelemetry.md @@ -1,5 +1,6 @@ --- title: OpenTelemetry +sidebar_position: 20 description: Exporting traces and structured logs from Flagsmith using OpenTelemetry. --- @@ -88,6 +89,9 @@ Excluded paths produce no spans at all. Flagsmith uses [structlog](https://www.structlog.org/) for application logging. When OTel is enabled, structlog events are exported as OTLP log records. The `flagsmith.event` attribute duplicates the event name for backends that don't surface OTel's `EventName` field. +See the [Events reference](/deployment-self-hosting/observability/events) for the catalogue of structured events the +backend emits, with attributes and source locations. + ### Span events When a structlog event is emitted inside an active span (e.g. during an HTTP request), it is also attached as a From 600f4165ab9d1372b217758ffd7cf5d7ae3a8e0e Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Mon, 20 Apr 2026 18:43:18 +0100 Subject: [PATCH 10/12] chore: Bump flagsmith-common to 3.8.2 Switch back from the PR branch pin now that Flagsmith/flagsmith-common#210 (pure-data docgen templates) has been released. beep boop --- api/poetry.lock | 80 ++++++++++++++++++++++------------------------ api/pyproject.toml | 4 +-- 2 files changed, 40 insertions(+), 44 deletions(-) diff --git a/api/poetry.lock b/api/poetry.lock index 29f42880b5ff..a10b9de29e30 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -2055,55 +2055,51 @@ resolved_reference = "b7fa1f42c333b443763548ea1fe0054f07cdf641" [[package]] name = "flagsmith-common" -version = "3.8.1" +version = "3.8.2" description = "Flagsmith's common library" optional = false -python-versions = ">=3.11,<4.0" +python-versions = "<4.0,>=3.11" groups = ["main", "dev", "licensing", "workflows"] -files = [] -develop = false - -[package.dependencies] -backoff = {version = ">=2.2.1,<3.0.0", optional = true} -django = {version = ">4,<6", optional = true} -django-health-check = {version = "*", optional = true} -djangorestframework = {version = "*", optional = true} -djangorestframework-recursive = {version = "*", optional = true} -drf-spectacular = {version = ">=0.28.0,<1", optional = true} -drf-writable-nested = {version = "*", optional = true} -environs = {version = "<15", optional = true} -flagsmith-flag-engine = {version = ">6", optional = true} -gunicorn = {version = ">=19.1", optional = true} -inflection = {version = "*", optional = true} -opentelemetry-api = {version = ">=1.25,<2", optional = true} -opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true} -opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true} -opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true} -opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true} -opentelemetry-sdk = {version = ">=1.25,<2", optional = true} -prometheus-client = {version = ">=0.0.16", optional = true} -psycopg2-binary = {version = ">=2.9,<3", optional = true} -pyfakefs = {version = ">=5,<6", optional = true} -pytest-django = {version = ">=4,<5", optional = true} -redis = {version = ">=5,<6", optional = true} -requests = {version = "*", optional = true} -sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true} -simplejson = {version = ">=3,<4", optional = true} -structlog = {version = ">=24.4,<26", optional = true} -typing_extensions = {version = "*", optional = true} +files = [ + {file = "flagsmith_common-3.8.2-py3-none-any.whl", hash = "sha256:4b1921ec874da52ce7dfa8a248677153a57bda5e607be892f5b5c9dddcbf5c73"}, + {file = "flagsmith_common-3.8.2.tar.gz", hash = "sha256:0612a14858c0e56f5d51dba6be9e4b1f82741b17aced24367a7ad6bccba3d7a8"}, +] + +[package.dependencies] +backoff = {version = ">=2.2.1,<3.0.0", optional = true, markers = "extra == \"task-processor\""} +django = {version = ">4,<6", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +django-health-check = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +djangorestframework = {version = "*", optional = true, markers = "extra == \"common-core\""} +djangorestframework-recursive = {version = "*", optional = true, markers = "extra == \"common-core\""} +drf-spectacular = {version = ">=0.28.0,<1", optional = true, markers = "extra == \"common-core\""} +drf-writable-nested = {version = "*", optional = true, markers = "extra == \"common-core\""} +environs = {version = "<15", optional = true, markers = "extra == \"common-core\""} +flagsmith-flag-engine = {version = ">6", optional = true, markers = "extra == \"flagsmith-schemas\""} +gunicorn = {version = ">=19.1", optional = true, markers = "extra == \"common-core\""} +inflection = {version = "*", optional = true, markers = "extra == \"common-core\""} +opentelemetry-api = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +opentelemetry-exporter-otlp-proto-http = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} +opentelemetry-instrumentation-django = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} +opentelemetry-instrumentation-psycopg2 = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} +opentelemetry-instrumentation-redis = {version = ">=0.46b0,<1", optional = true, markers = "extra == \"common-core\""} +opentelemetry-sdk = {version = ">=1.25,<2", optional = true, markers = "extra == \"common-core\""} +prometheus-client = {version = ">=0.0.16", optional = true, markers = "extra == \"common-core\" or extra == \"task-processor\""} +psycopg2-binary = {version = ">=2.9,<3", optional = true, markers = "extra == \"common-core\""} +pyfakefs = {version = ">=5,<6", optional = true, markers = "extra == \"test-tools\""} +pytest-django = {version = ">=4,<5", optional = true, markers = "extra == \"test-tools\""} +redis = {version = ">=5,<6", optional = true, markers = "extra == \"common-core\""} +requests = {version = "*", optional = true, markers = "extra == \"common-core\""} +sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true, markers = "extra == \"common-core\""} +simplejson = {version = ">=3,<4", optional = true, markers = "extra == \"common-core\" and extra == \"flagsmith-schemas\""} +structlog = {version = ">=24.4,<26", optional = true, markers = "extra == \"common-core\""} +typing-extensions = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"flagsmith-schemas\""} [package.extras] -common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing_extensions"] -flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing_extensions"] +common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "inflection", "opentelemetry-api (>=1.25,<2)", "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)", "opentelemetry-instrumentation-django (>=0.46b0,<1)", "opentelemetry-instrumentation-psycopg2 (>=0.46b0,<1)", "opentelemetry-instrumentation-redis (>=0.46b0,<1)", "opentelemetry-sdk (>=1.25,<2)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "redis (>=5,<6)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing-extensions"] +flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing-extensions"] task-processor = ["backoff (>=2.2.1,<3.0.0)", "django (>4,<6)", "django-health-check", "opentelemetry-api (>=1.25,<2)", "prometheus-client (>=0.0.16)"] test-tools = ["pyfakefs (>=5,<6)", "pytest-django (>=4,<5)"] -[package.source] -type = "git" -url = "https://github.com/Flagsmith/flagsmith-common.git" -reference = "feat/docgen-templates-header-partial" -resolved_reference = "4cee5266249e354441cfd052a831f5a7b31103ed" - [[package]] name = "flagsmith-flag-engine" version = "10.0.3" @@ -6026,4 +6022,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">3.11,<3.14" -content-hash = "3bb49789aefc37e6a3d0d4074d60010b107e0614a9231ade551d8966b221860b" +content-hash = "3887d5db2a2c09afcc53b6bdda606a15226230b49c0e1712346099b7a3a71d52" diff --git a/api/pyproject.toml b/api/pyproject.toml index fb3dc2cb01a2..91a41d6d1a2e 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -178,7 +178,7 @@ pygithub = "~2.8" hubspot-api-client = "^12.0.0" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-templates-header-partial", extras = [ +flagsmith-common = { version = ">=3.8.2,<4", extras = [ "common-core", "flagsmith-schemas", "task-processor", @@ -263,7 +263,7 @@ types-psycopg2 = "^2.9.21.20250121" types-python-dateutil = "^2.9.0.20241206" types-pytz = "^2025.1.0.20250204" ruff = "^0.9.7" -flagsmith-common = { git = "https://github.com/Flagsmith/flagsmith-common.git", branch = "feat/docgen-templates-header-partial", extras = ["test-tools"] } +flagsmith-common = { version = "*", extras = ["test-tools"] } pytest-responses = "^0.5.1" diff-cover = "^10.1.0" django-debug-toolbar = "*" From dab310fd332a0122dcc4d02b8d8d7a3df871d292 Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Tue, 21 Apr 2026 15:14:41 +0100 Subject: [PATCH 11/12] wording improvements Co-authored-by: Evandro Myller <22429+emyller@users.noreply.github.com> --- CODEOWNERS | 2 +- api/README.md | 2 +- docs/docs/deployment-self-hosting/observability/events.mdx | 2 +- docs/docs/deployment-self-hosting/observability/metrics.mdx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 79c4d1ffd786..96ede6a52ffa 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -7,5 +7,5 @@ /infrastructure/ @flagsmith/flagsmith-infrastructure /docs/ @flagsmith/flagsmith-docs -# Specific rules based on file +# Event changes are relevant to the product team /docs/docs/deployment-self-hosting/observability/_events-catalogue.md @flagsmith/flagsmith-product diff --git a/api/README.md b/api/README.md index d418636a4dfe..afa5125ff8da 100644 --- a/api/README.md +++ b/api/README.md @@ -35,7 +35,7 @@ We use the Given When Then structure in all our tests. ### Code guidelines: metrics -Flagsmith's backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](https://docs.flagsmith.com/deployment-self-hosting/observability/metrics). Metrics code is hosted in `metrics.py` modules. +The Flagsmith backend exports Prometheus metrics. When planning a feature, consider which metrics should cover it — counters for domain events, histograms for latency or sizes, gauges for cardinalities. See [documentation for existing metrics](https://docs.flagsmith.com/deployment-self-hosting/observability/metrics). Metrics code is hosted in `metrics.py` modules. Name metrics `flagsmith_{domain}_{entity}_{unit}` and give them a comprehensive description. diff --git a/docs/docs/deployment-self-hosting/observability/events.mdx b/docs/docs/deployment-self-hosting/observability/events.mdx index 62ade0c12383..d9ad94438287 100644 --- a/docs/docs/deployment-self-hosting/observability/events.mdx +++ b/docs/docs/deployment-self-hosting/observability/events.mdx @@ -6,7 +6,7 @@ sidebar_position: 40 import EventCatalogue from './_events-catalogue.md'; -Flagsmith backend emits [OpenTelemetry events](https://opentelemetry.io/docs/specs/otel/logs/data-model/#events) +The Flagsmith backend emits [OpenTelemetry events](https://opentelemetry.io/docs/specs/otel/logs/data-model/#events) that can be ingested to downstream observability systems and/or a data warehouse of your choice via OTLP. To learn how to configure this, see [OpenTelemetry](/deployment-self-hosting/observability/opentelemetry). diff --git a/docs/docs/deployment-self-hosting/observability/metrics.mdx b/docs/docs/deployment-self-hosting/observability/metrics.mdx index 09e11f743fca..3becac991b2c 100644 --- a/docs/docs/deployment-self-hosting/observability/metrics.mdx +++ b/docs/docs/deployment-self-hosting/observability/metrics.mdx @@ -18,5 +18,5 @@ The metrics provided by Flagsmith are described below. ## StatsD -Flagsmith's Gunicorn worker emits per-request access log metrics (request counts, durations, HTTP statuses) to StatsD +The Flagsmith WSGI worker emits per-request access log metrics (request counts, durations, HTTP statuses) to StatsD when configured. See [StatsD](/deployment-self-hosting/observability/monitoring#statsd) for setup. From 69ebd2abeb765d943a3645ba50a73c08d983420c Mon Sep 17 00:00:00 2001 From: Kim Gustyr Date: Tue, 21 Apr 2026 15:34:56 +0100 Subject: [PATCH 12/12] regen --- .../observability/_events-catalogue.md | 40 ++++--------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/docs/docs/deployment-self-hosting/observability/_events-catalogue.md b/docs/docs/deployment-self-hosting/observability/_events-catalogue.md index 6b10112bd465..0d800e459840 100644 --- a/docs/docs/deployment-self-hosting/observability/_events-catalogue.md +++ b/docs/docs/deployment-self-hosting/observability/_events-catalogue.md @@ -65,58 +65,34 @@ Logged at `warning` from: Attributes: - `path` -### `gitlab.api_call_failed` +### `gitlab.api_call.failed` Logged at `error` from: - - `api/integrations/gitlab/views/browse_gitlab.py:58` + - `api/integrations/gitlab/views/browse_gitlab.py:59` Attributes: - `exc_info` - -### `gitlab.configuration_created` - -Logged at `info` from: - - `api/integrations/gitlab/views/configuration.py:26` - -Attributes: - - `gitlab_instance_url` - `organisation.id` - `project.id` -### `gitlab.configuration_updated` +### `gitlab.configuration.created` Logged at `info` from: - - `api/integrations/gitlab/views/configuration.py:34` + - `api/integrations/gitlab/views/configuration.py:25` Attributes: - `gitlab_instance_url` - `organisation.id` - `project.id` -### `gitlab.issues_fetched` - -Logged at `info` from: - - `api/integrations/gitlab/views/browse_gitlab.py:133` - -Attributes: - - `gitlab_project_id` - - `project.id` - -### `gitlab.merge_requests_fetched` - -Logged at `info` from: - - `api/integrations/gitlab/views/browse_gitlab.py:159` - -Attributes: - - `gitlab_project_id` - - `project.id` - -### `gitlab.projects_fetched` +### `gitlab.configuration.updated` Logged at `info` from: - - `api/integrations/gitlab/views/browse_gitlab.py:108` + - `api/integrations/gitlab/views/configuration.py:33` Attributes: + - `gitlab_instance_url` + - `organisation.id` - `project.id` ### `launch_darkly.import_failed`