本文主要研究一下gorm的prometheusgit
gorm.io/gorm@v1.20.10/interfaces.gogithub
// Plugin GORM plugin interface type Plugin interface { Name() string Initialize(*DB) error }
Plugin接口定義了Name、Initialize方法
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.goapp
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()
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.gocode
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
接口
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.goorm
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()
gorm.io/plugin/prometheus@v0.0.0-20201023060415-b0e68fc269af/prometheus.goserver
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
gorm.io/gorm@v1.20.10/gorm.go接口
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()。get