github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/distributor/http_admin.go (about) 1 package distributor 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "html/template" 7 "net/http" 8 "sort" 9 "strings" 10 "time" 11 12 "github.com/cortexproject/cortex/pkg/util" 13 ) 14 15 const tpl = ` 16 <!DOCTYPE html> 17 <html> 18 <head> 19 <meta charset="UTF-8"> 20 <title>Cortex Ingester Stats</title> 21 </head> 22 <body> 23 <h1>Cortex Ingester Stats</h1> 24 <p>Current time: {{ .Now }}</p> 25 <p><b>NB stats do not account for replication factor, which is currently set to {{ .ReplicationFactor }}</b></p> 26 <form action="" method="POST"> 27 <input type="hidden" name="csrf_token" value="$__CSRF_TOKEN_PLACEHOLDER__"> 28 <table border="1"> 29 <thead> 30 <tr> 31 <th>User</th> 32 <th># Series</th> 33 <th>Total Ingest Rate</th> 34 <th>API Ingest Rate</th> 35 <th>Rule Ingest Rate</th> 36 </tr> 37 </thead> 38 <tbody> 39 {{ range .Stats }} 40 <tr> 41 <td>{{ .UserID }}</td> 42 <td align='right'>{{ .UserStats.NumSeries }}</td> 43 <td align='right'>{{ printf "%.2f" .UserStats.IngestionRate }}</td> 44 <td align='right'>{{ printf "%.2f" .UserStats.APIIngestionRate }}</td> 45 <td align='right'>{{ printf "%.2f" .UserStats.RuleIngestionRate }}</td> 46 </tr> 47 {{ end }} 48 </tbody> 49 </table> 50 </form> 51 </body> 52 </html>` 53 54 var tmpl *template.Template 55 56 func init() { 57 tmpl = template.Must(template.New("webpage").Parse(tpl)) 58 } 59 60 type userStatsByTimeseries []UserIDStats 61 62 func (s userStatsByTimeseries) Len() int { return len(s) } 63 func (s userStatsByTimeseries) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 64 65 func (s userStatsByTimeseries) Less(i, j int) bool { 66 return s[i].NumSeries > s[j].NumSeries || 67 (s[i].NumSeries == s[j].NumSeries && s[i].UserID < s[j].UserID) 68 } 69 70 // AllUserStatsHandler shows stats for all users. 71 func (d *Distributor) AllUserStatsHandler(w http.ResponseWriter, r *http.Request) { 72 stats, err := d.AllUserStats(r.Context()) 73 if err != nil { 74 http.Error(w, err.Error(), http.StatusInternalServerError) 75 return 76 } 77 78 sort.Sort(userStatsByTimeseries(stats)) 79 80 if encodings, found := r.Header["Accept"]; found && 81 len(encodings) > 0 && strings.Contains(encodings[0], "json") { 82 if err := json.NewEncoder(w).Encode(stats); err != nil { 83 http.Error(w, fmt.Sprintf("Error marshalling response: %v", err), http.StatusInternalServerError) 84 } 85 return 86 } 87 88 util.RenderHTTPResponse(w, struct { 89 Now time.Time `json:"now"` 90 Stats []UserIDStats `json:"stats"` 91 ReplicationFactor int `json:"replicationFactor"` 92 }{ 93 Now: time.Now(), 94 Stats: stats, 95 ReplicationFactor: d.ingestersRing.ReplicationFactor(), 96 }, tmpl, r) 97 }