(metric: McpLifecycleMetric)
| 585 | } |
| 586 | |
| 587 | export function recordMcpLifecycleMetric(metric: McpLifecycleMetric): void { |
| 588 | if (!shouldEmitMetrics()) { |
| 589 | return; |
| 590 | } |
| 591 | |
| 592 | const attributes = { |
| 593 | runtime: 'mcp', |
| 594 | event: sanitizeTagValue(metric.event), |
| 595 | phase: sanitizeTagValue(metric.phase), |
| 596 | ...(metric.reason ? { reason: sanitizeTagValue(metric.reason) } : {}), |
| 597 | watcher_running: String(metric.watcherRunning), |
| 598 | has_active_operations: String(metric.activeOperationCount > 0), |
| 599 | }; |
| 600 | |
| 601 | try { |
| 602 | Sentry.metrics.count('xcodebuildmcp.mcp.lifecycle.count', 1, { attributes }); |
| 603 | Sentry.metrics.distribution( |
| 604 | 'xcodebuildmcp.mcp.lifecycle.uptime_ms', |
| 605 | Math.max(0, metric.uptimeMs), |
| 606 | { attributes }, |
| 607 | ); |
| 608 | Sentry.metrics.distribution( |
| 609 | 'xcodebuildmcp.mcp.lifecycle.rss_bytes', |
| 610 | Math.max(0, metric.rssBytes), |
| 611 | { attributes }, |
| 612 | ); |
| 613 | if (metric.matchingMcpProcessCount != null) { |
| 614 | Sentry.metrics.distribution( |
| 615 | 'xcodebuildmcp.mcp.lifecycle.process_count', |
| 616 | Math.max(0, metric.matchingMcpProcessCount), |
| 617 | { attributes }, |
| 618 | ); |
| 619 | } |
| 620 | } catch { |
| 621 | // Metrics are best effort and must never affect runtime behavior. |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | export function recordMcpLifecycleAnomalyMetric(metric: McpLifecycleAnomalyMetric): void { |
| 626 | if (!shouldEmitMetrics()) { |
no test coverage detected