metrics/prometheus: minor cleanups

This commit is contained in:
Péter Szilágyi 2019-04-05 10:27:21 +03:00
parent ae5c0fc0e4
commit 8e8d55ed8e
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
2 changed files with 35 additions and 31 deletions

View file

@ -13,6 +13,7 @@
// //
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package prometheus package prometheus
import ( import (
@ -43,21 +44,26 @@ var (
nameQuantileTagTemplate = "{name=\"%s\",quantile=\"%s\"} %v\n" nameQuantileTagTemplate = "{name=\"%s\",quantile=\"%s\"} %v\n"
) )
// bufPool is a global pool of byte buffers to avoid constant reallocations.
var bufPool sync.Pool var bufPool sync.Pool
// getBuf retrieves a new empty (but possibly non-0 capacity) buffer.
func getBuf() *bytes.Buffer { func getBuf() *bytes.Buffer {
buf := bufPool.Get() if item := bufPool.Get(); item != nil {
if buf == nil { buf := item.(*bytes.Buffer)
return &bytes.Buffer{} buf.Reset()
return buf
} }
return buf.(*bytes.Buffer) return &bytes.Buffer{}
} }
// giveBuf returns a used byte buffer to the pool.
func giveBuf(buf *bytes.Buffer) { func giveBuf(buf *bytes.Buffer) {
buf.Reset()
bufPool.Put(buf) bufPool.Put(buf)
} }
// collector is a collection of byte buffers that aggregate Prometheus reports
// for different metric types.
type collector struct { type collector struct {
counters *bytes.Buffer counters *bytes.Buffer
gauges *bytes.Buffer gauges *bytes.Buffer
@ -67,6 +73,7 @@ type collector struct {
resettingTimers *bytes.Buffer resettingTimers *bytes.Buffer
} }
// newCollector createa a new Prometheus metric aggregator.
func newCollector() *collector { func newCollector() *collector {
return &collector{ return &collector{
counters: getBuf(), counters: getBuf(),
@ -78,7 +85,9 @@ func newCollector() *collector {
} }
} }
func (c *collector) reset() { // close releases all internally held byte buffers to be reused by subsequent
// metrics collection runs.
func (c *collector) close() {
giveBuf(c.counters) giveBuf(c.counters)
giveBuf(c.gauges) giveBuf(c.gauges)
giveBuf(c.histograms) giveBuf(c.histograms)
@ -87,38 +96,34 @@ func (c *collector) reset() {
giveBuf(c.resettingTimers) giveBuf(c.resettingTimers)
} }
func (c *collector) result() *bytes.Buffer { // aggregate iterates over the different metric types and aggregates them into
// a single byte buffer.
func (c *collector) aggregate() *bytes.Buffer {
buf := getBuf() buf := getBuf()
if c.counters.Len() > 0 { if c.counters.Len() > 0 {
buf.Write(countersHeader) buf.Write(countersHeader)
buf.Write(c.counters.Bytes()) buf.Write(c.counters.Bytes())
} }
if c.gauges.Len() > 0 { if c.gauges.Len() > 0 {
buf.Write(gaugesHeader) buf.Write(gaugesHeader)
buf.Write(c.gauges.Bytes()) buf.Write(c.gauges.Bytes())
} }
if c.meters.Len() > 0 { if c.meters.Len() > 0 {
buf.Write(meterHeader) buf.Write(meterHeader)
buf.Write(c.meters.Bytes()) buf.Write(c.meters.Bytes())
} }
if c.histograms.Len() > 0 { if c.histograms.Len() > 0 {
buf.Write(histogramHeader) buf.Write(histogramHeader)
buf.Write(c.histograms.Bytes()) buf.Write(c.histograms.Bytes())
} }
if c.timers.Len() > 0 { if c.timers.Len() > 0 {
buf.Write(timerHeader) buf.Write(timerHeader)
buf.Write(c.timers.Bytes()) buf.Write(c.timers.Bytes())
} }
if c.resettingTimers.Len() > 0 { if c.resettingTimers.Len() > 0 {
buf.Write(resettingTimerHeader) buf.Write(resettingTimerHeader)
buf.Write(c.resettingTimers.Bytes()) buf.Write(c.resettingTimers.Bytes())
} }
return buf return buf
} }

View file

@ -13,48 +13,47 @@
// //
// You should have received a copy of the GNU Lesser General Public License // You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// Package prometheus exposes go-metrics into a Prometheus format.
package prometheus package prometheus
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
) )
// Handler returns http handler which dump metrics in prometheus format // Handler returns an HTTP handler which dump metrics in Prometheus format.
func Handler(reg metrics.Registry) http.Handler { func Handler(reg metrics.Registry) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Aggregate all the metris into a Prometheus collector
c := newCollector() c := newCollector()
defer c.reset() defer c.close()
reg.Each(func(name string, i interface{}) { reg.Each(func(name string, i interface{}) {
switch m := i.(type) { switch m := i.(type) {
case metrics.Counter: case metrics.Counter:
ms := m.Snapshot() c.addCounter(name, m.Snapshot())
c.addCounter(name, ms)
case metrics.Gauge: case metrics.Gauge:
ms := m.Snapshot() c.addGuage(name, m.Snapshot())
c.addGuage(name, ms)
case metrics.GaugeFloat64: case metrics.GaugeFloat64:
ms := m.Snapshot() c.addGuageFloat64(name, m.Snapshot())
c.addGuageFloat64(name, ms)
case metrics.Histogram: case metrics.Histogram:
ms := m.Snapshot() c.addHistogram(name, m.Snapshot())
c.addHistogram(name, ms)
case metrics.Meter: case metrics.Meter:
ms := m.Snapshot() c.addMeter(name, m.Snapshot())
c.addMeter(name, ms)
case metrics.Timer: case metrics.Timer:
ms := m.Snapshot() c.addTimer(name, m.Snapshot())
c.addTimer(name, ms)
case metrics.ResettingTimer: case metrics.ResettingTimer:
ms := m.Snapshot() c.addResettingTimer(name, m.Snapshot())
c.addResettingTimer(name, ms) default:
log.Warn("Unknown Prometheus metric type", "type", fmt.Sprintf("%T", i))
} }
}) })
// Aggregate the results into a single buffer and send to the user
res := c.result() res := c.aggregate()
defer giveBuf(res) defer giveBuf(res)
w.Header().Add("Content-Type", "text/plain") w.Header().Add("Content-Type", "text/plain")