diff --git a/x/epoch/keeper/abci.go b/x/epoch/keeper/abci.go index 7ed12bd74f..f99ee5e3b0 100644 --- a/x/epoch/keeper/abci.go +++ b/x/epoch/keeper/abci.go @@ -14,7 +14,12 @@ import ( var logger = seilog.NewLogger("x", "epoch", "keeper") func (k Keeper) BeginBlock(ctx sdk.Context) { - defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker) + start := time.Now() + defer func() { + epochMetrics.beginBlockerDuration.Record(ctx.Context(), time.Since(start).Seconds()) + // TODO(PLT-336): remove once epoch_begin_blocker_duration_seconds verified + telemetry.ModuleMeasureSince(types.ModuleName, start, telemetry.MetricKeyBeginBlocker) + }() lastEpoch := k.GetEpoch(ctx) logger.Info(" Block time", "current", ctx.BlockTime(), "last", lastEpoch.CurrentEpochStartTime, "epoch-duration", lastEpoch.EpochDuration) @@ -39,6 +44,8 @@ func (k Keeper) BeginBlock(ctx sdk.Context) { ), ) + epochMetrics.epochNew.Record(ctx.Context(), int64(newEpoch.CurrentEpoch)) //nolint:gosec + // TODO(PLT-336): remove once epoch_new verified metrics.SetEpochNew(newEpoch.CurrentEpoch) } } diff --git a/x/epoch/keeper/metrics.go b/x/epoch/keeper/metrics.go new file mode 100644 index 0000000000..b7ba0f5342 --- /dev/null +++ b/x/epoch/keeper/metrics.go @@ -0,0 +1,39 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("epoch_keeper") + + // finerGrainedBuckets units are in seconds + finerGrainedBuckets = metric.WithExplicitBucketBoundaries( + 0.000025, 0.000050, 0.0001, 0.0005, 0.001, 0.0025, 0.005, 0.010, 0.020, 0.050, 0.075, 0.1, 0.25, 0.5, 1, 10, + ) + + epochMetrics = struct { + beginBlockerDuration metric.Float64Histogram + epochNew metric.Int64Gauge + }{ + beginBlockerDuration: must(meter.Float64Histogram( + "epoch_begin_blocker_duration", + metric.WithDescription("Duration of epoch begin-blocker execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + epochNew: must(meter.Int64Gauge( + "epoch_new", + metric.WithDescription("Current epoch number"), + metric.WithUnit("{epoch}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/x/mint/types/metrics.go b/x/mint/types/metrics.go new file mode 100644 index 0000000000..123d029a39 --- /dev/null +++ b/x/mint/types/metrics.go @@ -0,0 +1,27 @@ +package types + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("mint") + + mintMetrics = struct { + coinsMinted metric.Int64Gauge + }{ + coinsMinted: must(meter.Int64Gauge( + "mint_coins_minted", + metric.WithDescription("Amount of coins minted by denom"), + metric.WithUnit("{usei}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/x/mint/types/minter.go b/x/mint/types/minter.go index b3e10da670..8ab1b5b438 100644 --- a/x/mint/types/minter.go +++ b/x/mint/types/minter.go @@ -4,6 +4,9 @@ import ( fmt "fmt" "time" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" + sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" "github.com/sei-protocol/sei-chain/utils/metrics" epochTypes "github.com/sei-protocol/sei-chain/x/epoch/types" @@ -98,6 +101,8 @@ func (m *Minter) RecordSuccessfulMint(ctx sdk.Context, epoch epochTypes.Epoch, m m.LastMintDate = epoch.CurrentEpochStartTime.Format(TokenReleaseDateFormat) m.LastMintHeight = uint64(epoch.CurrentEpochHeight) //nolint:gosec m.LastMintAmount = mintedAmount + mintMetrics.coinsMinted.Record(ctx.Context(), int64(mintedAmount), otelmetric.WithAttributes(attribute.String("denom", m.GetDenom()))) //nolint:gosec + // TODO(PLT-336): remove once mint_coins_minted verified metrics.SetCoinsMinted(mintedAmount, m.GetDenom()) ctx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/x/oracle/abci.go b/x/oracle/abci.go index 62196611a4..57607cb43c 100755 --- a/x/oracle/abci.go +++ b/x/oracle/abci.go @@ -4,6 +4,9 @@ import ( "sort" "time" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" + "github.com/sei-protocol/sei-chain/utils/metrics" "github.com/sei-protocol/sei-chain/x/oracle/keeper" "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -14,7 +17,12 @@ import ( ) func MidBlocker(ctx sdk.Context, k keeper.Keeper) { - defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyMidBlocker) + start := time.Now() + defer func() { + oracleMetrics.midBlockerDuration.Record(ctx.Context(), time.Since(start).Seconds()) + // TODO(PLT-336): remove once oracle_mid_blocker_duration_seconds verified + telemetry.ModuleMeasureSince(types.ModuleName, start, telemetry.MetricKeyMidBlocker) + }() params := k.GetParams(ctx) if utils.IsPeriodLastBlock(ctx, params.VotePeriod) { @@ -91,6 +99,8 @@ func MidBlocker(ctx sdk.Context, k keeper.Keeper) { } // Set the exchange rate, emit ABCI event + oracleMetrics.priceUpdateTotal.Add(ctx.Context(), 1, otelmetric.WithAttributes(attribute.String("denom", denom))) + // TODO(PLT-336): remove once oracle_price_update_total verified metrics.IncrPriceUpdateDenom(denom) k.SetBaseExchangeRateWithEvent(ctx, denom, exchangeRate) } @@ -140,7 +150,12 @@ func MidBlocker(ctx sdk.Context, k keeper.Keeper) { } func EndBlocker(ctx sdk.Context, k keeper.Keeper) { - defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyEndBlocker) + start := time.Now() + defer func() { + oracleMetrics.endBlockerDuration.Record(ctx.Context(), time.Since(start).Seconds()) + // TODO(PLT-336): remove once oracle_end_blocker_duration_seconds verified + telemetry.ModuleMeasureSince(types.ModuleName, start, telemetry.MetricKeyEndBlocker) + }() params := k.GetParams(ctx) // Do slash who did miss voting over threshold and diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go index 3a2ec47b82..1a6c53f414 100755 --- a/x/oracle/keeper/keeper.go +++ b/x/oracle/keeper/keeper.go @@ -6,6 +6,9 @@ import ( "sort" "sync" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" + "github.com/sei-protocol/sei-chain/utils/datastructures" "github.com/sei-protocol/sei-chain/utils/metrics" @@ -202,9 +205,16 @@ func (k Keeper) GetVotePenaltyCounter(ctx sdk.Context, operator sdk.ValAddress) // SetVotePenaltyCounter updates the # of vote periods missed in this oracle slash window func (k Keeper) SetVotePenaltyCounter(ctx sdk.Context, operator sdk.ValAddress, missCount, abstainCount, successCount uint64) { - defer metrics.SetOracleVotePenaltyCount(missCount, operator.String(), "miss") - defer metrics.SetOracleVotePenaltyCount(abstainCount, operator.String(), "abstain") - defer metrics.SetOracleVotePenaltyCount(successCount, operator.String(), "success") + defer func() { + valLabel := attribute.String("validator", operator.String()) + oracleKeeperMetrics.votePenaltyCount.Record(ctx.Context(), int64(missCount), otelmetric.WithAttributes(valLabel, missTypeAttribute)) //nolint:gosec + oracleKeeperMetrics.votePenaltyCount.Record(ctx.Context(), int64(abstainCount), otelmetric.WithAttributes(valLabel, abstainTypeAttribute)) //nolint:gosec + oracleKeeperMetrics.votePenaltyCount.Record(ctx.Context(), int64(successCount), otelmetric.WithAttributes(valLabel, successTypeAttribute)) //nolint:gosec + // TODO(PLT-336): remove once oracle_vote_penalty_count verified + metrics.SetOracleVotePenaltyCount(missCount, operator.String(), "miss") + metrics.SetOracleVotePenaltyCount(abstainCount, operator.String(), "abstain") + metrics.SetOracleVotePenaltyCount(successCount, operator.String(), "success") + }() store := ctx.KVStore(k.storeKey) bz := k.cdc.MustMarshal(&types.VotePenaltyCounter{MissCount: missCount, AbstainCount: abstainCount, SuccessCount: successCount}) @@ -243,9 +253,16 @@ func (k Keeper) GetSuccessCount(ctx sdk.Context, operator sdk.ValAddress) uint64 // DeleteVotePenaltyCounter removes miss counter for the validator func (k Keeper) DeleteVotePenaltyCounter(ctx sdk.Context, operator sdk.ValAddress) { - defer metrics.SetOracleVotePenaltyCount(0, operator.String(), "miss") - defer metrics.SetOracleVotePenaltyCount(0, operator.String(), "abstain") - defer metrics.SetOracleVotePenaltyCount(0, operator.String(), "success") + defer func() { + valLabel := attribute.String("validator", operator.String()) + oracleKeeperMetrics.votePenaltyCount.Record(ctx.Context(), 0, otelmetric.WithAttributes(valLabel, missTypeAttribute)) + oracleKeeperMetrics.votePenaltyCount.Record(ctx.Context(), 0, otelmetric.WithAttributes(valLabel, abstainTypeAttribute)) + oracleKeeperMetrics.votePenaltyCount.Record(ctx.Context(), 0, otelmetric.WithAttributes(valLabel, successTypeAttribute)) + // TODO(PLT-336): remove once oracle_vote_penalty_count verified + metrics.SetOracleVotePenaltyCount(0, operator.String(), "miss") + metrics.SetOracleVotePenaltyCount(0, operator.String(), "abstain") + metrics.SetOracleVotePenaltyCount(0, operator.String(), "success") + }() store := ctx.KVStore(k.storeKey) store.Delete(types.GetVotePenaltyCounterKey(operator)) diff --git a/x/oracle/keeper/metrics.go b/x/oracle/keeper/metrics.go new file mode 100644 index 0000000000..109ae1f27e --- /dev/null +++ b/x/oracle/keeper/metrics.go @@ -0,0 +1,38 @@ +package keeper + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("oracle_keeper") + + missTypeAttribute = attribute.String("type", "miss") + abstainTypeAttribute = attribute.String("type", "abstain") + successTypeAttribute = attribute.String("type", "success") + + oracleKeeperMetrics = struct { + votePenaltyCount metric.Int64Gauge + validatorSlashedTotal metric.Int64Counter + }{ + votePenaltyCount: must(meter.Int64Gauge( + "oracle_vote_penalty_count", + metric.WithDescription("Oracle vote penalty counts by validator and type (miss, abstain, success)"), + metric.WithUnit("{count}"), + )), + validatorSlashedTotal: must(meter.Int64Counter( + "oracle_validator_slashed", + metric.WithDescription("Number of validators slashed by oracle"), + metric.WithUnit("{count}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +} diff --git a/x/oracle/keeper/slash.go b/x/oracle/keeper/slash.go index 1e4d3b81db..a64c898891 100755 --- a/x/oracle/keeper/slash.go +++ b/x/oracle/keeper/slash.go @@ -3,6 +3,9 @@ package keeper import ( "strconv" + "go.opentelemetry.io/otel/attribute" + otelmetric "go.opentelemetry.io/otel/metric" + cosmostelemetry "github.com/sei-protocol/sei-chain/sei-cosmos/telemetry" sdk "github.com/sei-protocol/sei-chain/sei-cosmos/types" "github.com/sei-protocol/sei-chain/x/oracle/types" @@ -47,6 +50,8 @@ func (k Keeper) SlashAndResetCounters(ctx sdk.Context) { distributionHeight, validator.GetConsensusPower(powerReduction), slashFraction, ) k.StakingKeeper.Jail(ctx, consAddr) + oracleKeeperMetrics.validatorSlashedTotal.Add(ctx.Context(), 1, otelmetric.WithAttributes(attribute.String("validator", consAddr.String()), attribute.String("type", "oracle"))) + // TODO(PLT-336): remove once oracle_validator_slashed_total verified cosmostelemetry.IncrValidatorSlashedCounter(consAddr.String(), "oracle") } } diff --git a/x/oracle/metrics.go b/x/oracle/metrics.go new file mode 100644 index 0000000000..9658edd47b --- /dev/null +++ b/x/oracle/metrics.go @@ -0,0 +1,46 @@ +package oracle + +import ( + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/metric" +) + +var ( + meter = otel.Meter("oracle") + + // finerGrainedBuckets units are in seconds + finerGrainedBuckets = metric.WithExplicitBucketBoundaries( + 0.000025, 0.000050, 0.0001, 0.0005, 0.001, 0.0025, 0.005, 0.010, 0.020, 0.050, 0.075, 0.1, 0.25, 0.5, 1, 10, + ) + + oracleMetrics = struct { + midBlockerDuration metric.Float64Histogram + endBlockerDuration metric.Float64Histogram + priceUpdateTotal metric.Int64Counter + }{ + midBlockerDuration: must(meter.Float64Histogram( + "oracle_mid_blocker_duration", + metric.WithDescription("Duration of oracle mid-blocker execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + endBlockerDuration: must(meter.Float64Histogram( + "oracle_end_blocker_duration", + metric.WithDescription("Duration of oracle end-blocker execution in seconds"), + finerGrainedBuckets, + metric.WithUnit("s"), + )), + priceUpdateTotal: must(meter.Int64Counter( + "oracle_price_update", + metric.WithDescription("Number of oracle price updates by denom"), + metric.WithUnit("{count}"), + )), + } +) + +func must[V any](v V, err error) V { + if err != nil { + panic(err) + } + return v +}