Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: change wasm metrics method #358

Merged
merged 2 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions x/wasm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/line/lbm-sdk/codec"
"github.com/line/lbm-sdk/store/prefix"
"github.com/line/lbm-sdk/telemetry"
sdk "github.com/line/lbm-sdk/types"
sdkerrors "github.com/line/lbm-sdk/types/errors"
authkeeper "github.com/line/lbm-sdk/x/auth/keeper"
Expand Down Expand Up @@ -66,6 +65,7 @@ type Keeper struct {
wasmVMQueryHandler WasmVMQueryHandler
wasmVMResponseHandler WasmVMResponseHandler
messenger Messenger
metrics *Metrics
// queryGasLimit is the max wasmvm gas that can be spent on executing a query with a contract
queryGasLimit uint64
paramSpace *paramtypes.Subspace
Expand Down Expand Up @@ -115,6 +115,7 @@ func NewKeeper(
messenger: NewDefaultMessageHandler(router, encodeRouter, channelKeeper, capabilityKeeper, bankKeeper, cdc, portSource, customEncoders),
queryGasLimit: wasmConfig.SmartQueryGasLimit,
paramSpace: paramSpace,
metrics: NopMetrics(),
}

keeper.wasmVMQueryHandler = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, channelKeeper, queryRouter, keeper).Merge(customPlugins)
Expand Down Expand Up @@ -233,7 +234,7 @@ func (k Keeper) importCode(ctx sdk.Context, codeID uint64, codeInfo types.CodeIn
}

func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authZ AuthorizationPolicy) (sdk.AccAddress, []byte, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "instantiate")
defer func(begin time.Time) { k.metrics.InstantiateElapsedTimes.Observe(time.Since(begin).Seconds()) }(time.Now())
if !k.IsPinnedCode(ctx, codeID) {
ctx.GasMeter().ConsumeGas(k.getInstanceCost(ctx), "Loading CosmWasm module: instantiate")
}
Expand Down Expand Up @@ -331,7 +332,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A

// Execute executes the contract instance
func (k Keeper) execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) (*sdk.Result, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "execute")
defer func(begin time.Time) { k.metrics.ExecuteElapsedTimes.Observe(time.Since(begin).Seconds()) }(time.Now())
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress)
if err != nil {
return nil, err
Expand Down Expand Up @@ -380,7 +381,7 @@ func (k Keeper) execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
}

func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) (*sdk.Result, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "migrate")
defer func(begin time.Time) { k.metrics.MigrateElapsedTimes.Observe(time.Since(begin).Seconds()) }(time.Now())
if !k.IsPinnedCode(ctx, newCodeID) {
ctx.GasMeter().ConsumeGas(k.getInstanceCost(ctx), "Loading CosmWasm module: migrate")
}
Expand Down Expand Up @@ -459,7 +460,7 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller
// another native Go module directly. Thus, the keeper doesn't place any access controls on it, that is the
// responsibility or the app developer (who passes the wasm.Keeper in app.go)
func (k Keeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) (*sdk.Result, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "sudo")
defer func(begin time.Time) { k.metrics.SudoElapsedTimes.Observe(time.Since(begin).Seconds()) }(time.Now())
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress)
if err != nil {
return nil, err
Expand Down Expand Up @@ -636,7 +637,7 @@ func (k Keeper) getLastContractHistoryEntry(ctx sdk.Context, contractAddr sdk.Ac

// QuerySmart queries the smart contract itself.
func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "query-smart")
defer func(begin time.Time) { k.metrics.QuerySmartElapsedTimes.Observe(time.Since(begin).Seconds()) }(time.Now())
contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr)
if err != nil {
return nil, err
Expand All @@ -660,7 +661,7 @@ func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []b

// QueryRaw returns the contract's state for give key. Returns `nil` when key is `nil`.
func (k Keeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte {
defer telemetry.MeasureSince(time.Now(), "wasm", "contract", "query-raw")
defer func(begin time.Time) { k.metrics.QueryRawElapsedTimes.Observe(time.Since(begin).Seconds()) }(time.Now())
if key == nil {
return nil
}
Expand Down
106 changes: 94 additions & 12 deletions x/wasm/keeper/metrics.go
Original file line number Diff line number Diff line change
@@ -1,35 +1,117 @@
package keeper

import (
"github.com/go-kit/kit/metrics"
"github.com/go-kit/kit/metrics/discard"
go_prometheus "github.com/go-kit/kit/metrics/prometheus"
wasmvmtypes "github.com/line/wasmvm/types"
"github.com/prometheus/client_golang/prometheus"
)

const (
labelPinned = "pinned"
labelMemory = "memory"
labelFs = "fs"
labelPinned = "pinned"
labelMemory = "memory"
labelFs = "fs"
MetricsSubsystem = "wasm"
)

type Metrics struct {
InstantiateElapsedTimes metrics.Histogram
ExecuteElapsedTimes metrics.Histogram
MigrateElapsedTimes metrics.Histogram
SudoElapsedTimes metrics.Histogram
QuerySmartElapsedTimes metrics.Histogram
QueryRawElapsedTimes metrics.Histogram
}

func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics {
return &Metrics{
InstantiateElapsedTimes: go_prometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "instantiate",
Help: "elapsed time of Instantiate the wasm contract",
}, nil),
ExecuteElapsedTimes: go_prometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "execute",
Help: "elapsed time of Execute the wasm contract",
}, nil),
MigrateElapsedTimes: go_prometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "migrate",
Help: "elapsed time of Migrate the wasm contract",
}, nil),
SudoElapsedTimes: go_prometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "sudo",
Help: "elapsed time of Sudo the wasm contract",
}, nil),
QuerySmartElapsedTimes: go_prometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "query_smart",
Help: "elapsed time of QuerySmart the wasm contract",
}, nil),
QueryRawElapsedTimes: go_prometheus.NewSummaryFrom(prometheus.SummaryOpts{
Namespace: namespace,
Subsystem: MetricsSubsystem,
Name: "query_raw",
Help: "elapsed time of QueryRaw the wasm contract",
}, nil),
}
}

// NopMetrics returns no-op Metrics.
func NopMetrics() *Metrics {
return &Metrics{
InstantiateElapsedTimes: discard.NewHistogram(),
ExecuteElapsedTimes: discard.NewHistogram(),
MigrateElapsedTimes: discard.NewHistogram(),
SudoElapsedTimes: discard.NewHistogram(),
QuerySmartElapsedTimes: discard.NewHistogram(),
QueryRawElapsedTimes: discard.NewHistogram(),
}
}

type MetricsProvider func() *Metrics

// PrometheusMetricsProvider returns PrometheusMetrics for each store
func PrometheusMetricsProvider(namespace string, labelsAndValues ...string) func() *Metrics {
return func() *Metrics {
return PrometheusMetrics(namespace, labelsAndValues...)
}
}

// NopMetricsProvider returns NopMetrics for each store
func NopMetricsProvider() func() *Metrics {
return func() *Metrics {
return NopMetrics()
}
}

// metricSource source of wasmvm metrics
type metricSource interface {
GetMetrics() (*wasmvmtypes.Metrics, error)
}

var _ prometheus.Collector = (*WasmVMMetricsCollector)(nil)
var _ prometheus.Collector = (*WasmVMCacheMetricsCollector)(nil)

// WasmVMMetricsCollector custom metrics collector to be used with Prometheus
type WasmVMMetricsCollector struct {
// WasmVMCacheMetricsCollector custom metrics collector to be used with Prometheus
type WasmVMCacheMetricsCollector struct {
source metricSource
CacheHitsDescr *prometheus.Desc
CacheMissesDescr *prometheus.Desc
CacheElementsDescr *prometheus.Desc
CacheSizeDescr *prometheus.Desc
}

//NewWasmVMMetricsCollector constructor
func NewWasmVMMetricsCollector(s metricSource) *WasmVMMetricsCollector {
return &WasmVMMetricsCollector{
//NewWasmVMCacheMetricsCollector constructor
func NewWasmVMCacheMetricsCollector(s metricSource) *WasmVMCacheMetricsCollector {
return &WasmVMCacheMetricsCollector{
source: s,
CacheHitsDescr: prometheus.NewDesc("wasmvm_cache_hits_total", "Total number of cache hits", []string{"type"}, nil),
CacheMissesDescr: prometheus.NewDesc("wasmvm_cache_misses_total", "Total number of cache misses", nil, nil),
Expand All @@ -39,20 +121,20 @@ func NewWasmVMMetricsCollector(s metricSource) *WasmVMMetricsCollector {
}

// Register registers all metrics
func (p *WasmVMMetricsCollector) Register(r prometheus.Registerer) {
func (p *WasmVMCacheMetricsCollector) Register(r prometheus.Registerer) {
r.MustRegister(p)
}

// Describe sends the super-set of all possible descriptors of metrics
func (p *WasmVMMetricsCollector) Describe(descs chan<- *prometheus.Desc) {
func (p *WasmVMCacheMetricsCollector) Describe(descs chan<- *prometheus.Desc) {
descs <- p.CacheHitsDescr
descs <- p.CacheMissesDescr
descs <- p.CacheElementsDescr
descs <- p.CacheSizeDescr
}

// Collect is called by the Prometheus registry when collecting metrics.
func (p *WasmVMMetricsCollector) Collect(c chan<- prometheus.Metric) {
func (p *WasmVMCacheMetricsCollector) Collect(c chan<- prometheus.Metric) {
m, err := p.source.GetMetrics()
if err != nil {
return
Expand Down
8 changes: 7 additions & 1 deletion x/wasm/keeper/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ func WithCoinTransferrer(x CoinTransferrer) Option {

func WithVMCacheMetrics(r prometheus.Registerer) Option {
return optsFn(func(k *Keeper) {
NewWasmVMMetricsCollector(k.wasmVM).Register(r)
NewWasmVMCacheMetricsCollector(k.wasmVM).Register(r)
})
}

func WithVMMetrics(provider MetricsProvider) Option {
return optsFn(func(k *Keeper) {
k.metrics = provider()
})
}