File size: 7,658 Bytes
383cb38 | 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 | """
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 Operation Metrics
# ============================================================================
# Sync duration histogram (measures time for sync operations)
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]
)
# Total successful syncs counter
sync_success_total = Counter(
'sync_success_total',
'Total number of successful sync operations',
['operation']
)
# Total sync errors counter
sync_errors_total = Counter(
'sync_errors_total',
'Total number of sync errors',
['operation', 'error_type']
)
# Skills in cache gauge
sync_skills_cached = Gauge(
'sync_skills_cached',
'Number of skills currently in cache'
)
# Categories in cache gauge
sync_categories_cached = Gauge(
'sync_categories_cached',
'Number of categories currently in cache'
)
# ============================================================================
# WebSocket Metrics
# ============================================================================
# WebSocket connection status gauge (0=disconnected, 1=connected)
websocket_connected = Gauge(
'websocket_connected',
'WebSocket connection status (0=disconnected, 1=connected)'
)
# WebSocket reconnections counter
websocket_reconnects_total = Counter(
'websocket_reconnects_total',
'Total number of WebSocket reconnections'
)
# WebSocket messages received counter
websocket_messages_total = Counter(
'websocket_messages_total',
'Total number of WebSocket messages received',
['message_type']
)
# ============================================================================
# Rating Sync Metrics
# ============================================================================
# Rating sync duration histogram
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]
)
# Successful rating syncs counter
rating_sync_success_total = Counter(
'rating_sync_success_total',
'Total number of successful rating sync operations'
)
# Rating sync errors counter
rating_sync_errors_total = Counter(
'rating_sync_errors_total',
'Total number of rating sync errors',
['error_type']
)
# Pending ratings gauge
rating_sync_pending = Gauge(
'rating_sync_pending',
'Number of ratings pending sync to Atom SaaS'
)
# Failed rating uploads gauge
rating_sync_failed_uploads = Gauge(
'rating_sync_failed_uploads',
'Number of failed rating uploads awaiting retry'
)
# ============================================================================
# Conflict Resolution Metrics
# ============================================================================
# Conflicts detected counter
conflicts_detected_total = Counter(
'conflicts_detected_total',
'Total number of sync conflicts detected',
['conflict_type']
)
# Conflicts resolved counter
conflicts_resolved_total = Counter(
'conflicts_resolved_total',
'Total number of conflicts resolved',
['resolution_strategy']
)
# Unresolved conflicts gauge
conflicts_unresolved = Gauge(
'conflicts_unresolved',
'Number of unresolved conflicts'
)
# ============================================================================
# Metrics Update Functions
# ============================================================================
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()
# ============================================================================
# Metrics Initialization
# ============================================================================
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")
# Auto-initialize on module import
initialize_metrics()
|