diff --git a/changelog/unreleased/sysinfo-prometheus.md b/changelog/unreleased/sysinfo-prometheus.md new file mode 100644 index 0000000000..798eea0cb0 --- /dev/null +++ b/changelog/unreleased/sysinfo-prometheus.md @@ -0,0 +1,5 @@ +Enhancement: System information included in Prometheus metrics + +System information is now included in the main Prometheus metrics exposed at `/metrics`. + +https://github.com/cs3org/reva/pull/1071 diff --git a/go.sum b/go.sum index 1801fc4768..62d00181b5 100644 --- a/go.sum +++ b/go.sum @@ -586,6 +586,7 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1: github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -593,6 +594,7 @@ github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -601,6 +603,7 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.6 h1:0qbH+Yqu/cj1ViVLvEWCP6qMQ4efWUj6bQqOEA0V0U4= github.com/prometheus/procfs v0.0.6/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/statsd_exporter v0.15.0 h1:UiwC1L5HkxEPeapXdm2Ye0u1vUJfTj7uwT5yydYpa1E= github.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7WL1zHKK7WMqFQqu72rw= @@ -880,6 +883,7 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20u golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1041,6 +1045,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= diff --git a/internal/http/services/prometheus/prometheus.go b/internal/http/services/prometheus/prometheus.go index d1392dc499..99f2bd5f3b 100644 --- a/internal/http/services/prometheus/prometheus.go +++ b/internal/http/services/prometheus/prometheus.go @@ -22,12 +22,15 @@ import ( "net/http" "contrib.go.opencensus.io/exporter/prometheus" - "github.com/cs3org/reva/pkg/rhttp/global" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" + promclient "github.com/prometheus/client_golang/prometheus" "github.com/rs/zerolog" "go.opencensus.io/stats/view" + "github.com/cs3org/reva/pkg/rhttp/global" + "github.com/cs3org/reva/pkg/sysinfo" + // Initializes goroutines which periodically update stats _ "github.com/cs3org/reva/pkg/metrics/reader/dummy" ) @@ -45,15 +48,23 @@ func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) conf.init() + registry := promclient.NewRegistry() // A Prometheus registry shared by OpenCensus and SysInfo pe, err := prometheus.NewExporter(prometheus.Options{ Namespace: "revad", + Registry: registry, }) if err != nil { return nil, errors.Wrap(err, "prometheus: error creating exporter") } + // Initialize the SysInfo Prometheus exporter + sysinfo, err := sysinfo.NewPrometheusExporter(registry) + if err != nil { + return nil, errors.Wrap(err, "prometheus: unable to create system info exporter") + } + view.RegisterExporter(pe) - return &svc{prefix: conf.Prefix, h: pe}, nil + return &svc{prefix: conf.Prefix, h: pe, sysinfo: sysinfo}, nil } type config struct { @@ -69,6 +80,8 @@ func (c *config) init() { type svc struct { prefix string h http.Handler + + sysinfo *sysinfo.PrometheusExporter } func (s *svc) Prefix() string { diff --git a/internal/http/services/sysinfo/sysinfo.go b/internal/http/services/sysinfo/sysinfo.go index b2c20154bf..24fcd71edb 100644 --- a/internal/http/services/sysinfo/sysinfo.go +++ b/internal/http/services/sysinfo/sysinfo.go @@ -20,7 +20,6 @@ package sysinfo import ( "net/http" - "strings" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" @@ -41,8 +40,6 @@ type config struct { type svc struct { conf *config - - promHandler *prometheusSysInfoHandler } const ( @@ -67,24 +64,9 @@ func (s *svc) Unprotected() []string { // Handler serves all HTTP requests. func (s *svc) Handler() http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt := strings.ToLower(r.URL.Query().Get("format")) - if len(fmt) == 0 { - // No format was specified, so let Prometheus handle the request - s.promHandler.httpHandler.ServeHTTP(w, r) - } else { - // Otherwise, provide the system information in the requested format - data := "" - switch fmt { - case "json": - data = s.getJSONData() - default: - data = "Unsupported format" - } - - log := appctx.GetLogger(r.Context()) - if _, err := w.Write([]byte(data)); err != nil { - log.Err(err).Msg("error writing SysInfo response") - } + log := appctx.GetLogger(r.Context()) + if _, err := w.Write([]byte(s.getJSONData())); err != nil { + log.Err(err).Msg("error writing SysInfo response") } }) } @@ -120,16 +102,9 @@ func New(m map[string]interface{}, log *zerolog.Logger) (global.Service, error) return nil, err } - // Create the Prometheus system information handler - promHandler := &prometheusSysInfoHandler{} - if err := promHandler.init(); err != nil { - return nil, err - } - // Create the service s := &svc{ - conf: conf, - promHandler: promHandler, + conf: conf, } return s, nil } diff --git a/internal/http/services/sysinfo/prometheus.go b/pkg/sysinfo/prometheus.go similarity index 77% rename from internal/http/services/sysinfo/prometheus.go rename to pkg/sysinfo/prometheus.go index 98ddeb0821..f327cb4010 100644 --- a/internal/http/services/sysinfo/prometheus.go +++ b/pkg/sysinfo/prometheus.go @@ -20,46 +20,41 @@ package sysinfo import ( "fmt" - "net/http" "reflect" "strings" "github.com/prometheus/client_golang/prometheus" - "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/cs3org/reva/pkg/sysinfo" "github.com/cs3org/reva/pkg/utils" ) -type prometheusSysInfoHandler struct { +// PrometheusExporter exports system information via Prometheus. +type PrometheusExporter struct { registry *prometheus.Registry sysInfoMetric prometheus.GaugeFunc - - httpHandler http.Handler } -func (psysinfo *prometheusSysInfoHandler) init() error { +func (psysinfo *PrometheusExporter) init(registry *prometheus.Registry) error { // Create all necessary Prometheus objects - psysinfo.registry = prometheus.NewRegistry() + psysinfo.registry = registry psysinfo.sysInfoMetric = prometheus.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: "revad", Name: "sys_info", Help: "A metric with a constant '1' value labeled by various system information elements", - ConstLabels: psysinfo.getLabels("", sysinfo.SysInfo), + ConstLabels: psysinfo.getLabels("", SysInfo), }, func() float64 { return 1 }, ) - psysinfo.httpHandler = promhttp.HandlerFor(psysinfo.registry, promhttp.HandlerOpts{}) if err := psysinfo.registry.Register(psysinfo.sysInfoMetric); err != nil { - return fmt.Errorf("unable to register the system information metric: %v", err) + return fmt.Errorf("unable to register the system information metrics: %v", err) } return nil } -func (psysinfo *prometheusSysInfoHandler) getLabels(root string, i interface{}) prometheus.Labels { +func (psysinfo *PrometheusExporter) getLabels(root string, i interface{}) prometheus.Labels { labels := prometheus.Labels{} // Iterate over each field of the given interface, recursively collecting the values as labels @@ -92,3 +87,17 @@ func (psysinfo *prometheusSysInfoHandler) getLabels(root string, i interface{}) return labels } + +// NewPrometheusExporter creates a new Prometheus system information exporter. +func NewPrometheusExporter(registry *prometheus.Registry) (*PrometheusExporter, error) { + if registry == nil { + return nil, fmt.Errorf("no registry provided") + } + + exporter := &PrometheusExporter{} + if err := exporter.init(registry); err != nil { + return nil, err + } + + return exporter, nil +}