• Home
  • Articles
    • 日志
    • 妍小言
    • 舒小书
    • 浩然说
    • 生活日记
  • All Tags

gorm sql监控上报

20 Aug 2021

Reading time ~1 minute

基于gorm默认的上报

import (
  "gorm.io/gorm"
  "gorm.io/driver/sqlite"
  "gorm.io/plugin/prometheus"
)

db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{})

db.Use(prometheus.New(prometheus.Config{
  DBName:          "db1", // use `DBName` as metrics label
  RefreshInterval: 15,    // Refresh metrics interval (default 15 seconds)
  PushAddr:        "prometheus pusher address", // push metrics if `PushAddr` configured
  StartServer:     true,  // start http server to expose metrics
  HTTPServerPort:  8080,  // configure http server port, default port 8080 (if you have configured multiple instances, only the first `HTTPServerPort` will be used to start server)
  MetricsCollector: []prometheus.MetricsCollector {
    &prometheus.MySQL{
      VariableNames: []string{"Threads_running"},
    },
  },  // user defined metrics
}))

以上为gorm默认提供的prometheus监控方式,但需要注意的是,这种方式会全新启动一个端点(http://xxxx:8080/metrics)。如果用户希望将上报的metrics上报到其他端点,可以使用下面方式。

基于gorm日志的上报

gorm的日志中已经带有了sql source,执行耗时,参数,发生时间等数据,如果能够对gorm的日志进行扩展,在记录日志的同时,将数据采集即可不用开启新的端点就能完成采集,简易代码如下:

type StatsLog struct {
	tally.Scope
	gormLogger *gormzap.Logger
}

func (log *StatsLog) Print(v ...interface{}) {
	log.stats(v)
	log.gormLogger.Print(v...)
}

func (log *StatsLog) stats(values []interface{}) {
	if len(values) > 1 {
		var level = values[0]
		source := getSource(values)

		if level == "sql" && log.Scope != nil {
			duration := getDuration(values)
			sql := values[3].(string)
			tags := map[string]string{
				"sql":       sql,
				"source":    source,
			}
			log.Scope.Tagged(tags).Histogram("metrics", HistogramBuckets).RecordDuration(duration)
		} 
	}
}

最后,向gorm注册log实现时,使用我们自定义的logger即可



gormprometheus