github.com/wfusion/gofusion@v1.1.14/db/metrics.go (about)

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"syscall"
     7  	"time"
     8  
     9  	"github.com/wfusion/gofusion/common/utils"
    10  	"github.com/wfusion/gofusion/config"
    11  	"github.com/wfusion/gofusion/metrics"
    12  )
    13  
    14  var (
    15  	metricsPoolIdleKey         = []string{"db", "idle"}
    16  	metricsPoolTotalKey        = []string{"db", "total"}
    17  	metricsPoolInUseKey        = []string{"db", "inuse"}
    18  	metricsPoolWaitCountKey    = []string{"db", "wait", "count"}
    19  	metricsPoolWaitDurationKey = []string{"db", "wait", "duration"}
    20  	metricsLatencyKey          = []string{"db", "latency"}
    21  	metricsLatencyBuckets      = []float64{
    22  		.1, .25, .5, .75, .90, .95, .99,
    23  		1, 2.5, 5, 7.5, 9, 9.5, 9.9,
    24  		10, 25, 50, 75, 90, 95, 99,
    25  	}
    26  )
    27  
    28  func startDaemonRoutines(ctx context.Context, appName, name string, conf *Conf) {
    29  	ticker := time.Tick(time.Second * 5)
    30  	app := config.Use(appName).AppName()
    31  	labels := []metrics.Label{
    32  		{Key: "config", Value: name},
    33  		{Key: "database", Value: conf.DB},
    34  	}
    35  
    36  	log.Printf("%v [Gofusion] %s %s %s metrics start", syscall.Getpid(), app, config.ComponentDB, name)
    37  	for {
    38  		select {
    39  		case <-ctx.Done():
    40  			log.Printf("%v [Gofusion] %s %s %s metrics exited",
    41  				syscall.Getpid(), app, config.ComponentDB, name)
    42  			return
    43  		case <-ticker:
    44  			go metricDBStats(ctx, appName, name, labels)
    45  			go metricDBLatency(ctx, appName, name, labels)
    46  		}
    47  	}
    48  }
    49  
    50  func metricDBStats(ctx context.Context, appName, name string, labels []metrics.Label) {
    51  	select {
    52  	case <-ctx.Done():
    53  		return
    54  	default:
    55  	}
    56  
    57  	_, _ = utils.Catch(func() {
    58  		rwlock.RLock()
    59  		defer rwlock.RUnlock()
    60  
    61  		instances, ok := appInstances[appName]
    62  		if !ok {
    63  			return
    64  		}
    65  		instance, ok := instances[name]
    66  		if !ok {
    67  			return
    68  		}
    69  		db := instance.GetProxy()
    70  		sqlDB, err := db.DB()
    71  		if err != nil {
    72  			return
    73  		}
    74  
    75  		app := config.Use(appName).AppName()
    76  		idleKey := append([]string{app}, metricsPoolIdleKey...)
    77  		inuseKey := append([]string{app}, metricsPoolInUseKey...)
    78  		totalKey := append([]string{app}, metricsPoolTotalKey...)
    79  		waitCountKey := append([]string{app}, metricsPoolWaitCountKey...)
    80  		waitDurationKey := append([]string{app}, metricsPoolWaitDurationKey...)
    81  
    82  		stats := sqlDB.Stats()
    83  		waitDuration := float64(stats.WaitDuration) / float64(time.Millisecond)
    84  		for _, m := range metrics.Internal(metrics.AppName(appName)) {
    85  			select {
    86  			case <-ctx.Done():
    87  				return
    88  			default:
    89  				if m.IsEnableServiceLabel() {
    90  					m.SetGauge(ctx, idleKey, float64(stats.Idle), metrics.Labels(labels))
    91  					m.SetGauge(ctx, inuseKey, float64(stats.InUse), metrics.Labels(labels))
    92  					m.SetGauge(ctx, totalKey, float64(stats.OpenConnections), metrics.Labels(labels))
    93  					m.SetGauge(ctx, waitCountKey, float64(stats.WaitCount), metrics.Labels(labels))
    94  					m.SetGauge(ctx, waitDurationKey, waitDuration, metrics.Labels(labels))
    95  				} else {
    96  					m.SetGauge(ctx, metricsPoolIdleKey, float64(stats.Idle), metrics.Labels(labels))
    97  					m.SetGauge(ctx, metricsPoolInUseKey, float64(stats.InUse), metrics.Labels(labels))
    98  					m.SetGauge(ctx, metricsPoolTotalKey, float64(stats.OpenConnections), metrics.Labels(labels))
    99  					m.SetGauge(ctx, metricsPoolWaitCountKey, float64(stats.WaitCount), metrics.Labels(labels))
   100  					m.SetGauge(ctx, metricsPoolWaitDurationKey, waitDuration, metrics.Labels(labels))
   101  				}
   102  			}
   103  		}
   104  	})
   105  }
   106  
   107  func metricDBLatency(ctx context.Context, appName, name string, labels []metrics.Label) {
   108  	select {
   109  	case <-ctx.Done():
   110  		return
   111  	default:
   112  	}
   113  
   114  	_, _ = utils.Catch(func() {
   115  		rwlock.RLock()
   116  		defer rwlock.RUnlock()
   117  		instances, ok := appInstances[appName]
   118  		if !ok {
   119  			return
   120  		}
   121  		instance, ok := instances[name]
   122  		if !ok {
   123  			return
   124  		}
   125  		db := instance.GetProxy()
   126  		sqlDB, err := db.DB()
   127  		if err != nil {
   128  			return
   129  		}
   130  
   131  		begin := time.Now()
   132  		if err := sqlDB.Ping(); err != nil {
   133  			return
   134  		}
   135  		latency := float64(time.Since(begin)) / float64(time.Millisecond)
   136  		latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
   137  		for _, m := range metrics.Internal(metrics.AppName(appName)) {
   138  			select {
   139  			case <-ctx.Done():
   140  				return
   141  			default:
   142  				if m.IsEnableServiceLabel() {
   143  					m.AddSample(ctx, latencyKey, latency,
   144  						metrics.Labels(labels),
   145  						metrics.PrometheusBuckets(metricsLatencyBuckets),
   146  					)
   147  				} else {
   148  					m.AddSample(ctx, metricsLatencyKey, latency,
   149  						metrics.Labels(labels),
   150  						metrics.PrometheusBuckets(metricsLatencyBuckets),
   151  					)
   152  				}
   153  			}
   154  		}
   155  	})
   156  }