Skip to content
This repository has been archived by the owner on Apr 2, 2024. It is now read-only.

Commit

Permalink
Merge pull request #579 from BuxOrg/feat-567-metrics
Browse files Browse the repository at this point in the history
feat(BUX-567): metrics
  • Loading branch information
chris-4chain authored Feb 12, 2024
2 parents 038f050 + 36a09b8 commit b0a6e9f
Show file tree
Hide file tree
Showing 20 changed files with 337 additions and 33 deletions.
10 changes: 9 additions & 1 deletion chainstate/chainstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ func (c *Client) Broadcast(ctx context.Context, id, txHex string, timeout time.D
// Note: this is slow, but follows a specific order: mAPI -> WhatsOnChain
func (c *Client) QueryTransaction(
ctx context.Context, id string, requiredIn RequiredIn, timeout time.Duration,
) (*TransactionInfo, error) {
) (transaction *TransactionInfo, err error) {
if c.options.metrics != nil {
end := c.options.metrics.TrackQueryTransaction()
defer func() {
success := err == nil
end(success)
}()
}

// Basic validation
if len(id) < 50 {
return nil, ErrInvalidTransactionID
Expand Down
14 changes: 7 additions & 7 deletions chainstate/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/BuxOrg/bux/logging"
"github.com/BuxOrg/bux/metrics"
"github.com/BuxOrg/bux/utils"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
"github.com/newrelic/go-agent/v3/newrelic"
Expand All @@ -23,11 +24,12 @@ type (

// clientOptions holds all the configuration for the client
clientOptions struct {
config *syncConfig // Configuration for broadcasting and other chain-state actions
debug bool // For extra logs and additional debug information
logger *zerolog.Logger // Logger interface
newRelicEnabled bool // If NewRelic is enabled (parent application)
userAgent string // Custom user agent for outgoing HTTP Requests
config *syncConfig // Configuration for broadcasting and other chain-state actions
debug bool // For extra logs and additional debug information
logger *zerolog.Logger // Logger interface
metrics *metrics.Metrics // For collecting metrics (if enabled)
newRelicEnabled bool // If NewRelic is enabled (parent application)
userAgent string // Custom user agent for outgoing HTTP Requests
}

// syncConfig holds all the configuration about the different sync processes
Expand Down Expand Up @@ -95,12 +97,10 @@ func (c *Client) Close(ctx context.Context) {
defer txn.StartSegment("close_chainstate").End()
}
if c != nil && c.options.config != nil {

// Close minercraft
if c.options.config.minercraft != nil {
c.options.config.minercraft = nil
}

}
}

Expand Down
9 changes: 9 additions & 0 deletions chainstate/client_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"time"

"github.com/BuxOrg/bux/metrics"
"github.com/BuxOrg/bux/utils"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
"github.com/newrelic/go-agent/v3/newrelic"
Expand Down Expand Up @@ -33,6 +34,7 @@ func defaultClientOptions() *clientOptions {
},
debug: false,
newRelicEnabled: false,
metrics: nil,
}
}

Expand Down Expand Up @@ -173,3 +175,10 @@ func WithCallback(callbackURL, callbackAuthToken string) ClientOps {
c.config.callbackToken = callbackAuthToken
}
}

// WithMetrics will set metrics
func WithMetrics(metrics *metrics.Metrics) ClientOps {
return func(c *clientOptions) {
c.metrics = metrics
}
}
7 changes: 7 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/BuxOrg/bux/chainstate"
"github.com/BuxOrg/bux/cluster"
"github.com/BuxOrg/bux/logging"
"github.com/BuxOrg/bux/metrics"
"github.com/BuxOrg/bux/notifications"
"github.com/BuxOrg/bux/taskmanager"
"github.com/bitcoin-sv/go-paymail"
Expand Down Expand Up @@ -35,6 +36,7 @@ type (
httpClient HTTPInterface // HTTP interface to use
iuc bool // (Input UTXO Check) True will check input utxos when saving transactions
logger *zerolog.Logger // Internal logging
metrics *metrics.Metrics // Metrics with a collector interface
models *modelOptions // Configuration options for the loaded models
newRelic *newRelicOptions // Configuration options for NewRelic
notifications *notificationsOptions // Configuration options for Notifications
Expand Down Expand Up @@ -416,3 +418,8 @@ func (c *Client) UserAgent() string {
func (c *Client) Version() string {
return version
}

// Metrics will return the metrics client (if it's enabled)
func (c *Client) Metrics() (metrics *metrics.Metrics, enabled bool) {
return c.options.metrics, c.options.metrics != nil
}
2 changes: 2 additions & 0 deletions client_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bux

import (
"context"

"github.com/BuxOrg/bux/chainstate"
"github.com/BuxOrg/bux/cluster"
"github.com/BuxOrg/bux/notifications"
Expand Down Expand Up @@ -37,6 +38,7 @@ func (c *Client) loadChainstate(ctx context.Context) (err error) {
if c.options.chainstate.ClientInterface == nil {
c.options.chainstate.options = append(c.options.chainstate.options, chainstate.WithUserAgent(c.UserAgent()))
c.options.chainstate.options = append(c.options.chainstate.options, chainstate.WithHTTPClient(c.HTTPClient()))
c.options.chainstate.options = append(c.options.chainstate.options, chainstate.WithMetrics(c.options.metrics))
c.options.chainstate.ClientInterface, err = chainstate.NewClient(ctx, c.options.chainstate.options...)
}

Expand Down
14 changes: 14 additions & 0 deletions client_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/BuxOrg/bux/chainstate"
"github.com/BuxOrg/bux/cluster"
"github.com/BuxOrg/bux/logging"
"github.com/BuxOrg/bux/metrics"
"github.com/BuxOrg/bux/notifications"
"github.com/BuxOrg/bux/taskmanager"
"github.com/BuxOrg/bux/utils"
Expand Down Expand Up @@ -283,6 +284,19 @@ func WithLogger(customLogger *zerolog.Logger) ClientOps {
}
}

// -----------------------------------------------------------------
// METRICS
// -----------------------------------------------------------------

// WithMetrics will set the metrics with a collector interface
func WithMetrics(collector metrics.Collector) ClientOps {
return func(c *clientOptions) {
if collector != nil {
c.metrics = metrics.NewMetrics(collector)
}
}
}

// -----------------------------------------------------------------
// CACHESTORE
// -----------------------------------------------------------------
Expand Down
61 changes: 44 additions & 17 deletions cron_job_declarations.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,58 @@ const (
CronJobNameDraftTransactionCleanUp = "draft_transaction_clean_up"
CronJobNameSyncTransactionBroadcast = "sync_transaction_broadcast"
CronJobNameSyncTransactionSync = "sync_transaction_sync"
CronJobNameCalculateMetrics = "calculate_metrics"
)

type cronJobHandler func(ctx context.Context, client *Client) error

// here is where we define all the cron jobs for the client
func (c *Client) cronJobs() taskmanager.CronJobs {
// handler adds the client pointer to the cronJobTask by using a closure
handler := func(cronJobTask cronJobHandler) taskmanager.CronJobHandler {
return func(ctx context.Context) error {
return cronJobTask(ctx, c)
jobs := taskmanager.CronJobs{}

addJob := func(name string, period time.Duration, task cronJobHandler) {
// handler adds the client pointer to the cronJobTask by using a closure
handler := func(ctx context.Context) (err error) {
if metrics, enabled := c.Metrics(); enabled {
end := metrics.TrackCron(name)
defer func() {
success := err == nil
end(success)
}()
}
err = task(ctx, c)
return
}

jobs[name] = taskmanager.CronJob{
Handler: handler,
Period: period,
}
}

return taskmanager.CronJobs{
CronJobNameDraftTransactionCleanUp: {
Period: 60 * time.Second,
Handler: handler(taskCleanupDraftTransactions),
},
CronJobNameSyncTransactionBroadcast: {
Period: 2 * time.Minute,
Handler: handler(taskBroadcastTransactions),
},
CronJobNameSyncTransactionSync: {
Period: 5 * time.Minute,
Handler: handler(taskSyncTransactions),
},
addJob(
CronJobNameDraftTransactionCleanUp,
60*time.Second,
taskCleanupDraftTransactions,
)
addJob(
CronJobNameSyncTransactionBroadcast,
2*time.Minute,
taskBroadcastTransactions,
)
addJob(
CronJobNameSyncTransactionSync,
5*time.Minute,
taskSyncTransactions,
)

if _, enabled := c.Metrics(); enabled {
addJob(
CronJobNameCalculateMetrics,
15*time.Second,
taskCalculateMetrics,
)
}

return jobs
}
41 changes: 41 additions & 0 deletions cron_job_definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,44 @@ func taskSyncTransactions(ctx context.Context, client *Client) error {
}
return err
}

func taskCalculateMetrics(ctx context.Context, client *Client) error {
m, enabled := client.Metrics()
if !enabled {
return errors.New("metrics are not enabled")
}

modelOpts := client.DefaultModelOptions()

if xpubsCount, err := getXPubsCount(ctx, nil, nil, modelOpts...); err != nil {
client.options.logger.Error().Err(err).Msg("error getting xpubs count")
} else {
m.SetXPubCount(xpubsCount)
}

if utxosCount, err := getUtxosCount(ctx, nil, nil, modelOpts...); err != nil {
client.options.logger.Error().Err(err).Msg("error getting utxos count")
} else {
m.SetUtxoCount(utxosCount)
}

if paymailsCount, err := getPaymailAddressesCount(ctx, nil, nil, modelOpts...); err != nil {
client.options.logger.Error().Err(err).Msg("error getting paymails count")
} else {
m.SetPaymailCount(paymailsCount)
}

if destinationsCount, err := getDestinationsCount(ctx, nil, nil, modelOpts...); err != nil {
client.options.logger.Error().Err(err).Msg("error getting destinations count")
} else {
m.SetDestinationCount(destinationsCount)
}

if accessKeysCount, err := getAccessKeysCount(ctx, nil, nil, modelOpts...); err != nil {
client.options.logger.Error().Err(err).Msg("error getting access keys count")
} else {
m.SetAccessKeyCount(accessKeysCount)
}

return nil
}
9 changes: 9 additions & 0 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/BuxOrg/bux/chainstate"
"github.com/BuxOrg/bux/cluster"
"github.com/BuxOrg/bux/metrics"
"github.com/BuxOrg/bux/notifications"
"github.com/BuxOrg/bux/taskmanager"
"github.com/bitcoin-sv/go-broadcast-client/broadcast"
Expand Down Expand Up @@ -186,4 +187,5 @@ type ClientInterface interface {
SetNotificationsClient(notifications.ClientInterface)
UserAgent() string
Version() string
Metrics() (metrics *metrics.Metrics, enabled bool)
}
10 changes: 10 additions & 0 deletions metrics/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package metrics

import "github.com/prometheus/client_golang/prometheus"

// Collector is an interface that is used to register metrics
type Collector interface {
RegisterGauge(name string) prometheus.Gauge
RegisterGaugeVec(name string, labels ...string) *prometheus.GaugeVec
RegisterHistogramVec(name string, labels ...string) *prometheus.HistogramVec
}
Loading

0 comments on commit b0a6e9f

Please sign in to comment.