snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
119
weed/telemetry/client.go
Normal file
119
weed/telemetry/client.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/seaweedfs/seaweedfs/telemetry/proto"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
protobuf "google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
url string
|
||||
enabled bool
|
||||
instanceID string
|
||||
httpClient *http.Client
|
||||
topologyId string
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// NewClient creates a new telemetry client
|
||||
func NewClient(url string, enabled bool) *Client {
|
||||
return &Client{
|
||||
url: url,
|
||||
enabled: enabled,
|
||||
instanceID: uuid.New().String(), // Generate UUID in memory only
|
||||
httpClient: &http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) SetTopologyId(topologyId string) {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
c.topologyId = topologyId
|
||||
}
|
||||
|
||||
// IsEnabled returns whether telemetry is enabled
|
||||
func (c *Client) IsEnabled() bool {
|
||||
return c.enabled && c.url != ""
|
||||
}
|
||||
|
||||
// SendTelemetry sends telemetry data synchronously using protobuf format
|
||||
func (c *Client) SendTelemetry(data *proto.TelemetryData) error {
|
||||
if !c.IsEnabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Work on a copy to avoid mutating the caller's TelemetryData
|
||||
clonedData, ok := protobuf.Clone(data).(*proto.TelemetryData)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to clone telemetry data")
|
||||
}
|
||||
|
||||
// Set the topology ID
|
||||
c.RLock()
|
||||
if c.topologyId != "" {
|
||||
clonedData.TopologyId = c.topologyId
|
||||
}
|
||||
c.RUnlock()
|
||||
|
||||
return c.sendProtobuf(clonedData)
|
||||
}
|
||||
|
||||
// SendTelemetryAsync sends telemetry data asynchronously
|
||||
func (c *Client) SendTelemetryAsync(data *proto.TelemetryData) {
|
||||
if !c.IsEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := c.SendTelemetry(data); err != nil {
|
||||
glog.V(1).Infof("Failed to send telemetry: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// sendProtobuf sends data using protobuf format
|
||||
func (c *Client) sendProtobuf(data *proto.TelemetryData) error {
|
||||
req := &proto.TelemetryRequest{
|
||||
Data: data,
|
||||
}
|
||||
|
||||
body, err := protobuf.Marshal(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal protobuf: %w", err)
|
||||
}
|
||||
|
||||
httpReq, err := http.NewRequest("POST", c.url, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create request: %w", err)
|
||||
}
|
||||
|
||||
httpReq.Header.Set("Content-Type", "application/x-protobuf")
|
||||
httpReq.Header.Set("User-Agent", fmt.Sprintf("SeaweedFS/%s", data.Version))
|
||||
|
||||
resp, err := c.httpClient.Do(httpReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send request: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("server returned status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
glog.V(2).Infof("Telemetry sent successfully via protobuf")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetInstanceID returns the current instance ID
|
||||
func (c *Client) GetInstanceID() string {
|
||||
return c.instanceID
|
||||
}
|
||||
228
weed/telemetry/collector.go
Normal file
228
weed/telemetry/collector.go
Normal file
@@ -0,0 +1,228 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/telemetry/proto"
|
||||
"github.com/seaweedfs/seaweedfs/weed/cluster"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
||||
"github.com/seaweedfs/seaweedfs/weed/topology"
|
||||
)
|
||||
|
||||
// Collector gathers telemetry data from a SeaweedFS cluster
|
||||
// Only the leader master will send telemetry to avoid duplicates
|
||||
type Collector struct {
|
||||
client *Client
|
||||
topo *topology.Topology
|
||||
cluster *cluster.Cluster
|
||||
masterServer interface{} // Will be set to *weed_server.MasterServer to access client tracking
|
||||
version string
|
||||
os string
|
||||
}
|
||||
|
||||
// NewCollector creates a new telemetry collector
|
||||
func NewCollector(client *Client, topo *topology.Topology, cluster *cluster.Cluster) *Collector {
|
||||
return &Collector{
|
||||
client: client,
|
||||
topo: topo,
|
||||
cluster: cluster,
|
||||
masterServer: nil,
|
||||
version: "unknown",
|
||||
os: "unknown",
|
||||
}
|
||||
}
|
||||
|
||||
// SetVersion sets the SeaweedFS version
|
||||
func (c *Collector) SetVersion(version string) {
|
||||
c.version = version
|
||||
}
|
||||
|
||||
// SetOS sets the operating system information
|
||||
func (c *Collector) SetOS(os string) {
|
||||
c.os = os
|
||||
}
|
||||
|
||||
// SetMasterServer sets a reference to the master server for client tracking
|
||||
func (c *Collector) SetMasterServer(masterServer interface{}) {
|
||||
c.masterServer = masterServer
|
||||
}
|
||||
|
||||
// isLeader checks if this master is the leader
|
||||
func (c *Collector) isLeader() bool {
|
||||
if c.topo == nil {
|
||||
return false
|
||||
}
|
||||
return c.topo.IsLeader()
|
||||
}
|
||||
|
||||
// CollectAndSendAsync collects telemetry data and sends it asynchronously
|
||||
// Only sends telemetry if this master is the leader
|
||||
func (c *Collector) CollectAndSendAsync() {
|
||||
if !c.client.IsEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
if c.topo != nil {
|
||||
c.client.SetTopologyId(c.topo.GetTopologyId())
|
||||
}
|
||||
|
||||
go func() {
|
||||
if data := c.collectData(); data != nil {
|
||||
c.client.SendTelemetryAsync(data)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// StartPeriodicCollection starts sending telemetry data periodically
|
||||
func (c *Collector) StartPeriodicCollection(interval time.Duration) {
|
||||
if !c.client.IsEnabled() {
|
||||
glog.V(1).Infof("Telemetry is disabled, skipping periodic collection")
|
||||
return
|
||||
}
|
||||
|
||||
glog.V(0).Infof("Reporting anonymous cluster statistics to %s every %v once %d GiB are stored, use -telemetry=false to opt out", c.client.url, interval, proto.MinDiskBytes>>30)
|
||||
|
||||
// Send initial telemetry after a short delay
|
||||
go func() {
|
||||
time.Sleep(61 * time.Second) // Wait for cluster to stabilize
|
||||
if c.isLeader() {
|
||||
c.CollectAndSendAsync()
|
||||
} else {
|
||||
glog.V(2).Infof("Skipping initial telemetry collection - not the leader master")
|
||||
}
|
||||
}()
|
||||
|
||||
// Start periodic collection
|
||||
ticker := time.NewTicker(interval)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
// Check leadership before each collection
|
||||
if c.isLeader() {
|
||||
c.CollectAndSendAsync()
|
||||
} else {
|
||||
glog.V(2).Infof("Skipping periodic telemetry collection - not the leader master")
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// collectData gathers telemetry data from the topology. It returns nil while
|
||||
// the cluster stores less than proto.MinDiskBytes, so throwaway clusters never
|
||||
// report.
|
||||
func (c *Collector) collectData() *proto.TelemetryData {
|
||||
data := &proto.TelemetryData{
|
||||
Version: c.version,
|
||||
Os: c.os,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
if c.topo != nil {
|
||||
// Collect volume server count
|
||||
data.VolumeServerCount = int32(c.countVolumeServers())
|
||||
|
||||
// Collect total disk usage and volume count
|
||||
diskBytes, volumeCount := c.collectVolumeStats()
|
||||
data.TotalDiskBytes = diskBytes
|
||||
data.TotalVolumeCount = int32(volumeCount)
|
||||
}
|
||||
|
||||
if c.cluster != nil {
|
||||
// Collect filer and broker counts
|
||||
data.FilerCount = int32(c.countFilers())
|
||||
data.BrokerCount = int32(c.countBrokers())
|
||||
}
|
||||
|
||||
if data.TotalDiskBytes < proto.MinDiskBytes {
|
||||
glog.V(2).Infof("Skipping telemetry: %d bytes stored, reporting starts at %d", data.TotalDiskBytes, proto.MinDiskBytes)
|
||||
return nil
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// countVolumeServers counts the number of active volume servers
|
||||
func (c *Collector) countVolumeServers() int {
|
||||
count := 0
|
||||
for _, dcNode := range c.topo.Children() {
|
||||
dc := dcNode.(*topology.DataCenter)
|
||||
for _, rackNode := range dc.Children() {
|
||||
rack := rackNode.(*topology.Rack)
|
||||
for range rack.Children() {
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// collectVolumeStats collects total disk usage and volume count
|
||||
func (c *Collector) collectVolumeStats() (uint64, int) {
|
||||
var totalDiskBytes uint64
|
||||
var totalVolumeCount int
|
||||
ecVolumeIds := make(map[needle.VolumeId]struct{})
|
||||
|
||||
for _, dcNode := range c.topo.Children() {
|
||||
dc := dcNode.(*topology.DataCenter)
|
||||
for _, rackNode := range dc.Children() {
|
||||
rack := rackNode.(*topology.Rack)
|
||||
for _, dnNode := range rack.Children() {
|
||||
dn := dnNode.(*topology.DataNode)
|
||||
volumes := dn.GetVolumes()
|
||||
for _, volumeInfo := range volumes {
|
||||
totalVolumeCount++
|
||||
totalDiskBytes += volumeInfo.Size
|
||||
}
|
||||
// An encoded volume leaves GetVolumes and is reported as
|
||||
// shards, so without this a cluster reports none of the
|
||||
// bytes it erasure-coded. Every shard copy counts, parity
|
||||
// included, the way a replicated volume counts every replica.
|
||||
for _, ecInfo := range dn.GetEcShards() {
|
||||
totalDiskBytes += uint64(ecInfo.ShardsInfo.TotalSize())
|
||||
// One volume's shards are spread over many nodes, so
|
||||
// count the volume once rather than once per holder.
|
||||
ecVolumeIds[ecInfo.VolumeId] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalDiskBytes, totalVolumeCount + len(ecVolumeIds)
|
||||
}
|
||||
|
||||
// countFilers counts the number of active filer servers across all groups
|
||||
func (c *Collector) countFilers() int {
|
||||
// Count all filer-type nodes in the cluster
|
||||
// This includes both pure filer servers and S3 servers (which register as filers)
|
||||
count := 0
|
||||
for _, groupName := range c.getAllFilerGroups() {
|
||||
nodes := c.cluster.ListClusterNode(cluster.FilerGroupName(groupName), cluster.FilerType)
|
||||
count += len(nodes)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// countBrokers counts the number of active broker servers
|
||||
func (c *Collector) countBrokers() int {
|
||||
// Count brokers across all broker groups
|
||||
count := 0
|
||||
for _, groupName := range c.getAllBrokerGroups() {
|
||||
nodes := c.cluster.ListClusterNode(cluster.FilerGroupName(groupName), cluster.BrokerType)
|
||||
count += len(nodes)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// getAllFilerGroups returns all filer group names
|
||||
func (c *Collector) getAllFilerGroups() []string {
|
||||
// For simplicity, we check the default group
|
||||
// In a more sophisticated implementation, we could enumerate all groups
|
||||
return []string{""}
|
||||
}
|
||||
|
||||
// getAllBrokerGroups returns all broker group names
|
||||
func (c *Collector) getAllBrokerGroups() []string {
|
||||
// For simplicity, we check the default group
|
||||
// In a more sophisticated implementation, we could enumerate all groups
|
||||
return []string{""}
|
||||
}
|
||||
87
weed/telemetry/collector_test.go
Normal file
87
weed/telemetry/collector_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package telemetry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/telemetry/proto"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/sequence"
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
|
||||
"github.com/seaweedfs/seaweedfs/weed/storage/needle"
|
||||
"github.com/seaweedfs/seaweedfs/weed/topology"
|
||||
)
|
||||
|
||||
// ecShardMessage builds a heartbeat message for the given shard ids, each
|
||||
// sized (id+1)*sizeUnit bytes.
|
||||
func ecShardMessage(vid uint32, sizeUnit int, shardIds ...erasure_coding.ShardId) *master_pb.VolumeEcShardInformationMessage {
|
||||
shards := erasure_coding.NewShardsInfo()
|
||||
for _, id := range shardIds {
|
||||
shards.Set(erasure_coding.NewShardInfo(id, erasure_coding.ShardSize((int(id)+1)*sizeUnit)))
|
||||
}
|
||||
return &master_pb.VolumeEcShardInformationMessage{
|
||||
Id: vid,
|
||||
EcIndexBits: shards.Bitmap(),
|
||||
ShardSizes: shards.SizesInt64(),
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectVolumeStatsCountsEcShards(t *testing.T) {
|
||||
topo := topology.NewTopology("weedfs", sequence.NewMemorySequencer(), 32*1024, 5, false)
|
||||
|
||||
rack := topo.GetOrCreateDataCenter("dc1").GetOrCreateRack("rack1")
|
||||
maxVolumeCounts := map[string]uint32{"": 25}
|
||||
dn1 := rack.GetOrCreateDataNode("127.0.0.1", 34534, 0, "127.0.0.1", "", maxVolumeCounts)
|
||||
dn2 := rack.GetOrCreateDataNode("127.0.0.2", 34534, 0, "127.0.0.2", "", maxVolumeCounts)
|
||||
|
||||
topo.SyncDataNodeRegistration([]*master_pb.VolumeInformationMessage{
|
||||
{Id: 1, Size: 1000, FileCount: 10, Version: uint32(needle.GetCurrentVersion())},
|
||||
{Id: 2, Size: 2000, FileCount: 20, Version: uint32(needle.GetCurrentVersion())},
|
||||
}, dn1)
|
||||
|
||||
// Volume 10's shards span both nodes, with a second copy of shard 0 on
|
||||
// dn2; volume 20 sits entirely on dn1.
|
||||
topo.SyncDataNodeEcShards([]*master_pb.VolumeEcShardInformationMessage{
|
||||
ecShardMessage(10, 100, 0, 1, 2, 3, 4, 5, 6),
|
||||
ecShardMessage(20, 10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
|
||||
}, dn1)
|
||||
topo.SyncDataNodeEcShards([]*master_pb.VolumeEcShardInformationMessage{
|
||||
ecShardMessage(10, 100, 0, 7, 8, 9, 10, 11, 12, 13),
|
||||
}, dn2)
|
||||
|
||||
collector := NewCollector(nil, topo, nil)
|
||||
diskBytes, volumeCount := collector.collectVolumeStats()
|
||||
|
||||
// 3000 from the two regular volumes, plus every shard copy of volume 10
|
||||
// sized (id+1)*100 — 100..700 on dn1, and 800..1400 plus the second copy
|
||||
// of shard 0 on dn2 — and volume 20's 14 shards at (id+1)*10.
|
||||
const expectedDiskBytes = 3000 + 2800 + (7700 + 100) + 1050
|
||||
if diskBytes != expectedDiskBytes {
|
||||
t.Errorf("Expected %d total disk bytes, got %d", expectedDiskBytes, diskBytes)
|
||||
}
|
||||
|
||||
// 2 regular volumes plus EC volumes 10 and 20 — volume 10 counts once
|
||||
// even though two nodes hold its shards.
|
||||
if volumeCount != 4 {
|
||||
t.Errorf("Expected 4 volumes, got %d", volumeCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectDataWaitsForMinDiskBytes(t *testing.T) {
|
||||
topo := topology.NewTopology("weedfs", sequence.NewMemorySequencer(), 32*1024, 5, false)
|
||||
rack := topo.GetOrCreateDataCenter("dc1").GetOrCreateRack("rack1")
|
||||
dn := rack.GetOrCreateDataNode("127.0.0.1", 34534, 0, "127.0.0.1", "", map[string]uint32{"": 25})
|
||||
collector := NewCollector(nil, topo, nil)
|
||||
|
||||
under := &master_pb.VolumeInformationMessage{Id: 1, Size: proto.MinDiskBytes - 1, Version: uint32(needle.GetCurrentVersion())}
|
||||
topo.SyncDataNodeRegistration([]*master_pb.VolumeInformationMessage{under}, dn)
|
||||
if data := collector.collectData(); data != nil {
|
||||
t.Fatalf("cluster under the floor reported %+v", data)
|
||||
}
|
||||
|
||||
one := &master_pb.VolumeInformationMessage{Id: 2, Size: 1, Version: uint32(needle.GetCurrentVersion())}
|
||||
topo.SyncDataNodeRegistration([]*master_pb.VolumeInformationMessage{under, one}, dn)
|
||||
data := collector.collectData()
|
||||
if data == nil || data.TotalDiskBytes != proto.MinDiskBytes {
|
||||
t.Fatalf("cluster on the floor reported %+v", data)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user