mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-05-06 20:02:41 +08:00
* 功能: v2.1 可观测性与流控 — Prometheus + 节点带宽 + 审计 Webhook 核心能力: - Prometheus /metrics 端点:11 类指标(任务/存储/节点/SLA/验证/恢复/复制) - 节点级带宽限速生效:model.Node.BandwidthLimit 覆盖全局默认 - 审计日志 Webhook 外输:HMAC-SHA256 签名,配合 SIEM 合规留档 实现: - server/internal/metrics/ 独立 Registry + 异步 Gauge Collector(30s) - backup/restore/verify/replication 服务注入 metrics 钩子,nil 安全 - resolveProviderForNode() 按 task.NodeID 解析 BandwidthLimit - AuditService.SetWebhook + 动态 settings 推送,无需重启 测试: - metrics/registry_test.go: 注册/采集/nil safety/HTTP handler - service/audit_service_webhook_test.go: 签名正确性/异步投递/禁用路径 - go test ./... 全部通过 * chore: 触发 CodeQL 扫描
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
package metrics
|
|
|
|
import (
|
|
"io"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/prometheus/client_golang/prometheus/testutil"
|
|
)
|
|
|
|
func TestNew_AppInfoVersionLabel(t *testing.T) {
|
|
m := New("2.1.0")
|
|
if got := testutil.ToFloat64(m.AppInfo.WithLabelValues("2.1.0")); got != 1 {
|
|
t.Fatalf("app_info(version=2.1.0) expected 1, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestObserveTaskRun_IncrementsCounterAndHistogram(t *testing.T) {
|
|
m := New("test")
|
|
m.ObserveTaskRun("mysql", "success", 12.5, 1024)
|
|
m.ObserveTaskRun("mysql", "failed", 3.0, 0)
|
|
if got := testutil.ToFloat64(m.TaskRunTotal.WithLabelValues("success", "mysql")); got != 1 {
|
|
t.Fatalf("task_run_total{status=success,task_type=mysql}: expected 1, got %v", got)
|
|
}
|
|
if got := testutil.ToFloat64(m.TaskRunTotal.WithLabelValues("failed", "mysql")); got != 1 {
|
|
t.Fatalf("task_run_total{status=failed,task_type=mysql}: expected 1, got %v", got)
|
|
}
|
|
if got := testutil.ToFloat64(m.TaskBytesTotal.WithLabelValues("mysql")); got != 1024 {
|
|
t.Fatalf("task_bytes_total{task_type=mysql}: expected 1024, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestObserveTaskRun_NilReceiverIsSafe(t *testing.T) {
|
|
var m *Metrics // nil
|
|
m.ObserveTaskRun("file", "success", 1, 1)
|
|
m.ObserveRestore("success")
|
|
m.ObserveVerify("failed")
|
|
m.ObserveReplication("success")
|
|
m.IncTaskRunning()
|
|
m.DecTaskRunning()
|
|
m.SetStorageUsed("a", "s3", 1)
|
|
m.SetNodeOnline("n1", "master", true)
|
|
m.SetSLABreach(3)
|
|
m.ResetNodeOnline()
|
|
m.ResetStorageUsed()
|
|
// no panic -> pass
|
|
}
|
|
|
|
func TestHandler_ExposesBackupxMetrics(t *testing.T) {
|
|
m := New("0.0.0-test")
|
|
m.ObserveTaskRun("file", "success", 1.0, 2048)
|
|
m.SetNodeOnline("n1", "master", true)
|
|
m.SetSLABreach(1)
|
|
|
|
recorder := httptest.NewRecorder()
|
|
req := httptest.NewRequest("GET", "/metrics", nil)
|
|
m.Handler().ServeHTTP(recorder, req)
|
|
|
|
body, err := io.ReadAll(recorder.Result().Body)
|
|
if err != nil {
|
|
t.Fatalf("read body: %v", err)
|
|
}
|
|
content := string(body)
|
|
for _, keyword := range []string{
|
|
"backupx_task_run_total",
|
|
"backupx_task_run_duration_seconds",
|
|
"backupx_node_online",
|
|
"backupx_sla_breach_tasks",
|
|
"backupx_app_info",
|
|
} {
|
|
if !strings.Contains(content, keyword) {
|
|
t.Errorf("expected /metrics to contain %q", keyword)
|
|
}
|
|
}
|
|
}
|