| """ |
| Prometheus Metrics for Atom SaaS Sync Operations |
| Exposes sync-specific metrics for monitoring and alerting |
| """ |
| import logging |
| from typing import Optional |
| from prometheus_client import Counter, Gauge, Histogram |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| |
| |
| |
|
|
| |
| sync_duration_seconds = Histogram( |
| 'sync_duration_seconds', |
| 'Duration of sync operations in seconds', |
| ['operation', 'status'], |
| buckets=[0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0, 60.0, 300.0] |
| ) |
|
|
| |
| sync_success_total = Counter( |
| 'sync_success_total', |
| 'Total number of successful sync operations', |
| ['operation'] |
| ) |
|
|
| |
| sync_errors_total = Counter( |
| 'sync_errors_total', |
| 'Total number of sync errors', |
| ['operation', 'error_type'] |
| ) |
|
|
| |
| sync_skills_cached = Gauge( |
| 'sync_skills_cached', |
| 'Number of skills currently in cache' |
| ) |
|
|
| |
| sync_categories_cached = Gauge( |
| 'sync_categories_cached', |
| 'Number of categories currently in cache' |
| ) |
|
|
| |
| |
| |
|
|
| |
| websocket_connected = Gauge( |
| 'websocket_connected', |
| 'WebSocket connection status (0=disconnected, 1=connected)' |
| ) |
|
|
| |
| websocket_reconnects_total = Counter( |
| 'websocket_reconnects_total', |
| 'Total number of WebSocket reconnections' |
| ) |
|
|
| |
| websocket_messages_total = Counter( |
| 'websocket_messages_total', |
| 'Total number of WebSocket messages received', |
| ['message_type'] |
| ) |
|
|
| |
| |
| |
|
|
| |
| rating_sync_duration_seconds = Histogram( |
| 'rating_sync_duration_seconds', |
| 'Duration of rating sync operations in seconds', |
| ['status'], |
| buckets=[0.5, 1.0, 2.0, 5.0, 10.0, 30.0, 60.0] |
| ) |
|
|
| |
| rating_sync_success_total = Counter( |
| 'rating_sync_success_total', |
| 'Total number of successful rating sync operations' |
| ) |
|
|
| |
| rating_sync_errors_total = Counter( |
| 'rating_sync_errors_total', |
| 'Total number of rating sync errors', |
| ['error_type'] |
| ) |
|
|
| |
| rating_sync_pending = Gauge( |
| 'rating_sync_pending', |
| 'Number of ratings pending sync to Atom SaaS' |
| ) |
|
|
| |
| rating_sync_failed_uploads = Gauge( |
| 'rating_sync_failed_uploads', |
| 'Number of failed rating uploads awaiting retry' |
| ) |
|
|
| |
| |
| |
|
|
| |
| conflicts_detected_total = Counter( |
| 'conflicts_detected_total', |
| 'Total number of sync conflicts detected', |
| ['conflict_type'] |
| ) |
|
|
| |
| conflicts_resolved_total = Counter( |
| 'conflicts_resolved_total', |
| 'Total number of conflicts resolved', |
| ['resolution_strategy'] |
| ) |
|
|
| |
| conflicts_unresolved = Gauge( |
| 'conflicts_unresolved', |
| 'Number of unresolved conflicts' |
| ) |
|
|
| |
| |
| |
|
|
| def record_sync_operation(operation: str, duration_seconds: float, success: bool, error_type: Optional[str] = None): |
| """ |
| Record sync operation metrics |
| |
| Args: |
| operation: Operation type (skills, categories, ratings) |
| duration_seconds: Operation duration in seconds |
| success: Whether operation succeeded |
| error_type: Error type if failed (e.g., timeout, network_error, api_error) |
| """ |
| status = 'success' if success else 'error' |
| sync_duration_seconds.labels(operation=operation, status=status).observe(duration_seconds) |
|
|
| if success: |
| sync_success_total.labels(operation=operation).inc() |
| else: |
| sync_errors_total.labels(operation=operation, error_type=error_type or 'unknown').inc() |
|
|
|
|
| def update_cache_metrics(skills_count: int, categories_count: int): |
| """ |
| Update cache size metrics |
| |
| Args: |
| skills_count: Number of skills in cache |
| categories_count: Number of categories in cache |
| """ |
| sync_skills_cached.set(skills_count) |
| sync_categories_cached.set(categories_count) |
|
|
|
|
| def set_websocket_connected(connected: bool): |
| """ |
| Update WebSocket connection status |
| |
| Args: |
| connected: Whether WebSocket is connected |
| """ |
| websocket_connected.set(1 if connected else 0) |
|
|
|
|
| def record_websocket_reconnect(): |
| """Record WebSocket reconnection event""" |
| websocket_reconnects_total.inc() |
|
|
|
|
| def record_websocket_message(message_type: str): |
| """ |
| Record received WebSocket message |
| |
| Args: |
| message_type: Type of message (skill_update, rating_update, etc.) |
| """ |
| websocket_messages_total.labels(message_type=message_type).inc() |
|
|
|
|
| def record_rating_sync(duration_seconds: float, success: bool, error_type: Optional[str] = None): |
| """ |
| Record rating sync metrics |
| |
| Args: |
| duration_seconds: Sync duration in seconds |
| success: Whether sync succeeded |
| error_type: Error type if failed |
| """ |
| status = 'success' if success else 'error' |
| rating_sync_duration_seconds.labels(status=status).observe(duration_seconds) |
|
|
| if success: |
| rating_sync_success_total.inc() |
| else: |
| rating_sync_errors_total.labels(error_type=error_type or 'unknown').inc() |
|
|
|
|
| def update_rating_sync_metrics(pending: int, failed_uploads: int): |
| """ |
| Update rating sync state metrics |
| |
| Args: |
| pending: Number of pending ratings |
| failed_uploads: Number of failed uploads |
| """ |
| rating_sync_pending.set(pending) |
| rating_sync_failed_uploads.set(failed_uploads) |
|
|
|
|
| def record_conflict_detected(conflict_type: str): |
| """ |
| Record conflict detection |
| |
| Args: |
| conflict_type: Type of conflict (version_mismatch, data_conflict, etc.) |
| """ |
| conflicts_detected_total.labels(conflict_type=conflict_type).inc() |
| conflicts_unresolved.inc() |
|
|
|
|
| def record_conflict_resolved(resolution_strategy: str): |
| """ |
| Record conflict resolution |
| |
| Args: |
| resolution_strategy: Strategy used (local_wins, remote_wins, merge) |
| """ |
| conflicts_resolved_total.labels(resolution_strategy=resolution_strategy).inc() |
| conflicts_unresolved.dec() |
|
|
|
|
| |
| |
| |
|
|
| def initialize_metrics(): |
| """ |
| Initialize sync metrics with default values |
| Called on application startup to set all gauges to known values |
| """ |
| sync_skills_cached.set(0) |
| sync_categories_cached.set(0) |
| websocket_connected.set(0) |
| rating_sync_pending.set(0) |
| rating_sync_failed_uploads.set(0) |
| conflicts_unresolved.set(0) |
|
|
| logger.info("Sync metrics initialized with default values") |
|
|
|
|
| |
| initialize_metrics() |
|
|