2021-05-04 04:44:54 +03:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2021-05-12 04:41:35 +03:00
|
|
|
"fmt"
|
2021-05-04 04:44:54 +03:00
|
|
|
"net/http"
|
|
|
|
|
2021-05-10 05:06:33 +03:00
|
|
|
"github.com/tidwall/tile38/core"
|
2022-09-13 18:16:41 +03:00
|
|
|
"github.com/tidwall/tile38/internal/collection"
|
2021-05-10 05:06:33 +03:00
|
|
|
|
2021-05-04 04:44:54 +03:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2022-09-13 03:06:27 +03:00
|
|
|
"github.com/prometheus/client_golang/prometheus/collectors"
|
2021-05-04 04:44:54 +03:00
|
|
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
metricDescriptions = map[string]*prometheus.Desc{
|
|
|
|
/*
|
|
|
|
these metrics are taken from basicStats() / extStats()
|
|
|
|
by accessing the map and directly exporting the value found
|
|
|
|
*/
|
2021-05-10 17:54:38 +03:00
|
|
|
"num_collections": prometheus.NewDesc("tile38_collections", "Total number of collections", nil, nil),
|
2021-05-04 04:44:54 +03:00
|
|
|
"pid": prometheus.NewDesc("tile38_pid", "", nil, nil),
|
|
|
|
"aof_size": prometheus.NewDesc("tile38_aof_size_bytes", "", nil, nil),
|
2021-05-12 04:41:35 +03:00
|
|
|
"num_hooks": prometheus.NewDesc("tile38_hooks", "", nil, nil),
|
2021-05-04 04:44:54 +03:00
|
|
|
"in_memory_size": prometheus.NewDesc("tile38_in_memory_size_bytes", "", nil, nil),
|
|
|
|
"heap_size": prometheus.NewDesc("tile38_heap_size_bytes", "", nil, nil),
|
|
|
|
"heap_released": prometheus.NewDesc("tile38_memory_reap_released_bytes", "", nil, nil),
|
|
|
|
"max_heap_size": prometheus.NewDesc("tile38_memory_max_heap_size_bytes", "", nil, nil),
|
|
|
|
"avg_item_size": prometheus.NewDesc("tile38_avg_item_size_bytes", "", nil, nil),
|
|
|
|
"pointer_size": prometheus.NewDesc("tile38_pointer_size_bytes", "", nil, nil),
|
|
|
|
"cpus": prometheus.NewDesc("tile38_num_cpus", "", nil, nil),
|
|
|
|
"tile38_connected_clients": prometheus.NewDesc("tile38_connected_clients", "", nil, nil),
|
|
|
|
|
2021-05-12 04:41:35 +03:00
|
|
|
"tile38_total_connections_received": prometheus.NewDesc("tile38_connections_received_total", "", nil, nil),
|
|
|
|
"tile38_total_messages_sent": prometheus.NewDesc("tile38_messages_sent_total", "", nil, nil),
|
|
|
|
"tile38_expired_keys": prometheus.NewDesc("tile38_expired_keys_total", "", nil, nil),
|
|
|
|
|
2021-05-04 04:44:54 +03:00
|
|
|
/*
|
|
|
|
these metrics are NOT taken from basicStats() / extStats()
|
|
|
|
but are calculated independently
|
|
|
|
*/
|
|
|
|
"collection_objects": prometheus.NewDesc("tile38_collection_objects", "Total number of objects per collection", []string{"col"}, nil),
|
|
|
|
"collection_points": prometheus.NewDesc("tile38_collection_points", "Total number of points per collection", []string{"col"}, nil),
|
|
|
|
"collection_strings": prometheus.NewDesc("tile38_collection_strings", "Total number of strings per collection", []string{"col"}, nil),
|
|
|
|
"collection_weight": prometheus.NewDesc("tile38_collection_weight_bytes", "Total weight of collection in bytes", []string{"col"}, nil),
|
|
|
|
"server_info": prometheus.NewDesc("tile38_server_info", "Server info", []string{"id", "version"}, nil),
|
2021-05-12 04:41:35 +03:00
|
|
|
"replication": prometheus.NewDesc("tile38_replication_info", "Replication info", []string{"role", "following", "caught_up", "caught_up_once"}, nil),
|
|
|
|
"start_time": prometheus.NewDesc("tile38_start_time_seconds", "", nil, nil),
|
2021-05-04 04:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cmdDurations = prometheus.NewSummaryVec(prometheus.SummaryOpts{
|
|
|
|
Name: "tile38_cmd_duration_seconds",
|
|
|
|
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
|
|
|
|
}, []string{"cmd"},
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2021-05-12 04:41:35 +03:00
|
|
|
func (s *Server) MetricsIndexHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Write([]byte(`<html><head>
|
|
|
|
<title>Tile38 ` + core.Version + `</title></head>
|
|
|
|
<body><h1>Tile38 ` + core.Version + `</h1>
|
|
|
|
<p><a href='/metrics'>Metrics</a></p>
|
|
|
|
</body></html>`))
|
|
|
|
}
|
|
|
|
|
2021-05-04 04:44:54 +03:00
|
|
|
func (s *Server) MetricsHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
reg := prometheus.NewRegistry()
|
|
|
|
|
|
|
|
reg.MustRegister(
|
2022-09-13 03:06:27 +03:00
|
|
|
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
|
|
|
|
collectors.NewGoCollector(),
|
|
|
|
collectors.NewBuildInfoCollector(),
|
2021-05-04 04:44:54 +03:00
|
|
|
cmdDurations,
|
|
|
|
s,
|
|
|
|
)
|
|
|
|
|
2021-05-10 17:54:38 +03:00
|
|
|
promhttp.HandlerFor(reg, promhttp.HandlerOpts{}).ServeHTTP(w, r)
|
2021-05-04 04:44:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) Describe(ch chan<- *prometheus.Desc) {
|
|
|
|
for _, desc := range metricDescriptions {
|
|
|
|
ch <- desc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) Collect(ch chan<- prometheus.Metric) {
|
2021-05-10 17:54:38 +03:00
|
|
|
s.mu.RLock()
|
|
|
|
defer s.mu.RUnlock()
|
|
|
|
|
2021-05-04 04:44:54 +03:00
|
|
|
m := make(map[string]interface{})
|
|
|
|
s.basicStats(m)
|
|
|
|
s.extStats(m)
|
|
|
|
|
|
|
|
for metric, descr := range metricDescriptions {
|
2024-02-12 21:48:18 +03:00
|
|
|
val, ok := toFloat(m[metric])
|
2022-09-25 00:01:36 +03:00
|
|
|
if ok {
|
2021-05-04 04:44:54 +03:00
|
|
|
ch <- prometheus.MustNewConstMetric(descr, prometheus.GaugeValue, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-10 05:06:33 +03:00
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["server_info"],
|
2021-05-12 04:41:35 +03:00
|
|
|
prometheus.GaugeValue, 1.0,
|
|
|
|
s.config.serverID(), core.Version)
|
|
|
|
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["start_time"],
|
|
|
|
prometheus.GaugeValue, float64(s.started.Unix()))
|
|
|
|
|
|
|
|
replLbls := []string{"leader", "", "", ""}
|
|
|
|
if s.config.followHost() != "" {
|
|
|
|
replLbls = []string{"follower",
|
|
|
|
fmt.Sprintf("%s:%d", s.config.followHost(), s.config.followPort()),
|
|
|
|
fmt.Sprintf("%t", s.fcup), fmt.Sprintf("%t", s.fcuponce)}
|
|
|
|
}
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["replication"],
|
|
|
|
prometheus.GaugeValue, 1.0,
|
|
|
|
replLbls...)
|
2021-05-10 05:06:33 +03:00
|
|
|
|
2021-05-04 04:44:54 +03:00
|
|
|
/*
|
2021-05-10 17:54:38 +03:00
|
|
|
add objects/points/strings stats for each collection
|
2021-05-04 04:44:54 +03:00
|
|
|
*/
|
2022-09-13 18:16:41 +03:00
|
|
|
s.cols.Scan(func(key string, col *collection.Collection) bool {
|
2021-05-04 04:44:54 +03:00
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["collection_objects"],
|
|
|
|
prometheus.GaugeValue,
|
2022-09-13 18:16:41 +03:00
|
|
|
float64(col.Count()),
|
|
|
|
key,
|
2021-05-04 04:44:54 +03:00
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["collection_points"],
|
|
|
|
prometheus.GaugeValue,
|
2022-09-13 18:16:41 +03:00
|
|
|
float64(col.PointCount()),
|
|
|
|
key,
|
2021-05-04 04:44:54 +03:00
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["collection_strings"],
|
|
|
|
prometheus.GaugeValue,
|
2022-09-13 18:16:41 +03:00
|
|
|
float64(col.StringCount()),
|
|
|
|
key,
|
2021-05-04 04:44:54 +03:00
|
|
|
)
|
|
|
|
ch <- prometheus.MustNewConstMetric(
|
|
|
|
metricDescriptions["collection_weight"],
|
|
|
|
prometheus.GaugeValue,
|
2022-09-13 18:16:41 +03:00
|
|
|
float64(col.TotalWeight()),
|
|
|
|
key,
|
2021-05-04 04:44:54 +03:00
|
|
|
)
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
}
|
2024-02-12 21:48:18 +03:00
|
|
|
|
|
|
|
func toFloat(val interface{}) (float64, bool) {
|
|
|
|
switch v := val.(type) {
|
|
|
|
case float64:
|
|
|
|
return v, true
|
|
|
|
case int64:
|
|
|
|
return float64(v), true
|
|
|
|
case uint64:
|
|
|
|
return float64(v), true
|
|
|
|
case float32:
|
|
|
|
return float64(v), true
|
|
|
|
case int:
|
|
|
|
return float64(v), true
|
|
|
|
case int32:
|
|
|
|
return float64(v), true
|
|
|
|
case uint32:
|
|
|
|
return float64(v), true
|
|
|
|
case int16:
|
|
|
|
return float64(v), true
|
|
|
|
case uint16:
|
|
|
|
return float64(v), true
|
|
|
|
case int8:
|
|
|
|
return float64(v), true
|
|
|
|
case uint8:
|
|
|
|
return float64(v), true
|
|
|
|
}
|
|
|
|
return 0, false
|
|
|
|
}
|