File size: 3,768 Bytes
2e818da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Environment-variable-based observability configuration.

Follows the codebase's existing plain-`os.getenv` convention (see
`DEPLOYMENT_ENV` in `app/routers/health.py` and friends) rather than
introducing a Settings/pydantic-settings framework. Reads are done fresh on
every call -> callers that need a stable snapshot across a request should
hold onto the returned `ObservabilityConfig` themselves.
"""

from __future__ import annotations

import os
from pathlib import Path

from pydantic import BaseModel, ConfigDict

from app.observability.contracts import TelemetryMode

_VALID_MODES: frozenset[str] = frozenset({"disabled", "local", "full"})

_TRUE_STRINGS = {"1", "true", "yes", "on"}


class ObservabilityConfig(BaseModel):
    """Resolved observability configuration for the current process."""

    model_config = ConfigDict(extra="forbid", arbitrary_types_allowed=True)

    enabled: bool
    mode: TelemetryMode
    otlp_endpoint: str
    signoz_ui_url: str
    artifact_root: Path
    capture_content: bool = False


def _read_bool(name: str, default: bool) -> bool:
    raw = os.getenv(name)
    if raw is None:
        return default
    return raw.strip().lower() in _TRUE_STRINGS


def get_observability_config() -> ObservabilityConfig:
    """Read observability configuration from the environment.

    `OTEL_MODE` gets special handling for evaluation runs: an evaluation run
    (`EVALUATION_RUN=true`) raises a descriptive `ValueError` if `OTEL_MODE`
    is set to a genuinely invalid string (not one of "disabled", "local", or
    "full") instead of silently falling back to "disabled" the way ordinary
    product startup does. An explicit `OTEL_MODE=disabled` (or unset, which
    defaults to "disabled") remains a legitimate, non-raising configuration
    under `EVALUATION_RUN=true` -- a benchmark run explicitly opting out of
    telemetry is a valid choice, not a misconfiguration. Ordinary product
    startup additionally requires `OTEL_ENABLED=true`; `DEPLOYMENT_ENV=demo`
    always forces the effective mode to disabled.
    """
    evaluation_run = _read_bool("EVALUATION_RUN", default=False)
    demo_deployment = os.getenv("DEPLOYMENT_ENV", "desktop").strip().lower() == "demo"
    enabled = _read_bool("OTEL_ENABLED", default=False) and not demo_deployment

    raw_mode = os.getenv("OTEL_MODE", "disabled")
    mode_is_valid = raw_mode in _VALID_MODES

    if evaluation_run and not mode_is_valid:
        raise ValueError(
            f"OTEL_MODE={raw_mode!r} is invalid for an evaluation run "
            f"(EVALUATION_RUN=true); expected one of {sorted(_VALID_MODES)}."
        )

    mode: TelemetryMode = raw_mode if mode_is_valid else "disabled"  # type: ignore[assignment]
    # Product telemetry is explicitly opt-in and is never started on the
    # constrained public demo backend. Evaluation runs retain their own
    # explicit OTEL_MODE contract so disabled/local/full comparisons work.
    if demo_deployment or (not enabled and not evaluation_run):
        mode = "disabled"

    otlp_endpoint = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://127.0.0.1:4318")
    signoz_ui_url = os.getenv("SIGNOZ_UI_URL", "http://127.0.0.1:8080")
    artifact_root_raw = os.getenv("OBSERVABILITY_ARTIFACT_ROOT", "~/.studybuddy/observability")

    return ObservabilityConfig(
        enabled=enabled,
        mode=mode,
        otlp_endpoint=otlp_endpoint,
        signoz_ui_url=signoz_ui_url,
        artifact_root=Path(artifact_root_raw).expanduser(),
        # Raw diagnostic content is local-only. Full/SigNoz export ignores the
        # flag even when accidentally enabled.
        capture_content=(
            mode == "local"
            and _read_bool("OBSERVABILITY_CAPTURE_CONTENT", default=False)
        ),
    )