handlers.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package api
  2. import (
  3. "encoding/json"
  4. "io"
  5. "net/http"
  6. "strconv"
  7. "time"
  8. "github.com/seaweedfs/seaweedfs/telemetry/proto"
  9. "github.com/seaweedfs/seaweedfs/telemetry/server/storage"
  10. protobuf "google.golang.org/protobuf/proto"
  11. )
  12. type Handler struct {
  13. storage *storage.PrometheusStorage
  14. }
  15. func NewHandler(storage *storage.PrometheusStorage) *Handler {
  16. return &Handler{storage: storage}
  17. }
  18. func (h *Handler) CollectTelemetry(w http.ResponseWriter, r *http.Request) {
  19. if r.Method != http.MethodPost {
  20. http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
  21. return
  22. }
  23. contentType := r.Header.Get("Content-Type")
  24. // Only accept protobuf content type
  25. if contentType != "application/x-protobuf" && contentType != "application/protobuf" {
  26. http.Error(w, "Content-Type must be application/x-protobuf", http.StatusUnsupportedMediaType)
  27. return
  28. }
  29. // Read protobuf request
  30. body, err := io.ReadAll(r.Body)
  31. if err != nil {
  32. http.Error(w, "Failed to read request body", http.StatusBadRequest)
  33. return
  34. }
  35. req := &proto.TelemetryRequest{}
  36. if err := protobuf.Unmarshal(body, req); err != nil {
  37. http.Error(w, "Invalid protobuf data", http.StatusBadRequest)
  38. return
  39. }
  40. data := req.Data
  41. if data == nil {
  42. http.Error(w, "Missing telemetry data", http.StatusBadRequest)
  43. return
  44. }
  45. // Validate required fields
  46. if data.ClusterId == "" || data.Version == "" || data.Os == "" {
  47. http.Error(w, "Missing required fields", http.StatusBadRequest)
  48. return
  49. }
  50. // Set timestamp if not provided
  51. if data.Timestamp == 0 {
  52. data.Timestamp = time.Now().Unix()
  53. }
  54. // Store the telemetry data
  55. if err := h.storage.StoreTelemetry(data); err != nil {
  56. http.Error(w, "Failed to store data", http.StatusInternalServerError)
  57. return
  58. }
  59. // Return protobuf response
  60. resp := &proto.TelemetryResponse{
  61. Success: true,
  62. Message: "Telemetry data received",
  63. }
  64. respData, err := protobuf.Marshal(resp)
  65. if err != nil {
  66. http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
  67. return
  68. }
  69. w.Header().Set("Content-Type", "application/x-protobuf")
  70. w.WriteHeader(http.StatusOK)
  71. w.Write(respData)
  72. }
  73. func (h *Handler) GetStats(w http.ResponseWriter, r *http.Request) {
  74. if r.Method != http.MethodGet {
  75. http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
  76. return
  77. }
  78. stats, err := h.storage.GetStats()
  79. if err != nil {
  80. http.Error(w, "Failed to get stats", http.StatusInternalServerError)
  81. return
  82. }
  83. w.Header().Set("Content-Type", "application/json")
  84. json.NewEncoder(w).Encode(stats)
  85. }
  86. func (h *Handler) GetInstances(w http.ResponseWriter, r *http.Request) {
  87. if r.Method != http.MethodGet {
  88. http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
  89. return
  90. }
  91. limitStr := r.URL.Query().Get("limit")
  92. limit := 100 // default
  93. if limitStr != "" {
  94. if l, err := strconv.Atoi(limitStr); err == nil && l > 0 && l <= 1000 {
  95. limit = l
  96. }
  97. }
  98. instances, err := h.storage.GetInstances(limit)
  99. if err != nil {
  100. http.Error(w, "Failed to get instances", http.StatusInternalServerError)
  101. return
  102. }
  103. w.Header().Set("Content-Type", "application/json")
  104. json.NewEncoder(w).Encode(instances)
  105. }
  106. func (h *Handler) GetMetrics(w http.ResponseWriter, r *http.Request) {
  107. if r.Method != http.MethodGet {
  108. http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
  109. return
  110. }
  111. daysStr := r.URL.Query().Get("days")
  112. days := 30 // default
  113. if daysStr != "" {
  114. if d, err := strconv.Atoi(daysStr); err == nil && d > 0 && d <= 365 {
  115. days = d
  116. }
  117. }
  118. metrics, err := h.storage.GetMetrics(days)
  119. if err != nil {
  120. http.Error(w, "Failed to get metrics", http.StatusInternalServerError)
  121. return
  122. }
  123. w.Header().Set("Content-Type", "application/json")
  124. json.NewEncoder(w).Encode(metrics)
  125. }