package app import ( "sync/atomic" "time" ) type MonitoringHeartbeatSnapshotMetricsSnapshot struct { PlatformReportedTotal int64 `json:"platform_reported_total"` TransactionOpenedTotal int64 `json:"transaction_opened_total"` SnapshotInsertedTotal int64 `json:"snapshot_inserted_total"` SnapshotUpdatedTotal int64 `json:"snapshot_updated_total"` SnapshotRefreshedTotal int64 `json:"snapshot_refreshed_total"` SnapshotSkippedTotal int64 `json:"snapshot_skipped_total"` ReconciledSkippedTaskTotal int64 `json:"reconciled_skipped_task_total"` ProjectionRebuildTotal int64 `json:"projection_rebuild_total"` ErrorTotal int64 `json:"error_total"` DurationCount int64 `json:"duration_count"` DurationSumSeconds float64 `json:"duration_sum_seconds"` LastDurationSeconds float64 `json:"last_duration_seconds"` LastErrorCode string `json:"last_error_code,omitempty"` LastErrorMessage string `json:"last_error_message,omitempty"` } type monitoringHeartbeatSnapshotMetricsEvent struct { Active bool PlatformCount int TransactionOpened bool SnapshotInsertedCount int64 SnapshotUpdatedCount int64 SnapshotRefreshedCount int64 SnapshotSkippedCount int64 ReconciledSkippedTaskCount int64 ProjectionRebuildCount int64 Duration time.Duration Err error } type monitoringHeartbeatSnapshotMetricsRecorder struct { platformReportedTotal atomic.Int64 transactionOpenedTotal atomic.Int64 snapshotInsertedTotal atomic.Int64 snapshotUpdatedTotal atomic.Int64 snapshotRefreshedTotal atomic.Int64 snapshotSkippedTotal atomic.Int64 reconciledSkippedTaskTotal atomic.Int64 projectionRebuildTotal atomic.Int64 errorTotal atomic.Int64 durationCount atomic.Int64 durationSumNanos atomic.Int64 lastDurationNanos atomic.Int64 lastErrorCode atomic.Value lastErrorMessage atomic.Value } var monitoringHeartbeatSnapshotMetrics = newMonitoringHeartbeatSnapshotMetricsRecorder() func newMonitoringHeartbeatSnapshotMetricsRecorder() *monitoringHeartbeatSnapshotMetricsRecorder { return &monitoringHeartbeatSnapshotMetricsRecorder{} } func recordMonitoringHeartbeatSnapshotMetrics(event monitoringHeartbeatSnapshotMetricsEvent) { monitoringHeartbeatSnapshotMetrics.record(event) } func MonitoringHeartbeatSnapshotMetricsSnapshotValue() MonitoringHeartbeatSnapshotMetricsSnapshot { return monitoringHeartbeatSnapshotMetrics.snapshot() } func resetMonitoringHeartbeatSnapshotMetricsForTest() { monitoringHeartbeatSnapshotMetrics = newMonitoringHeartbeatSnapshotMetricsRecorder() } func (r *monitoringHeartbeatSnapshotMetricsRecorder) record(event monitoringHeartbeatSnapshotMetricsEvent) { if r == nil { return } if event.Duration < 0 { event.Duration = 0 } r.platformReportedTotal.Add(int64(event.PlatformCount)) if event.TransactionOpened { r.transactionOpenedTotal.Add(1) } r.snapshotInsertedTotal.Add(event.SnapshotInsertedCount) r.snapshotUpdatedTotal.Add(event.SnapshotUpdatedCount) r.snapshotRefreshedTotal.Add(event.SnapshotRefreshedCount) r.snapshotSkippedTotal.Add(event.SnapshotSkippedCount) r.reconciledSkippedTaskTotal.Add(event.ReconciledSkippedTaskCount) r.projectionRebuildTotal.Add(event.ProjectionRebuildCount) r.durationCount.Add(1) r.durationSumNanos.Add(event.Duration.Nanoseconds()) r.lastDurationNanos.Store(event.Duration.Nanoseconds()) if event.Err != nil { code, message := monitoringDailyMetricError(event.Err) r.errorTotal.Add(1) r.lastErrorCode.Store(code) r.lastErrorMessage.Store(message) } } func (r *monitoringHeartbeatSnapshotMetricsRecorder) snapshot() MonitoringHeartbeatSnapshotMetricsSnapshot { if r == nil { return MonitoringHeartbeatSnapshotMetricsSnapshot{} } return MonitoringHeartbeatSnapshotMetricsSnapshot{ PlatformReportedTotal: r.platformReportedTotal.Load(), TransactionOpenedTotal: r.transactionOpenedTotal.Load(), SnapshotInsertedTotal: r.snapshotInsertedTotal.Load(), SnapshotUpdatedTotal: r.snapshotUpdatedTotal.Load(), SnapshotRefreshedTotal: r.snapshotRefreshedTotal.Load(), SnapshotSkippedTotal: r.snapshotSkippedTotal.Load(), ReconciledSkippedTaskTotal: r.reconciledSkippedTaskTotal.Load(), ProjectionRebuildTotal: r.projectionRebuildTotal.Load(), ErrorTotal: r.errorTotal.Load(), DurationCount: r.durationCount.Load(), DurationSumSeconds: float64(r.durationSumNanos.Load()) / float64(time.Second), LastDurationSeconds: float64(r.lastDurationNanos.Load()) / float64(time.Second), LastErrorCode: monitoringDailyLoadString(&r.lastErrorCode), LastErrorMessage: monitoringDailyLoadString(&r.lastErrorMessage), } }