yanic/webserver/prometheus/exporter.go

125 lines
3.0 KiB
Go
Raw Normal View History

2022-07-09 20:20:48 +02:00
package prometheus
import (
"io"
"net"
"net/http"
"time"
"github.com/bdlm/log"
"github.com/FreifunkBremen/yanic/respond"
"github.com/FreifunkBremen/yanic/runtime"
)
type Exporter struct {
config Config
srv *http.Server
coll *respond.Collector
nodes *runtime.Nodes
}
func (ex *Exporter) ServeHTTP(res http.ResponseWriter, req *http.Request) {
var ip net.IP
nodeID := ""
queryValues := req.URL.Query()
if nodeIDs := queryValues["node_id"]; len(nodeIDs) > 0 {
nodeID = nodeIDs[0]
node, ok := ex.nodes.List[nodeID]
if !ok || node.Address == nil {
http.Error(res, "not able to get node by cached nodeid", http.StatusNotFound)
return
}
ip = node.Address.IP
if ex.writeNode(res, node, true) {
log.WithFields(map[string]interface{}{
"ip": ip,
"node_id": nodeID,
}).Debug("take node from cache")
return
}
} else if ipstr := queryValues["ip"]; len(ipstr) > 0 {
ip = net.ParseIP(ipstr[0])
if ip == nil {
http.Error(res, "not able to parse ip address", http.StatusBadRequest)
return
}
node_select := ex.nodes.Select(func(n *runtime.Node) bool {
n_addr := n.Address
nodeID = n.Nodeinfo.NodeID
return n_addr != nil && ip.Equal(n_addr.IP)
})
if len(node_select) == 1 {
if ex.writeNode(res, node_select[0], true) {
log.WithFields(map[string]interface{}{
"ip": ip,
"node_id": nodeID,
}).Debug("take node from cache")
return
}
} else if len(node_select) > 1 {
log.Error("strange count of nodes")
}
} else {
http.Error(res, "please request with ?ip= or ?node_id=", http.StatusNotFound)
return
}
// send request
ex.coll.SendPacket(ip)
// wait
log.WithFields(map[string]interface{}{
"ip": ip,
"node_id": nodeID,
}).Debug("waited for")
time.Sleep(ex.config.Wait.Duration)
// result
node, ok := ex.nodes.List[nodeID]
if !ok {
http.Error(res, "not able to fetch this node", http.StatusGatewayTimeout)
return
}
ex.writeNode(res, node, false)
}
func (ex *Exporter) writeNode(res http.ResponseWriter, node *runtime.Node, dry bool) bool {
logger := log.WithField("database", "prometheus")
if nodeinfo := node.Nodeinfo; nodeinfo != nil {
logger = logger.WithField("node_id", nodeinfo.NodeID)
}
if !time.Now().Before(node.Lastseen.GetTime().Add(ex.config.Outdated.Duration)) {
if dry {
return false
}
m := Metric{Labels: MetricLabelsFromNode(node), Name: "yanic_node_up", Value: 0}
str, err := m.String()
if err == nil {
_, err = io.WriteString(res, str+"\n")
}
if err != nil {
logger.Warnf("not able to get metrics from node: %s", err)
http.Error(res, "not able to generate metric from node", http.StatusInternalServerError)
}
return false
}
metrics := MetricsFromNode(ex.nodes, node)
for _, m := range metrics {
str, err := m.String()
if err == nil {
_, err = io.WriteString(res, str+"\n")
}
if err != nil {
logger.Warnf("not able to get metrics from node: %s", err)
http.Error(res, "not able to generate metric from node", http.StatusInternalServerError)
}
}
return true
}