序
本文主要研究一下gorm的prometheus
Plugin
gorm.io/gorm@v1.20.10/interfaces.go
// Plugin GORM plugin interface
type Plugin interface {
Name() string
Initialize(*DB) error
}
Plugin接口定义了Name、Initialize方法
Prometheus
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.go
type Prometheus struct {
*gorm.DB
*DBStats
*Config
refreshOnce, pushOnce sync.Once
Labels map[string]string
collectors []prometheus.Collector
}
func (p *Prometheus) Name() string {
return "gorm:prometheus"
}
func (p *Prometheus) Initialize(db *gorm.DB) error { //can be called repeatedly
p.DB = db
if p.Config.DBName != "" {
p.Labels["db_name"] = p.Config.DBName
}
p.DBStats = newStats(p.Labels)
p.refreshOnce.Do(func() {
for _, mc := range p.MetricsCollector {
p.collectors = append(p.collectors, mc.Metrics(p)...)
}
go func() {
for range time.Tick(time.Duration(p.Config.RefreshInterval) * time.Second) {
p.refresh()
}
}()
})
if p.Config.StartServer {
go p.startServer()
}
if p.PushAddr != "" {
go p.startPush()
}
return nil
}
Prometheus实现了Plugin接口定义了Name、Initialize方法;Initialize方法这里执行了p.startServer()、p.startPush()以及定时任务执行p.refresh()
startServer
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.go
func (p *Prometheus) startServer() {
httpServerOnce.Do(func() { //only start once
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
err := http.ListenAndServe(fmt.Sprintf(":%d", p.Config.HTTPServerPort), mux)
if err != nil {
p.DB.Logger.Error(context.Background(), "gorm:prometheus listen and serve err: ", err)
}
})
}
startServer启动了http server提供了
/metrics
接口
startPush
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.go
func (p *Prometheus) startPush() {
p.pushOnce.Do(func() {
pusher := push.New(p.PushAddr, p.DBName)
for _, collector := range p.DBStats.Collectors() {
pusher = pusher.Collector(collector)
}
for _, c := range p.collectors {
pusher = pusher.Collector(c)
}
for range time.Tick(time.Duration(p.Config.RefreshInterval) * time.Second) {
err := pusher.Push()
if err != nil {
p.DB.Logger.Error(context.Background(), "gorm:prometheus push err: ", err)
}
}
})
}
startPush方法启动定时任务去执行pusher.Push()
refresh
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.go
func (p *Prometheus) refresh() {
if db, err := p.DB.DB(); err == nil {
p.DBStats.Set(db.Stats())
} else {
p.DB.Logger.Error(context.Background(), "gorm:prometheus failed to collect db status, got error: %v", err)
}
}
refresh方法主要是更新p.DBStats
Use
func (db *DB) Use(plugin Plugin) (err error) {
name := plugin.Name()
if _, ok := db.Plugins[name]; !ok {
if err = plugin.Initialize(db); err == nil {
db.Plugins[name] = plugin
}
} else {
return ErrRegistered
}
return err
}
gorm的Use方法用于启动一个plugin,它会执行plugin.Initialize(db)
实例
db.Use(prometheus.New(prometheus.Config{
DBName: "db1", // 使用 `DBName` 作为指标 label
RefreshInterval: 15, // 指标刷新频率(默认为 15 秒)
PushAddr: "prometheus pusher address", // 如果配置了 `PushAddr`,则推送指标
StartServer: true, // 启用一个 http 服务来暴露指标
HTTPServerPort: 8080, // 配置 http 服务监听端口,默认端口为 8080 (如果您配置了多个,只有第一个 `HTTPServerPort` 会被使用)
MetricsCollector: []prometheus.MetricsCollector {
&prometheus.MySQL{
VariableNames: []string{"Threads_running"},
},
}, // 用户自定义指标
}))
小结
gorm的Plugin接口定义了Name、Initialize方法;gorm的Use方法用于启动一个plugin,它会执行plugin.Initialize(db);Prometheus实现了Plugin接口定义了Name、Initialize方法;Initialize方法这里执行了p.startServer()、p.startPush()以及定时任务执行p.refresh()。
网友评论