Skip to content

Commit d9b691b

Browse files
Add metric exporter abstraction and add Prometheus support (#382)
* Add metric exporter abstraction * Support Prometheus metrics
1 parent 194d4be commit d9b691b

File tree

11 files changed

+404
-126
lines changed

11 files changed

+404
-126
lines changed

api/init.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ package api
1616

1717
import (
1818
"fmt"
19+
"net"
20+
"net/http"
1921

2022
"github.com/alibaba/sentinel-golang/core/config"
2123
"github.com/alibaba/sentinel-golang/core/log/metric"
2224
"github.com/alibaba/sentinel-golang/core/system_metric"
25+
metric_exporter "github.com/alibaba/sentinel-golang/exporter/metric"
2326
"github.com/alibaba/sentinel-golang/util"
2427
"github.com/pkg/errors"
2528
)
@@ -113,6 +116,23 @@ func initCoreComponents() error {
113116
util.StartTimeTicker()
114117
}
115118

119+
if config.MetricExportHTTPAddr() != "" {
120+
httpAddr := config.MetricExportHTTPAddr()
121+
httpPath := config.MetricExportHTTPPath()
122+
123+
l, err := net.Listen("tcp", httpAddr)
124+
if err != nil {
125+
return fmt.Errorf("init metric exporter http server err: %s", err.Error())
126+
}
127+
128+
http.Handle(httpPath, metric_exporter.HTTPHandler())
129+
go func() {
130+
_ = http.Serve(l, nil)
131+
}()
132+
133+
return nil
134+
}
135+
116136
return nil
117137
}
118138

core/circuitbreaker/circuit_breaker.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/alibaba/sentinel-golang/core/base"
2222
sbase "github.com/alibaba/sentinel-golang/core/stat/base"
23+
metric_exporter "github.com/alibaba/sentinel-golang/exporter/metric"
2324
"github.com/alibaba/sentinel-golang/logging"
2425
"github.com/alibaba/sentinel-golang/util"
2526
"github.com/pkg/errors"
@@ -47,6 +48,17 @@ const (
4748
Open
4849
)
4950

51+
var (
52+
stateChangedCounter = metric_exporter.NewCounter(
53+
"circuit_breaker_state_changed_total",
54+
"Circuit breaker total state change count",
55+
[]string{"resource", "from_state", "to_state"})
56+
)
57+
58+
func init() {
59+
metric_exporter.Register(stateChangedCounter)
60+
}
61+
5062
func newState() *State {
5163
var state State
5264
state = Closed
@@ -152,6 +164,8 @@ func (b *circuitBreakerBase) fromClosedToOpen(snapshot interface{}) bool {
152164
for _, listener := range stateChangeListeners {
153165
listener.OnTransformToOpen(Closed, *b.rule, snapshot)
154166
}
167+
168+
stateChangedCounter.Add(float64(1), b.BoundRule().Resource, "Closed", "Open")
155169
return true
156170
}
157171
return false
@@ -181,6 +195,8 @@ func (b *circuitBreakerBase) fromOpenToHalfOpen(ctx *base.EntryContext) bool {
181195
return nil
182196
})
183197
}
198+
199+
stateChangedCounter.Add(float64(1), b.BoundRule().Resource, "Open", "HalfOpen")
184200
return true
185201
}
186202
return false
@@ -194,6 +210,8 @@ func (b *circuitBreakerBase) fromHalfOpenToOpen(snapshot interface{}) bool {
194210
for _, listener := range stateChangeListeners {
195211
listener.OnTransformToOpen(HalfOpen, *b.rule, snapshot)
196212
}
213+
214+
stateChangedCounter.Add(float64(1), b.BoundRule().Resource, "HalfOpen", "Open")
197215
return true
198216
}
199217
return false
@@ -206,6 +224,8 @@ func (b *circuitBreakerBase) fromHalfOpenToClosed() bool {
206224
for _, listener := range stateChangeListeners {
207225
listener.OnTransformToClosed(HalfOpen, *b.rule)
208226
}
227+
228+
stateChangedCounter.Add(float64(1), b.BoundRule().Resource, "HalfOpen", "Closed")
209229
return true
210230
}
211231
return false

core/config/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ func LogUsePid() bool {
204204
return globalCfg.LogUsePid()
205205
}
206206

207+
func MetricExportHTTPAddr() string {
208+
return globalCfg.MetricExportHTTPAddr()
209+
}
210+
211+
func MetricExportHTTPPath() string {
212+
return globalCfg.MetricExportHTTPPath()
213+
}
214+
207215
func MetricLogFlushIntervalSec() uint32 {
208216
return globalCfg.MetricLogFlushIntervalSec()
209217
}

core/config/entity.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type SentinelConfig struct {
3838
// Type indicates the classification of the service (e.g. web service, API gateway).
3939
Type int32
4040
}
41+
// Exporter represents configuration items related to exporter, like metric exporter.
42+
Exporter ExporterConfig
4143
// Log represents configuration items related to logging.
4244
Log LogConfig
4345
// Stat represents configuration items related to statistics.
@@ -46,6 +48,19 @@ type SentinelConfig struct {
4648
UseCacheTime bool `yaml:"useCacheTime"`
4749
}
4850

51+
// ExporterConfig represents configuration items related to exporter, like metric exporter.
52+
type ExporterConfig struct {
53+
Metric MetricExporterConfig
54+
}
55+
56+
// MetricExporterConfig represents configuration of metric exporter.
57+
type MetricExporterConfig struct {
58+
// HttpAddr is the http server listen address, like ":8080".
59+
HttpAddr string `yaml:"http_addr"`
60+
// HttpPath is the http request path of access metrics, like "/metrics".
61+
HttpPath string `yaml:"http_path"`
62+
}
63+
4964
// LogConfig represent the configuration of logging in Sentinel.
5065
type LogConfig struct {
5166
// Logger indicates that using logger to replace default logging.
@@ -190,6 +205,14 @@ func (entity *Entity) LogUsePid() bool {
190205
return entity.Sentinel.Log.UsePid
191206
}
192207

208+
func (entity *Entity) MetricExportHTTPAddr() string {
209+
return entity.Sentinel.Exporter.Metric.HttpAddr
210+
}
211+
212+
func (entity *Entity) MetricExportHTTPPath() string {
213+
return entity.Sentinel.Exporter.Metric.HttpPath
214+
}
215+
193216
func (entity *Entity) MetricLogFlushIntervalSec() uint32 {
194217
return entity.Sentinel.Log.Metric.FlushIntervalSec
195218
}

core/flow/traffic_shaping.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,20 @@ package flow
1616

1717
import (
1818
"github.com/alibaba/sentinel-golang/core/base"
19-
"github.com/alibaba/sentinel-golang/metrics"
19+
metric_exporter "github.com/alibaba/sentinel-golang/exporter/metric"
2020
)
2121

22+
var (
23+
resourceFlowThresholdGauge = metric_exporter.NewGauge(
24+
"resource_flow_threshold",
25+
"Resource flow threshold",
26+
[]string{"resource"})
27+
)
28+
29+
func init() {
30+
metric_exporter.Register(resourceFlowThresholdGauge)
31+
}
32+
2233
// TrafficShapingCalculator calculates the actual traffic shaping threshold
2334
// based on the threshold of rule and the traffic shaping strategy.
2435
type TrafficShapingCalculator interface {
@@ -74,6 +85,8 @@ func (t *TrafficShapingController) FlowCalculator() TrafficShapingCalculator {
7485

7586
func (t *TrafficShapingController) PerformChecking(resStat base.StatNode, batchCount uint32, flag int32) *base.TokenResult {
7687
allowedTokens := t.flowCalculator.CalculateAllowedTokens(batchCount, flag)
77-
metrics.SetResourceFlowThreshold(t.rule.Resource, allowedTokens)
88+
89+
resourceFlowThresholdGauge.Set(float64(allowedTokens), t.rule.Resource)
90+
7891
return t.flowChecker.DoCheck(resStat, batchCount, allowedTokens)
7992
}

core/stat/stat_slot.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,29 @@ package stat
1616

1717
import (
1818
"github.com/alibaba/sentinel-golang/core/base"
19+
metric_exporter "github.com/alibaba/sentinel-golang/exporter/metric"
1920
"github.com/alibaba/sentinel-golang/util"
2021
)
2122

2223
const (
2324
StatSlotOrder = 1000
25+
ResultPass = "pass"
26+
ResultBlock = "block"
2427
)
2528

2629
var (
2730
DefaultSlot = &Slot{}
31+
32+
handledCounter = metric_exporter.NewCounter(
33+
"handled_total",
34+
"Total handled count",
35+
[]string{"resource", "result", "block_type"})
2836
)
2937

38+
func init() {
39+
metric_exporter.Register(handledCounter)
40+
}
41+
3042
type Slot struct {
3143
}
3244

@@ -39,13 +51,17 @@ func (s *Slot) OnEntryPassed(ctx *base.EntryContext) {
3951
if ctx.Resource.FlowType() == base.Inbound {
4052
s.recordPassFor(InboundNode(), ctx.Input.BatchCount)
4153
}
54+
55+
handledCounter.Add(float64(ctx.Input.BatchCount), ctx.Resource.Name(), ResultPass, "")
4256
}
4357

4458
func (s *Slot) OnEntryBlocked(ctx *base.EntryContext, blockError *base.BlockError) {
4559
s.recordBlockFor(ctx.StatNode, ctx.Input.BatchCount)
4660
if ctx.Resource.FlowType() == base.Inbound {
4761
s.recordBlockFor(InboundNode(), ctx.Input.BatchCount)
4862
}
63+
64+
handledCounter.Add(float64(ctx.Input.BatchCount), ctx.Resource.Name(), ResultBlock, blockError.BlockType().String())
4965
}
5066

5167
func (s *Slot) OnCompleted(ctx *base.EntryContext) {

core/system_metric/sys_metric_stat.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import (
2020
"sync/atomic"
2121
"time"
2222

23+
metric_exporter "github.com/alibaba/sentinel-golang/exporter/metric"
2324
"github.com/alibaba/sentinel-golang/logging"
24-
"github.com/alibaba/sentinel-golang/metrics"
2525
"github.com/alibaba/sentinel-golang/util"
2626
"github.com/shirou/gopsutil/v3/load"
2727
"github.com/shirou/gopsutil/v3/mem"
@@ -49,6 +49,15 @@ var (
4949
TotalMemorySize = getTotalMemorySize()
5050

5151
ssStopChan = make(chan struct{})
52+
53+
cpuRatioGauge = metric_exporter.NewGauge(
54+
"cpu_ratio",
55+
"Process cpu ratio",
56+
[]string{})
57+
processMemoryGauge = metric_exporter.NewGauge(
58+
"process_memory_bytes",
59+
"Process memory in bytes",
60+
[]string{})
5261
)
5362

5463
func init() {
@@ -64,6 +73,9 @@ func init() {
6473
currentProcessOnce.Do(func() {
6574
currentProcess.Store(p)
6675
})
76+
77+
metric_exporter.Register(cpuRatioGauge)
78+
metric_exporter.Register(processMemoryGauge)
6779
}
6880

6981
// getMemoryStat returns the current machine's memory statistic
@@ -105,7 +117,9 @@ func retrieveAndUpdateMemoryStat() {
105117
logging.Error(err, "Fail to retrieve and update cpu statistic")
106118
return
107119
}
108-
metrics.SetProcessMemorySize(memoryUsedBytes)
120+
121+
processMemoryGauge.Set(float64(memoryUsedBytes))
122+
109123
currentMemoryUsage.Store(memoryUsedBytes)
110124
}
111125

@@ -161,7 +175,9 @@ func retrieveAndUpdateCpuStat() {
161175
logging.Error(err, "Fail to retrieve and update cpu statistic")
162176
return
163177
}
164-
metrics.SetCPURatio(cpuPercent)
178+
179+
cpuRatioGauge.Set(cpuPercent)
180+
165181
currentCpuUsage.Store(cpuPercent)
166182
}
167183

0 commit comments

Comments
 (0)