mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
* telemetry: tidy the server module after the protobuf bump Claude-Session: https://claude.ai/code/session_01VGiphDxpsKMwu9XpUFhybQ * telemetry: keep only clusters that store at least 10 GiB Fresh weed server runs, CI jobs and throwaway containers each mint their own cluster id. They came in at tens of thousands a day, were most of the counted clusters and held almost none of the bytes, and the state file and the metrics page grew with every one of them. Reports under the floor are counted and dropped, and a state file written before the floor sheds them on the first restart. Claude-Session: https://claude.ai/code/session_01VGiphDxpsKMwu9XpUFhybQ * master: report telemetry only once the cluster stores 10 GiB A throwaway cluster no longer registers itself with its first report a minute after start; a real one begins reporting at the first daily tick after it crosses the floor. Claude-Session: https://claude.ai/code/session_01VGiphDxpsKMwu9XpUFhybQ
110 lines
3.1 KiB
Go
110 lines
3.1 KiB
Go
package storage
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/seaweedfs/seaweedfs/telemetry/proto"
|
|
)
|
|
|
|
func TestStateRoundTrip(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "data", "telemetry-state.json")
|
|
|
|
s := newPrometheusStorage(prometheus.NewRegistry())
|
|
|
|
if err := s.SaveStateIfDirty(path); err != nil {
|
|
t.Fatalf("clean save: %v", err)
|
|
}
|
|
if _, err := s.LoadState(path); err != nil {
|
|
t.Fatalf("load with no state file: %v", err)
|
|
}
|
|
|
|
report := &proto.TelemetryData{
|
|
TopologyId: "test-cluster-1",
|
|
Version: "4.40",
|
|
Os: "linux/amd64",
|
|
VolumeServerCount: 5,
|
|
TotalDiskBytes: 123 << 30,
|
|
TotalVolumeCount: 42,
|
|
FilerCount: 2,
|
|
BrokerCount: 1,
|
|
Timestamp: time.Now().Unix(),
|
|
}
|
|
if err := s.StoreTelemetry(report); err != nil {
|
|
t.Fatalf("store: %v", err)
|
|
}
|
|
receivedAt := s.instances[report.TopologyId].ReceivedAt
|
|
|
|
if err := s.SaveStateIfDirty(path); err != nil {
|
|
t.Fatalf("save: %v", err)
|
|
}
|
|
if s.dirty {
|
|
t.Fatal("dirty flag not cleared after save")
|
|
}
|
|
|
|
// Simulate a restart: wipe the in-memory map, then restore.
|
|
s.instances = make(map[string]*telemetryData)
|
|
n, err := s.LoadState(path)
|
|
if err != nil {
|
|
t.Fatalf("load: %v", err)
|
|
}
|
|
if n != 1 {
|
|
t.Fatalf("loaded %d instances, want 1", n)
|
|
}
|
|
|
|
got, ok := s.instances[report.TopologyId]
|
|
if !ok {
|
|
t.Fatal("instance missing after load")
|
|
}
|
|
if !got.ReceivedAt.Equal(receivedAt) {
|
|
t.Errorf("ReceivedAt not preserved: got %v, want %v", got.ReceivedAt, receivedAt)
|
|
}
|
|
if got.TelemetryData.TotalDiskBytes != report.TotalDiskBytes ||
|
|
got.TelemetryData.Version != report.Version ||
|
|
got.TelemetryData.VolumeServerCount != report.VolumeServerCount {
|
|
t.Errorf("fields not preserved: got %+v", got.TelemetryData)
|
|
}
|
|
|
|
// Load must not mark state dirty.
|
|
if s.dirty {
|
|
t.Error("dirty flag set after load")
|
|
}
|
|
}
|
|
|
|
// State written before versions were recorded still knows the version of the
|
|
// report its newest sample came from: the instance record's.
|
|
func TestLoadStateFillsNewestSampleVersion(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "telemetry-state.json")
|
|
|
|
s := newPrometheusStorage(prometheus.NewRegistry())
|
|
report := &proto.TelemetryData{TopologyId: "test-cluster-1", Version: "4.40", Os: "linux/amd64", TotalDiskBytes: proto.MinDiskBytes}
|
|
if err := s.StoreTelemetry(report); err != nil {
|
|
t.Fatalf("store: %v", err)
|
|
}
|
|
yesterday := time.Now().AddDate(0, 0, -1).Unix()
|
|
s.histories[report.TopologyId] = []HistorySample{
|
|
{Ts: yesterday, TotalDiskBytes: 10},
|
|
{Ts: time.Now().Unix(), TotalDiskBytes: 20},
|
|
}
|
|
if err := s.SaveStateIfDirty(path); err != nil {
|
|
t.Fatalf("save: %v", err)
|
|
}
|
|
|
|
s = newPrometheusStorage(prometheus.NewRegistry())
|
|
if _, err := s.LoadState(path); err != nil {
|
|
t.Fatalf("load: %v", err)
|
|
}
|
|
loaded := s.histories[report.TopologyId]
|
|
if len(loaded) != 2 {
|
|
t.Fatalf("history = %+v, want 2 samples", loaded)
|
|
}
|
|
if loaded[1].Version != report.Version {
|
|
t.Errorf("newest sample version = %q, want %q", loaded[1].Version, report.Version)
|
|
}
|
|
if loaded[0].Version != "" {
|
|
t.Errorf("older sample version = %q, want it left unknown", loaded[0].Version)
|
|
}
|
|
}
|