frp/server/monitor/prometheus.go
2019-12-08 20:16:03 +08:00

215 lines
6.8 KiB
Go

package monitor
import (
"net/http"
"strconv"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/server/stats"
"github.com/fatedier/frp/utils/version"
"github.com/fatedier/frp/utils/xlog"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
type Prometheus struct {
statsCollector stats.Collector
config config.ServerCommonConf
}
func NewPrometheus(statsCollector stats.Collector, config config.ServerCommonConf) *Prometheus {
return &Prometheus{
statsCollector: statsCollector,
config: config,
}
}
var (
serverBindPort = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "frps_server_bind_port",
Help: "The port of server frps.",
}, []string{"address", "version"})
serverBindUdpPort = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_bind_udp_port",
Help: "The udp port of server frps.",
})
serverHeartBeatTimeout = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_heartbeat_timeout",
Help: "The heartbeat timeout of server frps.",
})
serverKcpBindPort = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_kcp_bind_port",
Help: "The kcp port of server frps.",
})
serverMaxPoolCount = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_max_poolcount",
Help: "The max poolcount of server frps.",
})
serverVhostHttpPort = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "frps_server_http_port",
Help: "The http port of server frps.",
}, []string{"subdomain"})
serverMaxPortsPerClient = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_maxport_perclient",
Help: "The maxport perclient of server frps.",
})
serverVhostHttpsPort = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "frps_server_https_port",
Help: "The https port of server frps.",
}, []string{"subdomain"})
serverClientCounts = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_client_counts",
Help: "The client counts of server frps.",
})
serverCurConns = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_current_connections",
Help: "The current connections of server frps.",
})
serverTotalTrafficIn = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_total_trafficin",
Help: "The total trafficin of server frps.",
})
serverTotalTrafficOut = prometheus.NewGauge(prometheus.GaugeOpts{
Name: "frps_server_total_trafficout",
Help: "The total trafficout of server frps.",
})
)
type ProxyStats struct {
Proxys []*stats.ProxyStats
}
func NewProxyStats(Proxys []*stats.ProxyStats) *ProxyStats {
return &ProxyStats{
Proxys: Proxys,
}
}
func (s *ProxyStats) Describe(ch chan<- *prometheus.Desc) {}
func (s *ProxyStats) Collect(ch chan<- prometheus.Metric) {
dealWithProxyStats(s.Proxys, ch)
}
func setValue(cfg config.ServerCommonConf) {
serverBindPort.With(prometheus.Labels{"address": cfg.BindAddr, "version": version.Full()}).Set(float64(cfg.BindPort))
serverBindUdpPort.Set(float64(cfg.BindUdpPort))
serverVhostHttpsPort.With(prometheus.Labels{"subdomain": cfg.SubDomainHost}).Set(float64(cfg.VhostHttpsPort))
serverVhostHttpPort.With(prometheus.Labels{"subdomain": cfg.SubDomainHost}).Set(float64(cfg.VhostHttpPort))
serverMaxPortsPerClient.Set(float64(cfg.MaxPortsPerClient))
serverMaxPoolCount.Set(float64(cfg.MaxPoolCount))
serverKcpBindPort.Set(float64(cfg.KcpBindPort))
serverHeartBeatTimeout.Set(float64(cfg.HeartBeatTimeout))
}
func (p *Prometheus) dealWithServerStats(ServerStats *stats.ServerStats) {
serverClientCounts.Set(float64(ServerStats.ClientCounts))
serverCurConns.Set(float64(ServerStats.CurConns))
serverTotalTrafficIn.Set(float64(ServerStats.TotalTrafficIn))
serverTotalTrafficOut.Set(float64(ServerStats.TotalTrafficOut))
}
func dealWithProxyStats(ProxyStats []*stats.ProxyStats, ch chan<- prometheus.Metric) {
for _, v := range ProxyStats {
// Get the constant labels
var Labels = []string{"type", "laststarttime", "lastclosetime"}
var labelValue = []string{v.Type, v.LastStartTime, v.LastCloseTime}
//set value type
vType := prometheus.GaugeValue
//get name
name := "frps_" + v.Name + "_today_trafficin"
//get description
description := "The today trafficin of proxy."
//registry
desc := prometheus.NewDesc(name, description, Labels, nil)
ch <- prometheus.MustNewConstMetric(desc, vType, float64(v.TodayTrafficIn), labelValue...)
//get name
name = "frps_" + v.Name + "_today_trafficout"
description = "The today trafficout of proxy."
//registry
desc = prometheus.NewDesc(name, description, Labels, nil)
ch <- prometheus.MustNewConstMetric(desc, vType, float64(v.TodayTrafficOut), labelValue...)
//get name
name = "frps_" + v.Name + "_currconns"
description = "The today currconns of proxy."
//registry
desc = prometheus.NewDesc(name, description, Labels, nil)
ch <- prometheus.MustNewConstMetric(desc, vType, float64(v.CurConns), labelValue...)
}
}
func (p *Prometheus) handle(xl *xlog.Logger, w http.ResponseWriter, r *http.Request) {
//init config metrics
setValue(p.config)
//deal with server stat.
ServerStats := p.statsCollector.GetServer()
p.dealWithServerStats(ServerStats)
var Proxys []*stats.ProxyStats
for k, _ := range ServerStats.ProxyTypeCounts {
ProxyStats := p.statsCollector.GetProxiesByType(k)
Proxys = append(Proxys, ProxyStats...)
}
//NewProxyStats
proxyStats := NewProxyStats(Proxys)
//new registry
registry := prometheus.NewRegistry()
//registry exporter
registry.MustRegister(proxyStats)
registry.MustRegister(serverBindPort)
registry.MustRegister(serverBindUdpPort)
registry.MustRegister(serverVhostHttpPort)
registry.MustRegister(serverVhostHttpsPort)
registry.MustRegister(serverKcpBindPort)
registry.MustRegister(serverMaxPoolCount)
registry.MustRegister(serverMaxPortsPerClient)
registry.MustRegister(serverHeartBeatTimeout)
registry.MustRegister(serverClientCounts)
registry.MustRegister(serverCurConns)
registry.MustRegister(serverTotalTrafficIn)
registry.MustRegister(serverTotalTrafficOut)
//http server
h := promhttp.HandlerFor(registry, promhttp.HandlerOpts{})
h.ServeHTTP(w, r)
}
func (p *Prometheus) Start() {
//init log
xl := xlog.New()
xl.Debug("Start To Export Data For Prometheus Metrics")
//script metrics
http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
p.handle(xl, w, r)
})
//root
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(`<html>
<head><title>frps Exporter</title></head>
<body>
<h1>frps Exporter</h1>
<p><a href="\metrics">Metrics</a></p>
</body>
</html>`))
})
listenAddress := p.config.PromesAddr + ":" + strconv.Itoa(p.config.PromesPort)
xl.Info("prometheus exporter listen on %s:%d", p.config.PromesAddr, p.config.PromesPort)
//listen
if err := http.ListenAndServe(listenAddress, nil); err != nil {
xl.Error("Error starting HTTP server: %s", err)
}
}