-
Notifications
You must be signed in to change notification settings - Fork 97
LCORE-1826: Expose OpenTelemetry configuration in v1/config endpoint #2283
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
|
|
||
| # pylint: disable=too-many-lines | ||
|
|
||
| import os | ||
| import re | ||
| from enum import Enum | ||
| from functools import cached_property | ||
|
|
@@ -2830,6 +2831,83 @@ def compiled_patterns(self) -> CompiledPatterns: | |
| return list(self._compiled_patterns) | ||
|
|
||
|
|
||
| class ObservabilityConfiguration(ConfigurationBase): | ||
| """OpenTelemetry observability configuration. | ||
|
|
||
| This configuration is automatically populated from OTEL_* environment variables | ||
| to provide visibility into the active tracing setup. | ||
|
|
||
| Attributes: | ||
| otel: Dictionary of OTEL_* environment variables with secrets redacted. | ||
| """ | ||
|
|
||
| otel: dict[str, str] = Field( | ||
| default_factory=dict, | ||
| title="OpenTelemetry configuration", | ||
| description="Active OpenTelemetry configuration from OTEL_* environment variables", | ||
| ) | ||
|
|
||
| @field_validator("otel", mode="before") | ||
| @classmethod | ||
| def redact_secrets(cls, value: dict[str, str]) -> dict[str, str]: | ||
| """Redact sensitive OTEL environment variables. | ||
|
|
||
| Redacts headers, certificates, and client keys for generic and signal-specific | ||
| (traces, metrics, logs) OTLP exporters. | ||
|
|
||
| Parameters: | ||
| ---------- | ||
| value: Dictionary of OTEL environment variables | ||
|
|
||
| Returns: | ||
| New dictionary with sensitive values redacted as "[REDACTED]" | ||
| """ | ||
| if not value: | ||
| return value | ||
|
|
||
| # Create a new dict to avoid mutating caller's data | ||
| redacted = {} | ||
|
|
||
| for key, val in value.items(): | ||
| # Redact generic and signal-specific OTLP headers | ||
| # Matches: OTEL_EXPORTER_OTLP_HEADERS, | ||
| # OTEL_EXPORTER_OTLP_TRACES_HEADERS, | ||
| # OTEL_EXPORTER_OTLP_METRICS_HEADERS, | ||
| # OTEL_EXPORTER_OTLP_LOGS_HEADERS | ||
| if "HEADERS" in key and "OTLP" in key: | ||
| redacted[key] = "[REDACTED]" | ||
| # Redact generic and signal-specific certificates | ||
| # Matches: OTEL_EXPORTER_OTLP_CERTIFICATE, | ||
| # OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE, etc. | ||
| elif "CERTIFICATE" in key and "OTLP" in key: | ||
| redacted[key] = "[REDACTED]" | ||
| # Redact generic and signal-specific client keys | ||
| # Matches: OTEL_EXPORTER_OTLP_CLIENT_KEY, | ||
| # OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY, etc. | ||
| elif "CLIENT_KEY" in key and "OTLP" in key: | ||
| redacted[key] = "[REDACTED]" | ||
| else: | ||
| redacted[key] = val | ||
|
|
||
| return redacted | ||
|
|
||
| @classmethod | ||
| def from_environment(cls) -> "ObservabilityConfiguration": | ||
| """Collect all OTEL_* environment variables from the environment. | ||
|
|
||
| Sensitive variables (headers, certificates, keys) are automatically redacted | ||
| by the field validator. | ||
|
|
||
| Returns: | ||
| ObservabilityConfiguration with otel dict populated from environment. | ||
| """ | ||
| otel_vars = {} | ||
| for key, value in os.environ.items(): | ||
| if key.startswith("OTEL_"): | ||
| otel_vars[key] = value | ||
| return cls(otel=otel_vars) | ||
|
Comment on lines
+2850
to
+2908
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift Redact unknown The collector exports every Based on learnings, verify the current fix fully resolves the earlier broad environment-variable disclosure concern. 🤖 Prompt for AI AgentsSource: Learnings |
||
|
|
||
|
|
||
| class Configuration(ConfigurationBase): | ||
| """Global service configuration.""" | ||
|
|
||
|
|
@@ -2991,6 +3069,13 @@ class Configuration(ConfigurationBase): | |
| description="Splunk HEC configuration for sending telemetry events.", | ||
| ) | ||
|
|
||
| observability: ObservabilityConfiguration = Field( | ||
| default_factory=ObservabilityConfiguration.from_environment, | ||
| title="Observability configuration", | ||
| description="OpenTelemetry and observability configuration collected " | ||
| "from OTEL_* environment variables.", | ||
| ) | ||
|
|
||
| deployment_environment: str = Field( | ||
| "development", | ||
| title="Deployment environment", | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,9 +4,11 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # pyright: reportCallIssue=false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pathlib import Path | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import pytest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from pydantic import SecretStr | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import constants | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -52,6 +54,26 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @pytest.fixture(name="clear_otel_env", autouse=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def clear_otel_env_fixture(monkeypatch: pytest.MonkeyPatch) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Clear OTEL_* environment variables to prevent ambient leakage in tests. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This fixture ensures dump configuration tests have stable expectations | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| regardless of whether they run on instrumented CI runners. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for key in list(os.environ.keys()): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if key.startswith("OTEL_"): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monkeypatch.delenv(key, raising=False) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _get_expected_observability_dump() -> dict[str, dict[str, str]]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Get expected observability dump based on current environment. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Returns empty otel dict when OTEL_* vars are cleared by fixture. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return {"otel": {}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+57
to
+74
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win Document the fixture's
Separately, 📝 Proposed docstring fixes `@pytest.fixture`(name="clear_otel_env", autouse=True)
def clear_otel_env_fixture(monkeypatch: pytest.MonkeyPatch) -> None:
"""Clear OTEL_* environment variables to prevent ambient leakage in tests.
This fixture ensures dump configuration tests have stable expectations
regardless of whether they run on instrumented CI runners.
+
+ Parameters:
+ ----------
+ monkeypatch (pytest.MonkeyPatch): Pytest fixture for environment manipulation.
"""
for key in list(os.environ.keys()):
if key.startswith("OTEL_"):
monkeypatch.delenv(key, raising=False)
def _get_expected_observability_dump() -> dict[str, dict[str, str]]:
- """Get expected observability dump based on current environment.
-
- Returns empty otel dict when OTEL_* vars are cleared by fixture.
- """
+ """Get the expected observability dump for tests in this module.
+
+ Returns a static empty otel dict, relying on the autouse
+ `clear_otel_env` fixture to guarantee no OTEL_* vars are set.
+ """
return {"otel": {}}📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsSources: Coding guidelines, Learnings |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def test_dump_configuration_minimal_cfg(tmp_path: Path) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Test that the Configuration object can be serialized to a JSON file and | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -232,6 +254,7 @@ def test_dump_configuration_minimal_cfg(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -459,6 +482,7 @@ def test_dump_configuration_valid_values(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -837,6 +861,7 @@ def test_dump_configuration_with_quota_limiters(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1099,6 +1124,7 @@ def test_dump_configuration_with_quota_limiters_different_values( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1394,6 +1420,7 @@ def test_dump_configuration_byok(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1616,6 +1643,7 @@ def test_dump_configuration_pg_namespace(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1998,6 +2026,7 @@ def test_dump_configuration_allow_degraded_mode(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2226,6 +2255,7 @@ def test_dump_configuration_max_retries_settings(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2454,6 +2484,7 @@ def test_dump_configuration_retry_count_settings(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -2689,6 +2720,7 @@ def test_dump_configuration_specific_compaction_values(tmp_path: Path) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "quota_subject": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "splunk": None, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "observability": _get_expected_observability_dump(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "deployment_environment": "development", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "reranker": { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "enabled": False, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.