github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/metrics/metrics.go (about)

     1  package metrics
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  
    10  	"github.com/prometheus/client_golang/prometheus"
    11  
    12  	"github.com/machinefi/w3bstream/pkg/depends/kit/logr"
    13  	"github.com/machinefi/w3bstream/pkg/models"
    14  	"github.com/machinefi/w3bstream/pkg/types"
    15  )
    16  
    17  const (
    18  	_eventMtcName        = "inbound_events_metrics"
    19  	_publisherMtcName    = "publishers_metrics"
    20  	_blockChainTxMtcName = "w3b_blockchain_tx_metrics"
    21  )
    22  
    23  var (
    24  	eventMtc = prometheus.NewCounterVec(
    25  		prometheus.CounterOpts{
    26  			Name: _eventMtcName,
    27  			Help: "received events metrics.",
    28  		},
    29  		[]string{"account", "project", "publisher", "eventtype"},
    30  	)
    31  	eventClickhouseCli = NewSQLBatcher("INSERT INTO ws_metrics.inbound_events_metrics VALUES")
    32  
    33  	publisherMtc = prometheus.NewGaugeVec(
    34  		prometheus.GaugeOpts{
    35  			Name: _publisherMtcName,
    36  			Help: "registered publishers for the project.",
    37  		},
    38  		[]string{"account", "project"},
    39  	)
    40  	publisherClickhouseCli = NewSQLBatcher("INSERT INTO ws_metrics.publishers_metrics VALUES")
    41  
    42  	BlockChainTxMtc = prometheus.NewCounterVec(prometheus.CounterOpts{
    43  		Name: _blockChainTxMtcName,
    44  		Help: "blockchain transaction counter metrics.",
    45  	}, []string{"project", "chainID"})
    46  )
    47  
    48  func init() {
    49  	prometheus.MustRegister(eventMtc)
    50  	prometheus.MustRegister(publisherMtc)
    51  	prometheus.MustRegister(BlockChainTxMtc)
    52  }
    53  
    54  func RemoveMetrics(ctx context.Context, account string, project string) {
    55  	ctx, l := logr.Start(ctx, "metrics.RemoveMetrics")
    56  	defer l.End()
    57  
    58  	eventMtc.DeletePartialMatch(prometheus.Labels{"account": account, "project": project})
    59  	publisherMtc.DeletePartialMatch(prometheus.Labels{"account": account, "project": project})
    60  	BlockChainTxMtc.DeletePartialMatch(prometheus.Labels{"project": project})
    61  
    62  	// erase data in metrics server
    63  	if err := eraseDataInServer(ctx, account, project); err != nil {
    64  		// the metrics server isn't essential for the core service
    65  		l.Warn(err)
    66  	}
    67  	if clickhouseCLI != nil {
    68  		if err := clickhouseCLI.Insert(fmt.Sprintf(`DELETE FROM ws_metrics.inbound_events_metrics WHERE (
    69  			account = '%s') AND (project = '%s')`, account, project)); err != nil {
    70  			l.Warn(err)
    71  		}
    72  		if err := clickhouseCLI.Insert(fmt.Sprintf(`DELETE FROM ws_metrics.publishers_metrics WHERE (
    73  				account = '%s') AND (project = '%s')`, account, project)); err != nil {
    74  			l.Warn(err)
    75  		}
    76  		if err := clickhouseCLI.Insert(fmt.Sprintf(`DELETE FROM ws_metrics.customized_metrics WHERE (
    77  			account = '%s') AND (project = '%s')`, account, project)); err != nil {
    78  			l.Warn(err)
    79  		}
    80  	}
    81  }
    82  
    83  func EventMetricsInc(ctx context.Context, v *models.Event) {
    84  	ctx, l := logr.Start(ctx, "metrics.EventMetricsInc")
    85  	defer l.End()
    86  
    87  	eventMtc.WithLabelValues(v.AccountID.String(), v.ProjectName, v.PublisherKey, v.EventType).Inc()
    88  	if clickhouseCLI != nil {
    89  		if err := eventClickhouseCli.Insert(fmt.Sprintf(`now(), '%s', '%s', '%s', '%s', %d`,
    90  			v.AccountID, v.ProjectName, v.PublisherKey, v.EventType, 1)); err != nil {
    91  			l.Error(err)
    92  		}
    93  	}
    94  }
    95  
    96  func PublisherMetricsInc(ctx context.Context, account, project string) {
    97  	ctx, l := logr.Start(ctx, "metrics.PublisherMetricsInc")
    98  	defer l.End()
    99  
   100  	publisherMtc.WithLabelValues(account, project).Inc()
   101  	if clickhouseCLI != nil {
   102  		if err := publisherClickhouseCli.Insert(fmt.Sprintf(`now(), '%s', '%s', %d`, account, project, 1)); err != nil {
   103  			l.Error(err)
   104  		}
   105  	}
   106  }
   107  
   108  func PublisherMetricsDec(ctx context.Context, account, project string) {
   109  	ctx, l := logr.Start(ctx, "metrics.PublisherMetricsDec")
   110  	defer l.End()
   111  
   112  	publisherMtc.WithLabelValues(account, project).Dec()
   113  	if clickhouseCLI != nil {
   114  		if err := publisherClickhouseCli.Insert(fmt.Sprintf(`now(), '%s', '%s', %d`, account, project, -1)); err != nil {
   115  			l.Error(err)
   116  		}
   117  	}
   118  }
   119  
   120  func eraseDataInServer(ctx context.Context, account string, project string) error {
   121  	cfg, existed := types.MetricsCenterConfigFromContext(ctx)
   122  	if !existed {
   123  		return errors.New("fail to get the url of metrics center")
   124  	}
   125  	baseURL := cfg.Endpoint
   126  
   127  	if err := httpReq(
   128  		fmt.Sprintf("%s/api/v1/admin/tsdb/delete_series?match[]=%s",
   129  			baseURL,
   130  			url.QueryEscape(fmt.Sprintf(`%s{account="%s", project="%s"}`, _eventMtcName, account, project))),
   131  	); err != nil {
   132  		return err
   133  	}
   134  
   135  	if err := httpReq(
   136  		fmt.Sprintf("%s/api/v1/admin/tsdb/delete_series?match[]=%s",
   137  			baseURL,
   138  			url.QueryEscape(fmt.Sprintf(`%s{account="%s", project="%s"}`, _publisherMtcName, account, project))),
   139  	); err != nil {
   140  		return err
   141  	}
   142  
   143  	if err := httpReq(
   144  		fmt.Sprintf("%s/api/v1/admin/tsdb/delete_series?match[]=%s",
   145  			baseURL,
   146  			url.QueryEscape(fmt.Sprintf(`%s{project="%s"}`, _blockChainTxMtcName, project))),
   147  	); err != nil {
   148  		return err
   149  	}
   150  	return cleanTombstones(baseURL)
   151  }
   152  
   153  func cleanTombstones(baseURL string) error {
   154  	return httpReq(fmt.Sprintf("%s/api/v1/admin/tsdb/clean_tombstones", baseURL))
   155  }
   156  
   157  func httpReq(url string) error {
   158  	// Create the HTTP client and request
   159  	client := http.Client{}
   160  	req, err := http.NewRequest("POST", url, nil)
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	// Send the request
   166  	resp, err := client.Do(req)
   167  	if err != nil {
   168  		return err
   169  	}
   170  	defer resp.Body.Close()
   171  
   172  	if resp.StatusCode != 204 {
   173  		return errors.New("the http request to metrics center fails")
   174  	}
   175  
   176  	return nil
   177  }