diff options
| author | Chris Lu <chrislusf@users.noreply.github.com> | 2025-06-28 14:11:55 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-28 14:11:55 -0700 |
| commit | a1aab8a083111dd9357c7f35397fdf610f23cb6d (patch) | |
| tree | 66b56b09bec60cd1962236b7aad43a37011450b9 /telemetry/server/main.go | |
| parent | 29892c43ff95ad957c0f64ad5cd11e0d43e616e2 (diff) | |
| download | seaweedfs-a1aab8a083111dd9357c7f35397fdf610f23cb6d.tar.xz seaweedfs-a1aab8a083111dd9357c7f35397fdf610f23cb6d.zip | |
add telemetry (#6926)
* 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
Diffstat (limited to 'telemetry/server/main.go')
| -rw-r--r-- | telemetry/server/main.go | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/telemetry/server/main.go b/telemetry/server/main.go new file mode 100644 index 000000000..6cbae05c7 --- /dev/null +++ b/telemetry/server/main.go @@ -0,0 +1,111 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "log" + "net/http" + "time" + + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/seaweedfs/seaweedfs/telemetry/server/api" + "github.com/seaweedfs/seaweedfs/telemetry/server/dashboard" + "github.com/seaweedfs/seaweedfs/telemetry/server/storage" +) + +var ( + port = flag.Int("port", 8080, "HTTP server port") + enableCORS = flag.Bool("cors", true, "Enable CORS for dashboard") + logRequests = flag.Bool("log", true, "Log incoming requests") + enableDashboard = flag.Bool("dashboard", true, "Enable built-in dashboard (optional when using Grafana)") + cleanupInterval = flag.Duration("cleanup", 24*time.Hour, "Cleanup interval for old instances") + maxInstanceAge = flag.Duration("max-age", 30*24*time.Hour, "Maximum age for instances before cleanup") +) + +func main() { + flag.Parse() + + // Create Prometheus storage instance + store := storage.NewPrometheusStorage() + + // Start cleanup routine + go func() { + ticker := time.NewTicker(*cleanupInterval) + defer ticker.Stop() + for range ticker.C { + store.CleanupOldInstances(*maxInstanceAge) + } + }() + + // Setup HTTP handlers + mux := http.NewServeMux() + + // Prometheus metrics endpoint + mux.Handle("/metrics", promhttp.Handler()) + + // API endpoints + apiHandler := api.NewHandler(store) + mux.HandleFunc("/api/collect", corsMiddleware(logMiddleware(apiHandler.CollectTelemetry))) + mux.HandleFunc("/api/stats", corsMiddleware(logMiddleware(apiHandler.GetStats))) + mux.HandleFunc("/api/instances", corsMiddleware(logMiddleware(apiHandler.GetInstances))) + mux.HandleFunc("/api/metrics", corsMiddleware(logMiddleware(apiHandler.GetMetrics))) + + // Dashboard (optional) + if *enableDashboard { + dashboardHandler := dashboard.NewHandler() + mux.HandleFunc("/", corsMiddleware(dashboardHandler.ServeIndex)) + mux.HandleFunc("/dashboard", corsMiddleware(dashboardHandler.ServeIndex)) + mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static")))) + } + + // Health check + mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(map[string]string{ + "status": "ok", + "time": time.Now().UTC().Format(time.RFC3339), + }) + }) + + addr := fmt.Sprintf(":%d", *port) + log.Printf("Starting telemetry server on %s", addr) + log.Printf("Prometheus metrics: http://localhost%s/metrics", addr) + if *enableDashboard { + log.Printf("Dashboard: http://localhost%s/dashboard", addr) + } + log.Printf("Cleanup interval: %v, Max instance age: %v", *cleanupInterval, *maxInstanceAge) + + if err := http.ListenAndServe(addr, mux); err != nil { + log.Fatalf("Server failed: %v", err) + } +} + +func corsMiddleware(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if *enableCORS { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization") + } + + if r.Method == "OPTIONS" { + w.WriteHeader(http.StatusOK) + return + } + + next(w, r) + } +} + +func logMiddleware(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if *logRequests { + start := time.Now() + next(w, r) + log.Printf("%s %s %s %v", r.Method, r.URL.Path, r.RemoteAddr, time.Since(start)) + } else { + next(w, r) + } + } +} |
