Skip to content

Commit

Permalink
BCI-3127: monitoring report observation length (#418)
Browse files Browse the repository at this point in the history
  • Loading branch information
augustbleeds authored Apr 29, 2024
1 parent 09ebc1a commit 50c7a33
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 2 deletions.
8 changes: 6 additions & 2 deletions monitoring/cmd/monitoring/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,18 @@ func main() {
return
}

// per-feed factories
proxySourceFactory := monitoring.NewProxySourceFactory(ocr2Client)
monitor.SourceFactories = append(monitor.SourceFactories, proxySourceFactory)
transmissionsDetailsSourceFactory := monitoring.NewTransmissionDetailsSourceFactory(ocr2Client)
monitor.SourceFactories = append(monitor.SourceFactories, proxySourceFactory, transmissionsDetailsSourceFactory)

metricsBuilder := monitoring.NewMetrics(logger.With(log, "component", "starknet-metrics-builder"))

prometheusExporterFactory := monitoring.NewPrometheusExporterFactory(metricsBuilder)
monitor.ExporterFactories = append(monitor.ExporterFactories, prometheusExporterFactory)
transmissionsDetailsExporterFactory := monitoring.NewTransmissionDetailsExporterFactory(metricsBuilder)
monitor.ExporterFactories = append(monitor.ExporterFactories, prometheusExporterFactory, transmissionsDetailsExporterFactory)

// network factories
nodeBalancesSourceFactory := monitoring.NewNodeBalancesSourceFactory(strTokenClient)
monitor.NetworkSourceFactories = append(monitor.NetworkSourceFactories, nodeBalancesSourceFactory)

Expand Down
78 changes: 78 additions & 0 deletions monitoring/pkg/monitoring/exporter_transmission_details.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package monitoring

import (
"context"
"fmt"

relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring"
)

// NewPrometheusExporterFactory builds an implementation of the Exporter for prometheus.
func NewTransmissionDetailsExporterFactory(
metrics Metrics,
) relayMonitoring.ExporterFactory {
return &transmissionDetailsExporterFactory{
metrics,
}
}

type transmissionDetailsExporterFactory struct {
metrics Metrics
}

func (p *transmissionDetailsExporterFactory) NewExporter(
params relayMonitoring.ExporterParams,
) (relayMonitoring.Exporter, error) {
starknetFeedConfig, ok := params.FeedConfig.(StarknetFeedConfig)
if !ok {
return nil, fmt.Errorf("expected feedConfig to be of type StarknetFeedConfig not %T", params.FeedConfig)
}
return &transmissionDetailsExporter{
params.ChainConfig,
starknetFeedConfig,
p.metrics,
}, nil
}

type transmissionDetailsExporter struct {
chainConfig relayMonitoring.ChainConfig
feedConfig StarknetFeedConfig
metrics Metrics
}

func (p *transmissionDetailsExporter) Export(ctx context.Context, data interface{}) {
transmissionsEnvelope, found := data.(TransmissionsEnvelope)
if !found {
return
}

for _, t := range transmissionsEnvelope.Transmissions {
observationLength := float64(t.ObservationLength)
p.metrics.SetReportObservations(
observationLength,
p.feedConfig.ContractAddress,
p.feedConfig.GetID(),
p.chainConfig.GetChainID(),
p.feedConfig.GetContractStatus(),
p.feedConfig.GetContractType(),
p.feedConfig.Name,
p.feedConfig.Path,
p.chainConfig.GetNetworkID(),
p.chainConfig.GetNetworkName(),
)
}
}

func (p *transmissionDetailsExporter) Cleanup(_ context.Context) {
p.metrics.CleanupReportObservations(
p.feedConfig.GetContractAddress(),
p.feedConfig.GetID(),
p.chainConfig.GetChainID(),
p.feedConfig.GetContractStatus(),
p.feedConfig.GetContractType(),
p.feedConfig.GetName(),
p.feedConfig.GetPath(),
p.chainConfig.GetNetworkID(),
p.chainConfig.GetNetworkName(),
)
}
50 changes: 50 additions & 0 deletions monitoring/pkg/monitoring/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

// Metrics is an interface for prometheus metrics. Makes testing easier.
type Metrics interface {
SetReportObservations(answer float64, accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
CleanupReportObservations(accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
SetProxyAnswersRaw(answer float64, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
SetProxyAnswers(answer float64, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
CleanupProxy(proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string)
Expand All @@ -17,6 +19,23 @@ type Metrics interface {
}

var (
reportObservations = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "report_observations",
Help: "Reports # of observations included in a transmission report",
},
[]string{
"account_address",
"feed_id",
"chain_id",
"contract_status",
"contract_type",
"feed_name",
"feed_path",
"network_id",
"network_name",
},
)
proxyAnswersRaw = promauto.NewGaugeVec(
prometheus.GaugeOpts{
Name: "proxy_answers_raw",
Expand Down Expand Up @@ -72,6 +91,37 @@ func (d *defaultMetrics) CleanupBalance(contractAddress, alias, networkId, netwo
}
}

func (d *defaultMetrics) SetReportObservations(answer float64, accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
reportObservations.With(prometheus.Labels{
"account_address": accountAddress,
"feed_id": feedID,
"chain_id": chainID,
"contract_status": contractStatus,
"contract_type": contractType,
"feed_name": feedName,
"feed_path": feedPath,
"network_id": networkID,
"network_name": networkName,
}).Set(answer)
}

func (d *defaultMetrics) CleanupReportObservations(accountAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
labels := prometheus.Labels{
"account_address": accountAddress,
"feed_id": feedID,
"chain_id": chainID,
"contract_status": contractStatus,
"contract_type": contractType,
"feed_name": feedName,
"feed_path": feedPath,
"network_id": networkID,
"network_name": networkName,
}
if !reportObservations.Delete(labels) {
d.log.Errorw("failed to delete metric", "name", "report_observations", "labels", labels)
}
}

func (d *defaultMetrics) SetProxyAnswersRaw(answer float64, proxyContractAddress, feedID, chainID, contractStatus, contractType, feedName, feedPath, networkID, networkName string) {
proxyAnswersRaw.With(prometheus.Labels{
"proxy_contract_address": proxyContractAddress,
Expand Down
82 changes: 82 additions & 0 deletions monitoring/pkg/monitoring/source_transmission_details.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package monitoring

import (
"context"
"fmt"
"math/big"

"github.com/NethermindEth/juno/core/felt"
starknetutils "github.com/NethermindEth/starknet.go/utils"

relayMonitoring "github.com/smartcontractkit/chainlink-common/pkg/monitoring"

"github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/ocr2"
)

type TransmissionInfo struct {
GasPrice *big.Int
ObservationLength uint32
}

type TransmissionsEnvelope struct {
Transmissions []TransmissionInfo
}

func NewTransmissionDetailsSourceFactory(
ocr2Reader ocr2.OCR2Reader,
) relayMonitoring.SourceFactory {
return &transmissionDetailsSourceFactory{
ocr2Reader,
}
}

type transmissionDetailsSourceFactory struct {
ocr2Reader ocr2.OCR2Reader
}

func (s *transmissionDetailsSourceFactory) NewSource(
_ relayMonitoring.ChainConfig,
feedConfig relayMonitoring.FeedConfig,
) (relayMonitoring.Source, error) {
starknetFeedConfig, ok := feedConfig.(StarknetFeedConfig)
if !ok {
return nil, fmt.Errorf("expected feedConfig to be of type StarknetFeedConfig not %T", feedConfig)
}
contractAddress, err := starknetutils.HexToFelt(starknetFeedConfig.ContractAddress)
if err != nil {
return nil, err
}
return &transmissionDetailsSource{
contractAddress,
s.ocr2Reader,
}, nil
}

func (s *transmissionDetailsSourceFactory) GetType() string {
return "transmission details"
}

type transmissionDetailsSource struct {
contractAddress *felt.Felt
ocr2Reader ocr2.OCR2Reader
}

func (s *transmissionDetailsSource) Fetch(ctx context.Context) (interface{}, error) {
latestRound, err := s.ocr2Reader.LatestRoundData(ctx, s.contractAddress)
if err != nil {
return nil, fmt.Errorf("failed to fetch latest_round_data: %w", err)
}
transmissions, err := s.ocr2Reader.NewTransmissionsFromEventsAt(ctx, s.contractAddress, latestRound.BlockNumber)
if err != nil {
return nil, fmt.Errorf("couldn't fetch transmission events: %w", err)
}
var envelope TransmissionsEnvelope
for _, t := range transmissions {
envelope.Transmissions = append(
envelope.Transmissions,
TransmissionInfo{GasPrice: t.GasPrice, ObservationLength: t.ObservationsLen},
)
}

return envelope, nil
}
57 changes: 57 additions & 0 deletions monitoring/pkg/monitoring/source_transmission_details_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package monitoring

import (
"context"
"math/big"
"testing"

starknetutils "github.com/NethermindEth/starknet.go/utils"
"github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/ocr2"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

ocr2Mocks "github.com/smartcontractkit/chainlink-starknet/relayer/pkg/chainlink/ocr2/mocks"
)

func TestTransmissionDetailsSource(t *testing.T) {
chainConfig := generateChainConfig()
feedConfig := generateFeedConfig()

contractAddressFelt, err := starknetutils.HexToFelt(feedConfig.ContractAddress)
require.NoError(t, err)

ocr2Reader := ocr2Mocks.NewOCR2Reader(t)
blockNumber := uint64(777)
ocr2Reader.On(
"LatestRoundData",
mock.Anything, // ctx
contractAddressFelt,
).Return(ocr2.RoundData{BlockNumber: blockNumber}, nil).Once()
ocr2Reader.On(
"NewTransmissionsFromEventsAt",
mock.Anything, // ctx
contractAddressFelt,
blockNumber,
).Return(
[]ocr2.NewTransmissionEvent{
{
GasPrice: new(big.Int).SetUint64(7),
ObservationsLen: 7,
},
},
nil,
).Once()

factory := NewTransmissionDetailsSourceFactory(ocr2Reader)
source, err := factory.NewSource(chainConfig, feedConfig)
require.NoError(t, err)

transmissionsEnvelope, err := source.Fetch(context.Background())
require.NoError(t, err)
envelope, ok := transmissionsEnvelope.(TransmissionsEnvelope)
require.True(t, ok)

require.Equal(t, len(envelope.Transmissions), 1)
require.Equal(t, envelope.Transmissions[0].GasPrice.Uint64(), uint64(7))
require.Equal(t, envelope.Transmissions[0].ObservationLength, uint32(7))
}

0 comments on commit 50c7a33

Please sign in to comment.