File size: 7,658 Bytes
f84a02d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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()