Skip to content

Commit

Permalink
Adding gauges, histogram and counter vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
otherview committed Mar 18, 2024
1 parent e6cd9b9 commit c0ef281
Show file tree
Hide file tree
Showing 14 changed files with 256 additions and 36 deletions.
13 changes: 7 additions & 6 deletions api/accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,20 +351,21 @@ func (a *Accounts) Mount(root *mux.Router, pathPrefix string) {

sub.Path("/*").
Methods("POST").
HandlerFunc(utils.MetricsWrapHandler("accounts_call_batch_code", utils.WrapHandlerFunc(a.handleCallBatchCode)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "accounts_call_batch_code", a.handleCallBatchCode))
sub.Path("/{address}").
Methods(http.MethodGet).
HandlerFunc(utils.MetricsWrapHandler("accounts_get_account", utils.WrapHandlerFunc(a.handleGetAccount)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "accounts_get_account", a.handleGetAccount))
sub.Path("/{address}/code").
Methods(http.MethodGet).
HandlerFunc(utils.MetricsWrapHandler("accounts_get_code", utils.WrapHandlerFunc(a.handleGetCode)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "accounts_get_code", a.handleGetCode))
sub.Path("/{address}/storage/{key}").
Methods("GET").
HandlerFunc(utils.MetricsWrapHandler("accounts_get_storage", utils.WrapHandlerFunc(a.handleGetStorage)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "accounts_get_storage", a.handleGetStorage))
// These two methods are currently deprecated
sub.Path("").
Methods("POST").
HandlerFunc(utils.MetricsWrapHandler("accounts_api_call_contract", utils.WrapHandlerFunc(a.handleCallContract)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "accounts_api_call_contract", a.handleCallContract))
sub.Path("/{address}").
Methods("POST").
HandlerFunc(utils.MetricsWrapHandler("accounts_call_contract_address", utils.WrapHandlerFunc(a.handleCallContract)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "accounts_call_contract_address", a.handleCallContract))
}
2 changes: 1 addition & 1 deletion api/blocks/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,5 @@ func (b *Blocks) Mount(root *mux.Router, pathPrefix string) {
sub := root.PathPrefix(pathPrefix).Subrouter()
sub.Path("/{revision}").
Methods("GET").
HandlerFunc(utils.MetricsWrapHandler("blocks_get_block", utils.WrapHandlerFunc(b.handleGetBlock)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "blocks_get_block", b.handleGetBlock))
}
6 changes: 3 additions & 3 deletions api/debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,11 @@ func (d *Debug) Mount(root *mux.Router, pathPrefix string) {

sub.Path("/tracers").
Methods(http.MethodPost).
HandlerFunc(utils.MetricsWrapHandler("debug_trace_clause", utils.WrapHandlerFunc(d.handleTraceClause)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "debug_trace_clause", d.handleTraceClause))
sub.Path("/tracers/call").
Methods(http.MethodPost).
HandlerFunc(utils.MetricsWrapHandler("debug_trace_call", utils.WrapHandlerFunc(d.handleTraceCall)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "debug_trace_call", d.handleTraceCall))
sub.Path("/storage-range").
Methods(http.MethodPost).
HandlerFunc(utils.MetricsWrapHandler("debug_debug_storage", utils.WrapHandlerFunc(d.handleDebugStorage)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "debug_debug_storage", d.handleDebugStorage))
}
2 changes: 1 addition & 1 deletion api/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,5 @@ func (e *Events) Mount(root *mux.Router, pathPrefix string) {

sub.Path("").
Methods("POST").
HandlerFunc(utils.MetricsWrapHandler("events_filter", utils.WrapHandlerFunc(e.handleFilter)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "events_filter", e.handleFilter))
}
2 changes: 1 addition & 1 deletion api/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ func (n *Node) Mount(root *mux.Router, pathPrefix string) {

sub.Path("/network/peers").
Methods("Get").
HandlerFunc(utils.MetricsWrapHandler("node_network", utils.WrapHandlerFunc(n.handleNetwork)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "node_network", n.handleNetwork))
}
4 changes: 2 additions & 2 deletions api/subscriptions/subscriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,8 @@ func (s *Subscriptions) Mount(root *mux.Router, pathPrefix string) {

sub.Path("/txpool").
Methods("Get").
HandlerFunc(utils.MetricsWrapHandler("subscriptions_pending_transactions", utils.WrapHandlerFunc(s.handlePendingTransactions)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "subscriptions_pending_transactions", s.handlePendingTransactions))
sub.Path("/{subject}").
Methods("Get").
HandlerFunc(utils.MetricsWrapHandler("subscriptions_subject", utils.WrapHandlerFunc(s.handleSubject)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "subscriptions_subject", s.handleSubject))
}
6 changes: 3 additions & 3 deletions api/transactions/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,11 +217,11 @@ func (t *Transactions) Mount(root *mux.Router, pathPrefix string) {

sub.Path("").
Methods("POST").
HandlerFunc(utils.MetricsWrapHandler("transactions_send_transaction", utils.WrapHandlerFunc(t.handleSendTransaction)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "transactions_send_transaction", t.handleSendTransaction))
sub.Path("/{id}").
Methods("GET").
HandlerFunc(utils.MetricsWrapHandler("transactions_get_transaction_by_id", utils.WrapHandlerFunc(t.handleGetTransactionByID)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "transactions_get_transaction_by_id", t.handleGetTransactionByID))
sub.Path("/{id}/receipt").
Methods("GET").
HandlerFunc(utils.MetricsWrapHandler("transactions_get_transaction_by_receipt", utils.WrapHandlerFunc(t.handleGetTransactionReceiptByID)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "transactions_get_transaction_by_receipt", t.handleGetTransactionReceiptByID))
}
2 changes: 1 addition & 1 deletion api/transfers/transfers.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ func (t *Transfers) Mount(root *mux.Router, pathPrefix string) {

sub.Path("").
Methods("POST").
HandlerFunc(utils.MetricsWrapHandler("transfers_transfer_logs", utils.WrapHandlerFunc(t.handleFilterTransferLogs)))
HandlerFunc(utils.MetricsWrapHandler(pathPrefix, "transfers_transfer_logs", t.handleFilterTransferLogs))
}
35 changes: 27 additions & 8 deletions api/utils/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ package utils

import (
"encoding/json"
"github.com/vechain/thor/v2/telemetry"

Check failure on line 10 in api/utils/http.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `goimports`-ed (goimports)
"io"
"net/http"
"strconv"
"strings"
"time"

"github.com/vechain/thor/v2/telemetry"
)

type httpError struct {
Expand Down Expand Up @@ -71,14 +72,32 @@ func WrapHandlerFunc(f HandlerFunc) http.HandlerFunc {
}

// MetricsWrapHandler wraps a given handler and adds metrics to it
func MetricsWrapHandler(endpoint string, f http.HandlerFunc) http.HandlerFunc {
counter := telemetry.Counter("api_" + endpoint + "_count_requests")
duration := telemetry.HistogramWithHTTPBuckets("api_" + endpoint + "_duration_ms")
func MetricsWrapHandler(pathPrefix, endpoint string, f HandlerFunc) http.HandlerFunc {
fixedPath := strings.ReplaceAll(pathPrefix, "/", "_") // ensure no unexpected slashes
httpReqCounter := telemetry.CounterVec(fixedPath+"_request_count", []string{"path", "code", "method"})
httpReqDuration := telemetry.HistogramVecWithHTTPBuckets(fixedPath+"_duration_ms", []string{"path", "code", "method"})

return func(w http.ResponseWriter, r *http.Request) {
now := time.Now()
f(w, r)
counter.Add(1)
duration.Observe(time.Since(now).Milliseconds())
err := f(w, r)

method := r.Method
status := http.StatusOK
if err != nil {
if he, ok := err.(*httpError); ok {
if he.cause != nil {
http.Error(w, he.cause.Error(), he.status)
} else {
w.WriteHeader(he.status)
}
status = he.status
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
status = http.StatusInternalServerError
}
}
httpReqCounter.AddWithLabel(1, map[string]string{"path": endpoint, "code": strconv.Itoa(status), "method": method})
httpReqDuration.ObserveWithLabels(time.Since(now).Milliseconds(), map[string]string{"path": endpoint, "code": strconv.Itoa(status), "method": method})
}
}

Expand Down
18 changes: 18 additions & 0 deletions telemetry/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,36 @@ import "net/http"
// noopTelemetry implements a no operations telemetry service
type noopTelemetry struct{}

func (n *noopTelemetry) GetOrCreateHistogramVecMeter(name string, labels []string, buckets []int64) HistogramVecMeter {
return &noopTelemetry{}
}

func defaultNoopTelemetry() Telemetry { return &noopTelemetry{} }

func (n *noopTelemetry) GetOrCreateHistogramMeter(string, []int64) HistogramMeter { return &noopMetric }

func (n *noopTelemetry) GetOrCreateCountMeter(string) CountMeter { return &noopMetric }

func (n *noopTelemetry) GetOrCreateCountVecMeter(_ string, _ []string) CountVecMeter {
return &noopMetric
}

func (n *noopTelemetry) GetOrCreateGaugeVecMeter(name string, labels []string) GaugeVecMeter {
return &noopMetric
}

func (n *noopTelemetry) GetOrCreateHandler() http.Handler { return nil }

var noopMetric = noopMeters{}

type noopMeters struct{}

func (n noopMeters) GaugeWithLabel(i int64, m map[string]string) {}

func (n noopMeters) AddWithLabel(i int64, m map[string]string) {}

func (n noopMeters) Add(int64) {}

func (n noopMeters) Observe(int64) {}

func (n *noopTelemetry) ObserveWithLabels(i int64, m map[string]string) {}
7 changes: 7 additions & 0 deletions telemetry/noop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"math/rand"
"net/http"
"net/http/httptest"
"strconv"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -33,6 +34,12 @@ func TestNoopTelemetry(t *testing.T) {
histTotal += i
}

countVect := CounterVec("countVec1", []string{"zeroOrOne"})
for i := 0; i < rand.Intn(100)+1; i++ {
color := i % 2
countVect.AddWithLabel(int64(i), map[string]string{"color": strconv.Itoa(color)})
}

// Make a request to the metrics endpoint
resp, err := http.Get(server.URL + "/metrics")
if err != nil {
Expand Down
Loading

0 comments on commit c0ef281

Please sign in to comment.