mirror of
https://github.com/chrislusf/seaweedfs
synced 2025-06-29 16:22:46 +02:00
* add telemetry * fix go mod * add default telemetry server url * Update README.md * replace with broker count instead of s3 count * Update telemetry.pb.go * github action to deploy
152 lines
3.7 KiB
Go
152 lines
3.7 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/seaweedfs/seaweedfs/telemetry/proto"
|
|
"github.com/seaweedfs/seaweedfs/telemetry/server/storage"
|
|
protobuf "google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
type Handler struct {
|
|
storage *storage.PrometheusStorage
|
|
}
|
|
|
|
func NewHandler(storage *storage.PrometheusStorage) *Handler {
|
|
return &Handler{storage: storage}
|
|
}
|
|
|
|
func (h *Handler) CollectTelemetry(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
contentType := r.Header.Get("Content-Type")
|
|
|
|
// Only accept protobuf content type
|
|
if contentType != "application/x-protobuf" && contentType != "application/protobuf" {
|
|
http.Error(w, "Content-Type must be application/x-protobuf", http.StatusUnsupportedMediaType)
|
|
return
|
|
}
|
|
|
|
// Read protobuf request
|
|
body, err := io.ReadAll(r.Body)
|
|
if err != nil {
|
|
http.Error(w, "Failed to read request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
req := &proto.TelemetryRequest{}
|
|
if err := protobuf.Unmarshal(body, req); err != nil {
|
|
http.Error(w, "Invalid protobuf data", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
data := req.Data
|
|
if data == nil {
|
|
http.Error(w, "Missing telemetry data", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Validate required fields
|
|
if data.ClusterId == "" || data.Version == "" || data.Os == "" {
|
|
http.Error(w, "Missing required fields", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Set timestamp if not provided
|
|
if data.Timestamp == 0 {
|
|
data.Timestamp = time.Now().Unix()
|
|
}
|
|
|
|
// Store the telemetry data
|
|
if err := h.storage.StoreTelemetry(data); err != nil {
|
|
http.Error(w, "Failed to store data", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Return protobuf response
|
|
resp := &proto.TelemetryResponse{
|
|
Success: true,
|
|
Message: "Telemetry data received",
|
|
}
|
|
|
|
respData, err := protobuf.Marshal(resp)
|
|
if err != nil {
|
|
http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/x-protobuf")
|
|
w.WriteHeader(http.StatusOK)
|
|
w.Write(respData)
|
|
}
|
|
|
|
func (h *Handler) GetStats(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
stats, err := h.storage.GetStats()
|
|
if err != nil {
|
|
http.Error(w, "Failed to get stats", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(stats)
|
|
}
|
|
|
|
func (h *Handler) GetInstances(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
limitStr := r.URL.Query().Get("limit")
|
|
limit := 100 // default
|
|
if limitStr != "" {
|
|
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 1000 {
|
|
limit = l
|
|
}
|
|
}
|
|
|
|
instances, err := h.storage.GetInstances(limit)
|
|
if err != nil {
|
|
http.Error(w, "Failed to get instances", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(instances)
|
|
}
|
|
|
|
func (h *Handler) GetMetrics(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
daysStr := r.URL.Query().Get("days")
|
|
days := 30 // default
|
|
if daysStr != "" {
|
|
if d, err := strconv.Atoi(daysStr); err == nil && d > 0 && d <= 365 {
|
|
days = d
|
|
}
|
|
}
|
|
|
|
metrics, err := h.storage.GetMetrics(days)
|
|
if err != nil {
|
|
http.Error(w, "Failed to get metrics", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(metrics)
|
|
}
|