87 lines
2.4 KiB
Go
87 lines
2.4 KiB
Go
package service
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Dependency 依赖名称。
|
|
type Dependency string
|
|
|
|
const (
|
|
DependencyPostgres Dependency = "postgresql"
|
|
DependencyRedis Dependency = "redis"
|
|
DependencyMQTT Dependency = "mqtt"
|
|
DependencyIoTDB Dependency = "iotdb"
|
|
DependencyS3 Dependency = "s3"
|
|
DependencyAI Dependency = "ai"
|
|
DependencyWVP Dependency = "wvp"
|
|
DependencyWechat Dependency = "wechat"
|
|
DependencyWeather Dependency = "weather"
|
|
)
|
|
|
|
// DependencyMetric 依赖调用指标。
|
|
type DependencyMetric struct {
|
|
Requests int64 `json:"requests"`
|
|
Failures int64 `json:"failures"`
|
|
LastLatencyMs float64 `json:"lastLatencyMs"`
|
|
P50LatencyMs float64 `json:"p50LatencyMs"`
|
|
P95LatencyMs float64 `json:"p95LatencyMs"`
|
|
LastSuccessAt *time.Time `json:"lastSuccessAt,omitempty"`
|
|
LastFailureAt *time.Time `json:"lastFailureAt,omitempty"`
|
|
LastError string `json:"lastError,omitempty"`
|
|
}
|
|
|
|
var dependencyMetrics sync.Map
|
|
|
|
// RecordDependency 记录一次依赖调用。
|
|
func RecordDependency(dep Dependency, err error, latency time.Duration) {
|
|
now := time.Now()
|
|
value, _ := dependencyMetrics.LoadOrStore(dep, &DependencyMetric{})
|
|
metric := value.(*DependencyMetric)
|
|
metric.Requests++
|
|
metric.LastLatencyMs = float64(latency.Microseconds()) / 1000
|
|
if err != nil {
|
|
metric.Failures++
|
|
metric.LastFailureAt = &now
|
|
metric.LastError = err.Error()
|
|
} else {
|
|
metric.LastSuccessAt = &now
|
|
metric.LastError = ""
|
|
}
|
|
}
|
|
|
|
// DependencySnapshot 返回当前依赖指标快照。
|
|
func DependencySnapshot() map[Dependency]DependencyMetric {
|
|
result := map[Dependency]DependencyMetric{}
|
|
dependencyMetrics.Range(func(key, value interface{}) bool {
|
|
dep := key.(Dependency)
|
|
metric := *value.(*DependencyMetric)
|
|
result[dep] = metric
|
|
return true
|
|
})
|
|
return result
|
|
}
|
|
|
|
// RecordDependencyHistogram 预留直方图能力;当前仅更新最近一次指标。
|
|
func RecordDependencyHistogram(dep Dependency, err error, latency time.Duration, samples []float64) {
|
|
RecordDependency(dep, err, latency)
|
|
if len(samples) == 0 {
|
|
return
|
|
}
|
|
value, _ := dependencyMetrics.LoadOrStore(dep, &DependencyMetric{})
|
|
metric := value.(*DependencyMetric)
|
|
sort.Float64s(samples)
|
|
metric.P50LatencyMs = percentile(samples, 0.5)
|
|
metric.P95LatencyMs = percentile(samples, 0.95)
|
|
}
|
|
|
|
func percentile(sorted []float64, p float64) float64 {
|
|
if len(sorted) == 0 {
|
|
return 0
|
|
}
|
|
idx := int(float64(len(sorted)-1) * p)
|
|
return sorted[idx]
|
|
}
|