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

     1  package mongo
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"sync"
     7  	"syscall"
     8  	"time"
     9  
    10  	"go.mongodb.org/mongo-driver/event"
    11  	"go.uber.org/atomic"
    12  
    13  	"github.com/wfusion/gofusion/common/utils"
    14  	"github.com/wfusion/gofusion/config"
    15  	"github.com/wfusion/gofusion/metrics"
    16  )
    17  
    18  var (
    19  	metricsPoolIdleKey      = []string{"mongo", "idle"}
    20  	metricsPoolInUseKey     = []string{"mongo", "inuse"}
    21  	metricsPoolTotalKey     = []string{"mongo", "total"}
    22  	metricsPoolLocker       = new(sync.RWMutex)
    23  	metricsPoolInUseCounter = map[string]map[string]*atomic.Int64{}
    24  	metricsPoolTotalCounter = map[string]map[string]*atomic.Int64{}
    25  	metricsLatencyKey       = []string{"mongo", "latency"}
    26  	metricsLatencyBuckets   = []float64{
    27  		.1, .25, .5, .75, .90, .95, .99,
    28  		1, 2.5, 5, 7.5, 9, 9.5, 9.9,
    29  		10, 25, 50, 75, 90, 95, 99,
    30  		100, 250, 500, 750, 900, 950, 990,
    31  	}
    32  )
    33  
    34  func startDaemonRoutines(ctx context.Context, appName, name string, conf *Conf) {
    35  	ticker := time.Tick(time.Second * 5)
    36  	app := config.Use(appName).AppName()
    37  	labels := []metrics.Label{
    38  		{Key: "config", Value: name},
    39  		{Key: "database", Value: conf.DB},
    40  	}
    41  
    42  	log.Printf("%v [Gofusion] %s %s %s metrics start", syscall.Getpid(), app, config.ComponentMongo, name)
    43  	for {
    44  		select {
    45  		case <-ctx.Done():
    46  			log.Printf("%v [Gofusion] %s %s %s metrics exited",
    47  				syscall.Getpid(), app, config.ComponentMongo, name)
    48  			return
    49  		case <-ticker:
    50  			go metricMongoStats(ctx, appName, name, labels)
    51  			go metricMongoLatency(ctx, appName, name, labels)
    52  		}
    53  	}
    54  }
    55  
    56  func metricMongoStats(ctx context.Context, appName, name string, labels []metrics.Label) {
    57  	select {
    58  	case <-ctx.Done():
    59  		return
    60  	default:
    61  	}
    62  
    63  	_, _ = utils.Catch(func() {
    64  		var total, inuse int64
    65  		_, err := utils.Catch(func() {
    66  			metricsPoolLocker.RLock()
    67  			defer metricsPoolLocker.RUnlock()
    68  			inuse = metricsPoolInUseCounter[appName][name].Load()
    69  			total = metricsPoolTotalCounter[appName][name].Load()
    70  		})
    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  		ide := total - inuse
    80  		for _, m := range metrics.Internal(metrics.AppName(appName)) {
    81  			select {
    82  			case <-ctx.Done():
    83  				return
    84  			default:
    85  				if m.IsEnableServiceLabel() {
    86  					m.SetGauge(ctx, idleKey, float64(ide), metrics.Labels(labels))
    87  					m.SetGauge(ctx, inuseKey, float64(inuse), metrics.Labels(labels))
    88  					m.SetGauge(ctx, totalKey, float64(total), metrics.Labels(labels))
    89  				} else {
    90  					m.SetGauge(ctx, metricsPoolIdleKey, float64(ide), metrics.Labels(labels))
    91  					m.SetGauge(ctx, metricsPoolInUseKey, float64(inuse), metrics.Labels(labels))
    92  					m.SetGauge(ctx, metricsPoolTotalKey, float64(total), metrics.Labels(labels))
    93  				}
    94  			}
    95  		}
    96  	})
    97  }
    98  
    99  func metricMongoLatency(ctx context.Context, appName, name string, labels []metrics.Label) {
   100  	select {
   101  	case <-ctx.Done():
   102  		return
   103  	default:
   104  	}
   105  
   106  	_, _ = utils.Catch(func() {
   107  		rwlock.RLock()
   108  		defer rwlock.RUnlock()
   109  		instances, ok := appInstances[appName]
   110  		if !ok {
   111  			return
   112  		}
   113  		instance, ok := instances[name]
   114  		if !ok {
   115  			return
   116  		}
   117  
   118  		mgoCli := instance.GetProxy()
   119  		begin := time.Now()
   120  		if err := mgoCli.Ping(ctx, nil); err != nil {
   121  			return
   122  		}
   123  
   124  		latency := float64(time.Since(begin)) / float64(time.Millisecond)
   125  		latencyKey := append([]string{config.Use(appName).AppName()}, metricsLatencyKey...)
   126  		for _, m := range metrics.Internal(metrics.AppName(appName)) {
   127  			select {
   128  			case <-ctx.Done():
   129  				return
   130  			default:
   131  				if m.IsEnableServiceLabel() {
   132  					m.AddSample(ctx, latencyKey, latency,
   133  						metrics.Labels(labels),
   134  						metrics.PrometheusBuckets(metricsLatencyBuckets),
   135  					)
   136  				} else {
   137  					m.AddSample(ctx, metricsLatencyKey, latency,
   138  						metrics.Labels(labels),
   139  						metrics.PrometheusBuckets(metricsLatencyBuckets),
   140  					)
   141  				}
   142  			}
   143  		}
   144  	})
   145  }
   146  
   147  func metricsPoolMonitor(appName, name string) func(evt *event.PoolEvent) {
   148  	metricsPoolLocker.Lock()
   149  	defer metricsPoolLocker.Unlock()
   150  	if metricsPoolTotalCounter[appName] == nil {
   151  		metricsPoolTotalCounter[appName] = make(map[string]*atomic.Int64)
   152  	}
   153  	if metricsPoolTotalCounter[appName][name] == nil {
   154  		metricsPoolTotalCounter[appName][name] = atomic.NewInt64(0)
   155  	}
   156  	if metricsPoolInUseCounter[appName] == nil {
   157  		metricsPoolInUseCounter[appName] = make(map[string]*atomic.Int64)
   158  	}
   159  	if metricsPoolInUseCounter[appName][name] == nil {
   160  		metricsPoolInUseCounter[appName][name] = atomic.NewInt64(0)
   161  	}
   162  
   163  	inuse := metricsPoolInUseCounter[appName][name]
   164  	total := metricsPoolTotalCounter[appName][name]
   165  	return func(evt *event.PoolEvent) {
   166  		switch evt.Type {
   167  		case event.PoolCreated:
   168  		case event.PoolReady:
   169  		case event.PoolCleared:
   170  		case event.PoolClosedEvent:
   171  		case event.ConnectionCreated:
   172  			total.Add(1)
   173  		case event.ConnectionReady:
   174  		case event.ConnectionClosed:
   175  			total.Add(-1)
   176  		case event.GetStarted:
   177  		case event.GetFailed:
   178  		case event.GetSucceeded:
   179  			inuse.Add(1)
   180  		case event.ConnectionReturned:
   181  			inuse.Add(-1)
   182  		}
   183  	}
   184  
   185  }