flagsmith-common 3.11.0__tar.gz → 3.12.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/PKG-INFO +5 -3
  2. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/README.md +3 -2
  3. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/pyproject.toml +3 -2
  4. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/constants.py +4 -0
  5. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/main.py +20 -3
  6. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/otel.py +50 -10
  7. flagsmith_common-3.12.0/src/common/core/types.py +3 -0
  8. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/LICENSE +0 -0
  9. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/__init__.py +0 -0
  10. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/__init__.py +0 -0
  11. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/app.py +0 -0
  12. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/cli/__init__.py +0 -0
  13. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/cli/healthcheck.py +0 -0
  14. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/cli/run.py +0 -0
  15. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/docgen/__init__.py +0 -0
  16. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/docgen/events.py +0 -0
  17. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/logging.py +0 -0
  18. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/management/__init__.py +0 -0
  19. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/management/commands/__init__.py +0 -0
  20. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/management/commands/docgen.py +0 -0
  21. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/management/commands/start.py +0 -0
  22. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/management/commands/waitfordb.py +0 -0
  23. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/metrics.py +0 -0
  24. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/middleware.py +0 -0
  25. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/sentry.py +0 -0
  26. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/templates/docgen-events.md +0 -0
  27. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/templates/docgen-metrics.md +0 -0
  28. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/urls.py +0 -0
  29. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/utils.py +0 -0
  30. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/core/views.py +0 -0
  31. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/environments/permissions.py +0 -0
  32. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/features/__init__.py +0 -0
  33. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/features/multivariate/__init__.py +0 -0
  34. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/features/multivariate/serializers.py +0 -0
  35. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/features/serializers.py +0 -0
  36. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/features/versioning/__init__.py +0 -0
  37. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/features/versioning/serializers.py +0 -0
  38. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/__init__.py +0 -0
  39. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/conf.py +0 -0
  40. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/constants.py +0 -0
  41. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/logging.py +0 -0
  42. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/metrics.py +0 -0
  43. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/metrics_server.py +0 -0
  44. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/middleware.py +0 -0
  45. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/processors.py +0 -0
  46. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/gunicorn/utils.py +0 -0
  47. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/lint_tests.py +0 -0
  48. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/migrations/__init__.py +0 -0
  49. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/migrations/helpers/__init__.py +0 -0
  50. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/migrations/helpers/postgres_helpers.py +0 -0
  51. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/organisations/permissions.py +0 -0
  52. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/projects/permissions.py +0 -0
  53. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/prometheus/__init__.py +0 -0
  54. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/prometheus/utils.py +0 -0
  55. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/py.typed +0 -0
  56. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/test_tools/__init__.py +0 -0
  57. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/test_tools/plugin.py +0 -0
  58. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/test_tools/types.py +0 -0
  59. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/test_tools/utils.py +0 -0
  60. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/common/types.py +0 -0
  61. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/__init__.py +0 -0
  62. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/api.py +0 -0
  63. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/constants.py +0 -0
  64. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/dynamodb.py +0 -0
  65. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/py.typed +0 -0
  66. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/pydantic_types.py +0 -0
  67. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/types.py +0 -0
  68. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/utils.py +0 -0
  69. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/flagsmith_schemas/validators.py +0 -0
  70. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/__init__.py +0 -0
  71. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/admin.py +0 -0
  72. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/apps.py +0 -0
  73. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/constants.py +0 -0
  74. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/decorators.py +0 -0
  75. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/exceptions.py +0 -0
  76. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/health.py +0 -0
  77. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/managers.py +0 -0
  78. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/metrics.py +0 -0
  79. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0001_initial.py +0 -0
  80. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0002_healthcheckmodel.py +0 -0
  81. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0003_add_completed_to_task.py +0 -0
  82. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0004_recreate_task_indexes.py +0 -0
  83. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0005_update_conditional_index_conditions.py +0 -0
  84. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0006_auto_20230221_0802.py +0 -0
  85. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0007_add_is_locked.py +0 -0
  86. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0008_add_get_task_to_process_function.py +0 -0
  87. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0009_add_recurring_task_run_first_run_at.py +0 -0
  88. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0010_task_priority.py +0 -0
  89. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0011_add_priority_to_get_tasks_to_process.py +0 -0
  90. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0012_add_locked_at_and_timeout.py +0 -0
  91. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0013_add_last_picked_at.py +0 -0
  92. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0014_add_trace_context.py +0 -0
  93. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/0015_add_is_disabled.py +0 -0
  94. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/__init__.py +0 -0
  95. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/0008_get_recurring_tasks_to_process.sql +0 -0
  96. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/0008_get_tasks_to_process.sql +0 -0
  97. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/0011_get_tasks_to_process.sql +0 -0
  98. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/0012_get_recurringtasks_to_process.sql +0 -0
  99. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/0013_get_recurringtasks_to_process.sql +0 -0
  100. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/0015_get_recurringtasks_to_process.sql +0 -0
  101. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/migrations/sql/__init__.py +0 -0
  102. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/models.py +0 -0
  103. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/monitoring.py +0 -0
  104. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/processor.py +0 -0
  105. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/py.typed +0 -0
  106. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/routers.py +0 -0
  107. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/serializers.py +0 -0
  108. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/task_registry.py +0 -0
  109. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/task_run_method.py +0 -0
  110. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/tasks.py +0 -0
  111. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/threads.py +0 -0
  112. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/types.py +0 -0
  113. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/urls.py +0 -0
  114. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/utils.py +0 -0
  115. {flagsmith_common-3.11.0 → flagsmith_common-3.12.0}/src/task_processor/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flagsmith-common
3
- Version: 3.11.0
3
+ Version: 3.12.0
4
4
  Summary: Flagsmith's common library
5
5
  Author: Matthew Elwell, Gagan Trivedi, Kim Gustyr, Zach Aysan, Francesco Lo Franco, Rodrigo López Dato, Evandro Myller, Wadii Zaim
6
6
  License-Expression: BSD-3-Clause
@@ -32,6 +32,7 @@ Requires-Dist: flagsmith-flag-engine>6 ; extra == 'flagsmith-schemas'
32
32
  Requires-Dist: inflection ; extra == 'otel'
33
33
  Requires-Dist: opentelemetry-api>=1.25,<2 ; extra == 'otel'
34
34
  Requires-Dist: opentelemetry-sdk>=1.25,<2 ; extra == 'otel'
35
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25,<2 ; extra == 'otel'
35
36
  Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.25,<2 ; extra == 'otel'
36
37
  Requires-Dist: sentry-sdk>=2.0.0,<3.0.0 ; extra == 'otel'
37
38
  Requires-Dist: structlog>=24.4,<26 ; extra == 'otel'
@@ -194,7 +195,8 @@ OTel instrumentation is opt-in, controlled by environment variables:
194
195
 
195
196
  | Variable | Description | Default |
196
197
  | --------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------- |
197
- | `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP endpoint (e.g. `http://collector:4318`). If unset, no OTel setup occurs. | _(disabled)_ |
198
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP endpoint (e.g. `http://collector:4318` for HTTP, `http://collector:4317` for gRPC). If unset, no OTel setup occurs. | _(disabled)_ |
199
+ | `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP transport: `grpc` or `http/protobuf` (default). | `http/protobuf` |
198
200
  | `OTEL_SERVICE_NAME` | The `service.name` resource attribute. Defaults to `flagsmith-task-processor` when running the task processor. | `flagsmith-api` |
199
201
  | `OTEL_TRACING_EXCLUDED_URL_PATHS` | Comma-separated URL paths to exclude from tracing (e.g. `health/liveness,health/readiness`). | _(none)_ |
200
202
 
@@ -204,7 +206,7 @@ Standard `OTEL_*` env vars (e.g. `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_EXPORTER_OTLP
204
206
 
205
207
  When `OTEL_EXPORTER_OTLP_ENDPOINT` is set, `ensure_cli_env()` sets up:
206
208
 
207
- - **Tracing**: `TracerProvider` with OTLP/HTTP span export, W3C `TraceContext` + `Baggage` propagation, and auto-instrumentation for:
209
+ - **Tracing**: `TracerProvider` with OTLP span export (HTTP or gRPC, per `OTEL_EXPORTER_OTLP_PROTOCOL`), W3C `TraceContext` + `Baggage` propagation, and auto-instrumentation for:
208
210
  - **Django** (`DjangoInstrumentor`): creates a root span per HTTP request with span names formatted as `{METHOD} {route_template}` (e.g. `GET /api/v1/projects/{pk}/`).
209
211
  - **psycopg2** (`Psycopg2Instrumentor`): creates child spans for each SQL query with `db.system`, `db.statement`, and `db.name` attributes. SQL commenter is enabled, adding trace context as SQL comments for database-side correlation.
210
212
  - **Redis** (`RedisInstrumentor`): creates child spans for each Redis command with `db.system` and `db.statement` attributes.
@@ -133,7 +133,8 @@ OTel instrumentation is opt-in, controlled by environment variables:
133
133
 
134
134
  | Variable | Description | Default |
135
135
  | --------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------- |
136
- | `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP endpoint (e.g. `http://collector:4318`). If unset, no OTel setup occurs. | _(disabled)_ |
136
+ | `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP endpoint (e.g. `http://collector:4318` for HTTP, `http://collector:4317` for gRPC). If unset, no OTel setup occurs. | _(disabled)_ |
137
+ | `OTEL_EXPORTER_OTLP_PROTOCOL` | OTLP transport: `grpc` or `http/protobuf` (default). | `http/protobuf` |
137
138
  | `OTEL_SERVICE_NAME` | The `service.name` resource attribute. Defaults to `flagsmith-task-processor` when running the task processor. | `flagsmith-api` |
138
139
  | `OTEL_TRACING_EXCLUDED_URL_PATHS` | Comma-separated URL paths to exclude from tracing (e.g. `health/liveness,health/readiness`). | _(none)_ |
139
140
 
@@ -143,7 +144,7 @@ Standard `OTEL_*` env vars (e.g. `OTEL_RESOURCE_ATTRIBUTES`, `OTEL_EXPORTER_OTLP
143
144
 
144
145
  When `OTEL_EXPORTER_OTLP_ENDPOINT` is set, `ensure_cli_env()` sets up:
145
146
 
146
- - **Tracing**: `TracerProvider` with OTLP/HTTP span export, W3C `TraceContext` + `Baggage` propagation, and auto-instrumentation for:
147
+ - **Tracing**: `TracerProvider` with OTLP span export (HTTP or gRPC, per `OTEL_EXPORTER_OTLP_PROTOCOL`), W3C `TraceContext` + `Baggage` propagation, and auto-instrumentation for:
147
148
  - **Django** (`DjangoInstrumentor`): creates a root span per HTTP request with span names formatted as `{METHOD} {route_template}` (e.g. `GET /api/v1/projects/{pk}/`).
148
149
  - **psycopg2** (`Psycopg2Instrumentor`): creates child spans for each SQL query with `db.system`, `db.statement`, and `db.name` attributes. SQL commenter is enabled, adding trace context as SQL comments for database-side correlation.
149
150
  - **Redis** (`RedisInstrumentor`): creates child spans for each Redis command with `db.system` and `db.statement` attributes.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "flagsmith-common"
3
- version = "3.11.0"
3
+ version = "3.12.0"
4
4
  description = "Flagsmith's common library"
5
5
  requires-python = ">=3.11,<4.0"
6
6
  dependencies = []
@@ -29,6 +29,7 @@ optional-dependencies = { test-tools = [
29
29
  "inflection",
30
30
  "opentelemetry-api (>=1.25,<2)",
31
31
  "opentelemetry-sdk (>=1.25,<2)",
32
+ "opentelemetry-exporter-otlp-proto-grpc (>=1.25,<2)",
32
33
  "opentelemetry-exporter-otlp-proto-http (>=1.25,<2)",
33
34
  "sentry-sdk (>=2.0.0,<3.0.0)",
34
35
  "structlog (>=24.4,<26)",
@@ -97,7 +98,7 @@ dev = [
97
98
  "pytest-freezegun (>=0.4.2, <1.0.0)",
98
99
  "pytest-httpserver (>=1.1.3, <2.0.0)",
99
100
  "pytest-mock (>=3.14.0, <4.0.0)",
100
- "setuptools (>=78.1.1, <79.0.0)",
101
+ "setuptools (>=83.0.0, <83.1.0)",
101
102
  "types-python-dateutil (>=2.9.0.20250516, <3.0.0)",
102
103
  "types-simplejson (>=3.20.0.20250326, <4.0.0)",
103
104
  ]
@@ -1,3 +1,7 @@
1
+ from common.core.types import OtlpProtocol
2
+
1
3
  DEFAULT_PROMETHEUS_MULTIPROC_DIR_NAME = "flagsmith-prometheus"
2
4
 
3
5
  LOGGING_DEFAULT_ROOT_LOG_LEVEL = "WARNING"
6
+
7
+ DEFAULT_OTLP_PROTOCOL: OtlpProtocol = "http/protobuf"
@@ -8,10 +8,12 @@ from tempfile import mkdtemp
8
8
  from django.core.management import (
9
9
  execute_from_command_line as django_execute_from_command_line,
10
10
  )
11
- from environs import Env
11
+ from environs import Env, validate
12
12
 
13
13
  from common.core.cli import healthcheck, run
14
+ from common.core.constants import DEFAULT_OTLP_PROTOCOL
14
15
  from common.core.logging import setup_logging
16
+ from common.core.types import OtlpProtocol
15
17
  from common.gunicorn.processors import make_gunicorn_access_processor
16
18
 
17
19
  env = Env()
@@ -63,6 +65,7 @@ def ensure_cli_env() -> typing.Generator[None, None, None]:
63
65
  build_otel_log_provider,
64
66
  build_tracer_provider,
65
67
  make_structlog_otel_processor,
68
+ resolve_otlp_export_endpoints,
66
69
  setup_tracing,
67
70
  )
68
71
 
@@ -72,17 +75,31 @@ def ensure_cli_env() -> typing.Generator[None, None, None]:
72
75
  else "flagsmith-api"
73
76
  )
74
77
  service_name = env.str("OTEL_SERVICE_NAME", default_service_name)
78
+ otel_protocol = typing.cast(
79
+ OtlpProtocol,
80
+ env.str(
81
+ "OTEL_EXPORTER_OTLP_PROTOCOL",
82
+ DEFAULT_OTLP_PROTOCOL,
83
+ validate=validate.OneOf(typing.get_args(OtlpProtocol)),
84
+ ),
85
+ )
86
+ traces_endpoint, logs_endpoint = resolve_otlp_export_endpoints(
87
+ otel_endpoint,
88
+ otel_protocol,
89
+ )
75
90
  log_provider = build_otel_log_provider(
76
- endpoint=f"{otel_endpoint}/v1/logs",
91
+ endpoint=logs_endpoint,
77
92
  service_name=service_name,
93
+ protocol=otel_protocol,
78
94
  )
79
95
  otel_processors = [
80
96
  add_otel_trace_context,
81
97
  make_structlog_otel_processor(log_provider),
82
98
  ]
83
99
  tracer_provider = build_tracer_provider(
84
- endpoint=f"{otel_endpoint}/v1/traces",
100
+ endpoint=traces_endpoint,
85
101
  service_name=service_name,
102
+ protocol=otel_protocol,
86
103
  )
87
104
  excluded_urls = env.str("OTEL_TRACING_EXCLUDED_URL_PATHS", None)
88
105
  ctx.enter_context(setup_tracing(tracer_provider, excluded_urls=excluded_urls))
@@ -11,26 +11,37 @@ from opentelemetry import baggage, trace
11
11
  from opentelemetry import context as otel_context
12
12
  from opentelemetry._logs import SeverityNumber
13
13
  from opentelemetry.baggage.propagation import W3CBaggagePropagator
14
+ from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
15
+ OTLPLogExporter as GrpcOTLPLogExporter,
16
+ )
17
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
18
+ OTLPSpanExporter as GrpcOTLPSpanExporter,
19
+ )
14
20
  from opentelemetry.exporter.otlp.proto.http._log_exporter import (
15
- OTLPLogExporter,
21
+ OTLPLogExporter as HttpOTLPLogExporter,
16
22
  )
17
23
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
18
- OTLPSpanExporter,
24
+ OTLPSpanExporter as HttpOTLPSpanExporter,
19
25
  )
20
26
  from opentelemetry.propagate import set_global_textmap
21
27
  from opentelemetry.propagators.composite import CompositePropagator
22
28
  from opentelemetry.propagators.textmap import TextMapPropagator
23
29
  from opentelemetry.sdk._logs import LoggerProvider
24
- from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
30
+ from opentelemetry.sdk._logs.export import (
31
+ BatchLogRecordProcessor,
32
+ LogRecordExporter,
33
+ )
25
34
  from opentelemetry.sdk.resources import Resource
26
35
  from opentelemetry.sdk.trace import TracerProvider
27
- from opentelemetry.sdk.trace.export import BatchSpanProcessor
36
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor, SpanExporter
28
37
  from opentelemetry.trace.propagation.tracecontext import (
29
38
  TraceContextTextMapPropagator,
30
39
  )
31
40
  from opentelemetry.util.types import AnyValue, Attributes
32
41
  from structlog.typing import EventDict, Processor
33
42
 
43
+ from common.core.types import OtlpProtocol
44
+
34
45
  _SEVERITY_MAP: dict[str, SeverityNumber] = {
35
46
  "debug": SeverityNumber.DEBUG,
36
47
  "info": SeverityNumber.INFO,
@@ -51,6 +62,17 @@ _RESERVED_KEYS = frozenset(
51
62
  )
52
63
 
53
64
 
65
+ def resolve_otlp_export_endpoints(
66
+ base_endpoint: str,
67
+ protocol: OtlpProtocol,
68
+ ) -> tuple[str, str]:
69
+ """Resolve trace and log exporter endpoints from a base OTLP endpoint."""
70
+ normalised_base = base_endpoint.rstrip("/")
71
+ if protocol == "grpc":
72
+ return normalised_base, normalised_base
73
+ return f"{normalised_base}/v1/traces", f"{normalised_base}/v1/logs"
74
+
75
+
54
76
  def get_otel_event_name(*, logger_name: str | None, body: str) -> str:
55
77
  """Build the event name that reaches OTel from a structlog `(logger, event)`.
56
78
 
@@ -153,20 +175,38 @@ def map_value_to_otel_value(value: object) -> str | int | float | bool:
153
175
  return json.dumps(value, default=str)
154
176
 
155
177
 
156
- def build_otel_log_provider(*, endpoint: str, service_name: str) -> LoggerProvider:
157
- """Create and configure an OTel LoggerProvider with OTLP/HTTP export."""
178
+ def build_otel_log_provider(
179
+ *,
180
+ endpoint: str,
181
+ service_name: str,
182
+ protocol: OtlpProtocol,
183
+ ) -> LoggerProvider:
184
+ """Create and configure an OTel LoggerProvider with OTLP export."""
158
185
  resource = Resource.create({"service.name": service_name})
159
186
  provider = LoggerProvider(resource=resource)
160
- exporter = OTLPLogExporter(endpoint=endpoint)
187
+ exporter: LogRecordExporter
188
+ if protocol == "grpc":
189
+ exporter = GrpcOTLPLogExporter(endpoint=endpoint)
190
+ else:
191
+ exporter = HttpOTLPLogExporter(endpoint=endpoint)
161
192
  provider.add_log_record_processor(BatchLogRecordProcessor(exporter))
162
193
  return provider
163
194
 
164
195
 
165
- def build_tracer_provider(*, endpoint: str, service_name: str) -> TracerProvider:
166
- """Create a TracerProvider with OTLP/HTTP export."""
196
+ def build_tracer_provider(
197
+ *,
198
+ endpoint: str,
199
+ service_name: str,
200
+ protocol: OtlpProtocol,
201
+ ) -> TracerProvider:
202
+ """Create a TracerProvider with OTLP export."""
167
203
  resource = Resource.create({"service.name": service_name})
168
204
  tracer_provider = TracerProvider(resource=resource)
169
- span_exporter = OTLPSpanExporter(endpoint=endpoint)
205
+ span_exporter: SpanExporter
206
+ if protocol == "grpc":
207
+ span_exporter = GrpcOTLPSpanExporter(endpoint=endpoint)
208
+ else:
209
+ span_exporter = HttpOTLPSpanExporter(endpoint=endpoint)
170
210
  tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter))
171
211
  return tracer_provider
172
212
 
@@ -0,0 +1,3 @@
1
+ from typing import Literal
2
+
3
+ OtlpProtocol = Literal["grpc", "http/protobuf"]