Initial project structure
This commit is contained in:
91
src/mosaicstack_telemetry/config.py
Normal file
91
src/mosaicstack_telemetry/config.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user