From 5dc9f7dc839ef7d349df01d4e791904b9788691f Mon Sep 17 00:00:00 2001 From: Laszlo Fogas Date: Thu, 30 May 2019 11:11:14 +0200 Subject: [PATCH] Reimlemented metrics --- cmd/drone-server/server.go | 2 + cmd/drone-server/setup.go | 62 ++++- .../client_golang/prometheus/promauto/auto.go | 223 ++++++++++++++++++ vendor/vendor.json | 6 + 4 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go diff --git a/cmd/drone-server/server.go b/cmd/drone-server/server.go index 9c3673368..adabae869 100644 --- a/cmd/drone-server/server.go +++ b/cmd/drone-server/server.go @@ -608,6 +608,8 @@ func server(c *cli.Context) error { return g.Wait() } + setupMetrics(g, store_) + // start the server without tls enabled if !c.Bool("lets-encrypt") { return http.ListenAndServe( diff --git a/cmd/drone-server/setup.go b/cmd/drone-server/setup.go index e95afb177..046f1e2ae 100644 --- a/cmd/drone-server/setup.go +++ b/cmd/drone-server/setup.go @@ -18,8 +18,8 @@ import ( "fmt" "time" - "github.com/laszlocph/drone-oss-08/cncd/queue" "github.com/dimfeld/httptreemux" + "github.com/laszlocph/drone-oss-08/cncd/queue" "github.com/laszlocph/drone-oss-08/model" "github.com/laszlocph/drone-oss-08/plugins/registry" "github.com/laszlocph/drone-oss-08/plugins/secrets" @@ -32,9 +32,13 @@ import ( "github.com/laszlocph/drone-oss-08/remote/gitlab" "github.com/laszlocph/drone-oss-08/remote/gitlab3" "github.com/laszlocph/drone-oss-08/remote/gogs" + droneserver "github.com/laszlocph/drone-oss-08/server" "github.com/laszlocph/drone-oss-08/server/web" "github.com/laszlocph/drone-oss-08/store" "github.com/laszlocph/drone-oss-08/store/datastore" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" + "golang.org/x/sync/errgroup" "github.com/urfave/cli" ) @@ -200,3 +204,59 @@ func setupTree(c *cli.Context) *httptreemux.ContextMux { } func before(c *cli.Context) error { return nil } + +func setupMetrics(g errgroup.Group, store_ store.Store) { + pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "drone", + Name: "pending_jobs", + Help: "Total number of pending build processes.", + }) + runningJobs := promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "drone", + Name: "running_jobs", + Help: "Total number of running build processes.", + }) + workers := promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "drone", + Name: "worker_count", + Help: "Total number of workers.", + }) + builds := promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "drone", + Name: "build_count", + Help: "Total number of builds.", + }) + users := promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "drone", + Name: "user_count", + Help: "Total number of users.", + }) + repos := promauto.NewGauge(prometheus.GaugeOpts{ + Namespace: "drone", + Name: "repo_count", + Help: "Total number of repos.", + }) + + g.Go(func() error { + for { + stats := droneserver.Config.Services.Queue.Info(nil) + pendingJobs.Set(float64(stats.Stats.Pending)) + runningJobs.Set(float64(stats.Stats.Running)) + workers.Set(float64(stats.Stats.Workers)) + + buildCount, _ := store_.GetBuildCount() + builds.Set(float64(buildCount)) + + time.Sleep(500 * time.Millisecond) + } + }) + g.Go(func() error { + for { + repoCount, _ := store_.GetRepoCount() + userCount, _ := store_.GetUserCount() + users.Set(float64(userCount)) + repos.Set(float64(repoCount)) + time.Sleep(10 * time.Second) + } + }) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go b/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go new file mode 100644 index 000000000..a00ba1eb8 --- /dev/null +++ b/vendor/github.com/prometheus/client_golang/prometheus/promauto/auto.go @@ -0,0 +1,223 @@ +// Copyright 2018 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package promauto provides constructors for the usual Prometheus metrics that +// return them already registered with the global registry +// (prometheus.DefaultRegisterer). This allows very compact code, avoiding any +// references to the registry altogether, but all the constructors in this +// package will panic if the registration fails. +// +// The following example is a complete program to create a histogram of normally +// distributed random numbers from the math/rand package: +// +// package main +// +// import ( +// "math/rand" +// "net/http" +// +// "github.com/prometheus/client_golang/prometheus" +// "github.com/prometheus/client_golang/prometheus/promauto" +// "github.com/prometheus/client_golang/prometheus/promhttp" +// ) +// +// var histogram = promauto.NewHistogram(prometheus.HistogramOpts{ +// Name: "random_numbers", +// Help: "A histogram of normally distributed random numbers.", +// Buckets: prometheus.LinearBuckets(-3, .1, 61), +// }) +// +// func Random() { +// for { +// histogram.Observe(rand.NormFloat64()) +// } +// } +// +// func main() { +// go Random() +// http.Handle("/metrics", promhttp.Handler()) +// http.ListenAndServe(":1971", nil) +// } +// +// Prometheus's version of a minimal hello-world program: +// +// package main +// +// import ( +// "fmt" +// "net/http" +// +// "github.com/prometheus/client_golang/prometheus" +// "github.com/prometheus/client_golang/prometheus/promauto" +// "github.com/prometheus/client_golang/prometheus/promhttp" +// ) +// +// func main() { +// http.Handle("/", promhttp.InstrumentHandlerCounter( +// promauto.NewCounterVec( +// prometheus.CounterOpts{ +// Name: "hello_requests_total", +// Help: "Total number of hello-world requests by HTTP code.", +// }, +// []string{"code"}, +// ), +// http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// fmt.Fprint(w, "Hello, world!") +// }), +// )) +// http.Handle("/metrics", promhttp.Handler()) +// http.ListenAndServe(":1971", nil) +// } +// +// This appears very handy. So why are these constructors locked away in a +// separate package? There are two caveats: +// +// First, in more complex programs, global state is often quite problematic. +// That's the reason why the metrics constructors in the prometheus package do +// not interact with the global prometheus.DefaultRegisterer on their own. You +// are free to use the Register or MustRegister functions to register them with +// the global prometheus.DefaultRegisterer, but you could as well choose a local +// Registerer (usually created with prometheus.NewRegistry, but there are other +// scenarios, e.g. testing). +// +// The second issue is that registration may fail, e.g. if a metric inconsistent +// with the newly to be registered one is already registered. But how to signal +// and handle a panic in the automatic registration with the default registry? +// The only way is panicking. While panicking on invalid input provided by the +// programmer is certainly fine, things are a bit more subtle in this case: You +// might just add another package to the program, and that package (in its init +// function) happens to register a metric with the same name as your code. Now, +// all of a sudden, either your code or the code of the newly imported package +// panics, depending on initialization order, without any opportunity to handle +// the case gracefully. Even worse is a scenario where registration happens +// later during the runtime (e.g. upon loading some kind of plugin), where the +// panic could be triggered long after the code has been deployed to +// production. A possibility to panic should be explicitly called out by the +// Must… idiom, cf. prometheus.MustRegister. But adding a separate set of +// constructors in the prometheus package called MustRegisterNewCounterVec or +// similar would be quite unwieldy. Adding an extra MustRegister method to each +// metric, returning the registered metric, would result in nice code for those +// using the method, but would pollute every single metric interface for +// everybody avoiding the global registry. +// +// To address both issues, the problematic auto-registering and possibly +// panicking constructors are all in this package with a clear warning +// ahead. And whoever cares about avoiding global state and possibly panicking +// function calls can simply ignore the existence of the promauto package +// altogether. +// +// A final note: There is a similar case in the net/http package of the standard +// library. It has DefaultServeMux as a global instance of ServeMux, and the +// Handle function acts on it, panicking if a handler for the same pattern has +// already been registered. However, one might argue that the whole HTTP routing +// is usually set up closely together in the same package or file, while +// Prometheus metrics tend to be spread widely over the codebase, increasing the +// chance of surprising registration failures. Furthermore, the use of global +// state in net/http has been criticized widely, and some avoid it altogether. +package promauto + +import "github.com/prometheus/client_golang/prometheus" + +// NewCounter works like the function of the same name in the prometheus package +// but it automatically registers the Counter with the +// prometheus.DefaultRegisterer. If the registration fails, NewCounter panics. +func NewCounter(opts prometheus.CounterOpts) prometheus.Counter { + c := prometheus.NewCounter(opts) + prometheus.MustRegister(c) + return c +} + +// NewCounterVec works like the function of the same name in the prometheus +// package but it automatically registers the CounterVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewCounterVec +// panics. +func NewCounterVec(opts prometheus.CounterOpts, labelNames []string) *prometheus.CounterVec { + c := prometheus.NewCounterVec(opts, labelNames) + prometheus.MustRegister(c) + return c +} + +// NewCounterFunc works like the function of the same name in the prometheus +// package but it automatically registers the CounterFunc with the +// prometheus.DefaultRegisterer. If the registration fails, NewCounterFunc +// panics. +func NewCounterFunc(opts prometheus.CounterOpts, function func() float64) prometheus.CounterFunc { + g := prometheus.NewCounterFunc(opts, function) + prometheus.MustRegister(g) + return g +} + +// NewGauge works like the function of the same name in the prometheus package +// but it automatically registers the Gauge with the +// prometheus.DefaultRegisterer. If the registration fails, NewGauge panics. +func NewGauge(opts prometheus.GaugeOpts) prometheus.Gauge { + g := prometheus.NewGauge(opts) + prometheus.MustRegister(g) + return g +} + +// NewGaugeVec works like the function of the same name in the prometheus +// package but it automatically registers the GaugeVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewGaugeVec panics. +func NewGaugeVec(opts prometheus.GaugeOpts, labelNames []string) *prometheus.GaugeVec { + g := prometheus.NewGaugeVec(opts, labelNames) + prometheus.MustRegister(g) + return g +} + +// NewGaugeFunc works like the function of the same name in the prometheus +// package but it automatically registers the GaugeFunc with the +// prometheus.DefaultRegisterer. If the registration fails, NewGaugeFunc panics. +func NewGaugeFunc(opts prometheus.GaugeOpts, function func() float64) prometheus.GaugeFunc { + g := prometheus.NewGaugeFunc(opts, function) + prometheus.MustRegister(g) + return g +} + +// NewSummary works like the function of the same name in the prometheus package +// but it automatically registers the Summary with the +// prometheus.DefaultRegisterer. If the registration fails, NewSummary panics. +func NewSummary(opts prometheus.SummaryOpts) prometheus.Summary { + s := prometheus.NewSummary(opts) + prometheus.MustRegister(s) + return s +} + +// NewSummaryVec works like the function of the same name in the prometheus +// package but it automatically registers the SummaryVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewSummaryVec +// panics. +func NewSummaryVec(opts prometheus.SummaryOpts, labelNames []string) *prometheus.SummaryVec { + s := prometheus.NewSummaryVec(opts, labelNames) + prometheus.MustRegister(s) + return s +} + +// NewHistogram works like the function of the same name in the prometheus +// package but it automatically registers the Histogram with the +// prometheus.DefaultRegisterer. If the registration fails, NewHistogram panics. +func NewHistogram(opts prometheus.HistogramOpts) prometheus.Histogram { + h := prometheus.NewHistogram(opts) + prometheus.MustRegister(h) + return h +} + +// NewHistogramVec works like the function of the same name in the prometheus +// package but it automatically registers the HistogramVec with the +// prometheus.DefaultRegisterer. If the registration fails, NewHistogramVec +// panics. +func NewHistogramVec(opts prometheus.HistogramOpts, labelNames []string) *prometheus.HistogramVec { + h := prometheus.NewHistogramVec(opts, labelNames) + prometheus.MustRegister(h) + return h +} diff --git a/vendor/vendor.json b/vendor/vendor.json index f565fc57d..42de874dd 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -539,6 +539,12 @@ "revision": "f0a455664ecb0634bfb64d58b0c8226c2dab0804", "revisionTime": "2019-05-28T13:29:58Z" }, + { + "checksumSHA1": "BFMAsj5z3cYaNKx9fwHrazQRFvI=", + "path": "github.com/prometheus/client_golang/prometheus/promauto", + "revision": "f0a455664ecb0634bfb64d58b0c8226c2dab0804", + "revisionTime": "2019-05-28T13:29:58Z" + }, { "checksumSHA1": "tqpiUpHWFso3wcHDAPXoEhT2CoM=", "path": "github.com/prometheus/client_golang/prometheus/promhttp",