Skip to content

Commit

Permalink
[FAB-6558]Make metrics option configurable
Browse files Browse the repository at this point in the history
This patchset make metrics option configurable
based core.yaml. Meanwhile refactor metrics
server create and start separate. Add a no-op
metrics implementation when metrics disabled
in config.

Change-Id: Ic4a1cc769cf3dd93a545a3cd1d938585708abf4a
Signed-off-by: grapebaba <281165273@qq.com>
  • Loading branch information
GrapeBaBa committed Oct 25, 2017
1 parent 5b38cbc commit d3fe83b
Show file tree
Hide file tree
Showing 8 changed files with 636 additions and 176 deletions.
209 changes: 209 additions & 0 deletions common/metrics/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package metrics

import (
"fmt"
"sync"
"sync/atomic"
"time"

"github.com/spf13/viper"
"github.com/uber-go/tally"
)

const (
namespace string = "hyperledger_fabric"

statsdReporterType = "statsd"
promReporterType = "prom"

defaultReporterType = statsdReporterType
defaultInterval = 1 * time.Second

defaultStatsdReporterFlushInterval = 2 * time.Second
defaultStatsdReporterFlushBytes = 1432
)

var RootScope Scope
var once sync.Once
var started uint32

// NewOpts create metrics options based config file
func NewOpts() Opts {
opts := Opts{}
opts.Enabled = viper.GetBool("metrics.enabled")
if report := viper.GetString("metrics.reporter"); report != "" {
opts.Reporter = report
} else {
opts.Reporter = defaultReporterType
}
if interval := viper.GetDuration("metrics.interval"); interval > 0 {
opts.Interval = interval
} else {
opts.Interval = defaultInterval
}

if opts.Reporter == statsdReporterType {
statsdOpts := StatsdReporterOpts{}
statsdOpts.Address = viper.GetString("metrics.statsdReporter.address")
if flushInterval := viper.GetDuration("metrics.statsdReporter.flushInterval"); flushInterval > 0 {
statsdOpts.FlushInterval = flushInterval
} else {
statsdOpts.FlushInterval = defaultStatsdReporterFlushInterval
}
if flushBytes := viper.GetInt("metrics.statsdReporter.flushBytes"); flushBytes > 0 {
statsdOpts.FlushBytes = flushBytes
} else {
statsdOpts.FlushBytes = defaultStatsdReporterFlushBytes
}
opts.StatsdReporterOpts = statsdOpts
}

if opts.Reporter == promReporterType {
promOpts := PromReporterOpts{}
promOpts.ListenAddress = viper.GetString("metrics.promReporter.listenAddress")
opts.PromReporterOpts = promOpts
}

return opts
}

//Init initializes global root metrics scope instance, all callers can only use it to extend sub scope
func Init(opts Opts) (err error) {
once.Do(func() {
RootScope, err = create(opts)
})

return
}

//Start starts metrics server
func Start() error {
if atomic.CompareAndSwapUint32(&started, 0, 1) {
return RootScope.Start()
}
return nil
}

//Shutdown closes underlying resources used by metrics server
func Shutdown() error {
if atomic.CompareAndSwapUint32(&started, 1, 0) {
err := RootScope.Close()
RootScope = nil
return err
}

return nil
}

type StatsdReporterOpts struct {
Address string
FlushInterval time.Duration
FlushBytes int
}

type PromReporterOpts struct {
ListenAddress string
}

type Opts struct {
Reporter string
Interval time.Duration
Enabled bool
StatsdReporterOpts StatsdReporterOpts
PromReporterOpts PromReporterOpts
}

type noOpCounter struct {
}

func (c *noOpCounter) Inc(v int64) {

}

type noOpGauge struct {
}

func (g *noOpGauge) Update(v float64) {

}

type noOpScope struct {
counter *noOpCounter
gauge *noOpGauge
}

func (s *noOpScope) Counter(name string) Counter {
return s.counter
}

func (s *noOpScope) Gauge(name string) Gauge {
return s.gauge
}

func (s *noOpScope) Tagged(tags map[string]string) Scope {
return s
}

func (s *noOpScope) SubScope(prefix string) Scope {
return s
}

func (s *noOpScope) Close() error {
return nil
}

func (s *noOpScope) Start() error {
return nil
}

func newNoOpScope() Scope {
return &noOpScope{
counter: &noOpCounter{},
gauge: &noOpGauge{},
}
}

func create(opts Opts) (rootScope Scope, e error) {
if !opts.Enabled {
rootScope = newNoOpScope()
return
} else {
if opts.Interval <= 0 {
e = fmt.Errorf("invalid Interval option %d", opts.Interval)
return
}

if opts.Reporter != statsdReporterType && opts.Reporter != promReporterType {
e = fmt.Errorf("not supported Reporter type %s", opts.Reporter)
return
}

var reporter tally.StatsReporter
var cachedReporter tally.CachedStatsReporter
if opts.Reporter == statsdReporterType {
reporter, e = newStatsdReporter(opts.StatsdReporterOpts)
}

if opts.Reporter == promReporterType {
cachedReporter, e = newPromReporter(opts.PromReporterOpts)
}

if e != nil {
return
}

rootScope = newRootScope(
tally.ScopeOptions{
Prefix: namespace,
Reporter: reporter,
CachedReporter: cachedReporter,
}, opts.Interval)
return
}
}
Loading

0 comments on commit d3fe83b

Please sign in to comment.