92 lines
3.1 KiB
Python
92 lines
3.1 KiB
Python
"""Telemetry client configuration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
from dataclasses import dataclass, field
|
|
|
|
_HEX_64_RE = re.compile(r"^[0-9a-fA-F]{64}$")
|
|
_UUID_RE = re.compile(
|
|
r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class TelemetryConfig:
|
|
"""Configuration for the telemetry client.
|
|
|
|
Values can be provided directly or loaded from environment variables:
|
|
- MOSAIC_TELEMETRY_ENABLED -> enabled
|
|
- MOSAIC_TELEMETRY_SERVER_URL -> server_url
|
|
- MOSAIC_TELEMETRY_API_KEY -> api_key
|
|
- MOSAIC_TELEMETRY_INSTANCE_ID -> instance_id
|
|
"""
|
|
|
|
server_url: str = ""
|
|
api_key: str = ""
|
|
instance_id: str = ""
|
|
enabled: bool = True
|
|
submit_interval_seconds: float = 300.0
|
|
max_queue_size: int = 1000
|
|
batch_size: int = 100
|
|
request_timeout_seconds: float = 10.0
|
|
prediction_cache_ttl_seconds: float = 21600.0
|
|
dry_run: bool = False
|
|
max_retries: int = 3
|
|
user_agent: str = field(default="mosaicstack-telemetry-python/0.1.0")
|
|
|
|
def __post_init__(self) -> None:
|
|
"""Load environment variable overrides and validate."""
|
|
env_enabled = os.environ.get("MOSAIC_TELEMETRY_ENABLED")
|
|
if env_enabled is not None:
|
|
self.enabled = env_enabled.lower() in ("1", "true", "yes")
|
|
|
|
env_url = os.environ.get("MOSAIC_TELEMETRY_SERVER_URL")
|
|
if env_url and not self.server_url:
|
|
self.server_url = env_url
|
|
|
|
env_key = os.environ.get("MOSAIC_TELEMETRY_API_KEY")
|
|
if env_key and not self.api_key:
|
|
self.api_key = env_key
|
|
|
|
env_instance = os.environ.get("MOSAIC_TELEMETRY_INSTANCE_ID")
|
|
if env_instance and not self.instance_id:
|
|
self.instance_id = env_instance
|
|
|
|
# Strip trailing slashes from server_url
|
|
self.server_url = self.server_url.rstrip("/")
|
|
|
|
def validate(self) -> list[str]:
|
|
"""Validate configuration and return list of errors (empty if valid)."""
|
|
errors: list[str] = []
|
|
|
|
if not self.server_url:
|
|
errors.append("server_url is required")
|
|
elif not self.server_url.startswith(("http://", "https://")):
|
|
errors.append("server_url must start with http:// or https://")
|
|
|
|
if not self.api_key:
|
|
errors.append("api_key is required")
|
|
elif not _HEX_64_RE.match(self.api_key):
|
|
errors.append("api_key must be a 64-character hex string")
|
|
|
|
if not self.instance_id:
|
|
errors.append("instance_id is required")
|
|
elif not _UUID_RE.match(self.instance_id):
|
|
errors.append("instance_id must be a valid UUID string")
|
|
|
|
if self.submit_interval_seconds <= 0:
|
|
errors.append("submit_interval_seconds must be positive")
|
|
|
|
if self.max_queue_size <= 0:
|
|
errors.append("max_queue_size must be positive")
|
|
|
|
if self.batch_size <= 0 or self.batch_size > 100:
|
|
errors.append("batch_size must be between 1 and 100")
|
|
|
|
if self.request_timeout_seconds <= 0:
|
|
errors.append("request_timeout_seconds must be positive")
|
|
|
|
return errors
|