diff --git a/docker-compose.yml b/docker-compose.yml index c8372325..e44c4b69 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,7 +5,7 @@ services: container_name: evmdnode0 image: "cosmos/evmd" entrypoint: ["/usr/bin/wrapper.sh"] - command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3"] + command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3", "--metrics", "--otel.enable", "--otel.endpoint", "host.docker.internal:4317", "--otel.insecure"] environment: - DEBUG=0 - ID=0 @@ -16,10 +16,12 @@ services: - seccomp:unconfined ports: - "26656-26657:26656-26657" + - "26660:26660" - "1317:1317" - "9090:9090" - "2345:2345" - "6065:6065" + - "8100:8100" - "8545-8546:8545-8546" volumes: - ./.testnets:/data:Z @@ -31,7 +33,7 @@ services: container_name: evmdnode1 image: "cosmos/evmd" entrypoint: ["/usr/bin/wrapper.sh"] - command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3"] + command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3", "--metrics", "--otel.enable", "--otel.endpoint", "host.docker.internal:4317", "--otel.insecure"] environment: - DEBUG=0 - ID=1 @@ -42,10 +44,12 @@ services: - seccomp:unconfined ports: - "26666-26667:26656-26657" + - "26661:26660" - "1318:1317" - "9091:9090" - "2346:2345" - "6075:6065" + - "8101:8100" - "8555-8556:8545-8546" volumes: - ./.testnets:/data:Z @@ -57,7 +61,7 @@ services: container_name: evmdnode2 image: "cosmos/evmd" entrypoint: ["/usr/bin/wrapper.sh"] - command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3"] + command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3", "--metrics", "--otel.enable", "--otel.endpoint", "host.docker.internal:4317", "--otel.insecure"] environment: - DEBUG=0 - ID=2 @@ -68,10 +72,12 @@ services: - seccomp:unconfined ports: - "26676-26677:26656-26657" + - "26662:26660" - "1319:1317" - "9092:9090" - "2347:2345" - "6085:6065" + - "8102:8100" - "8565-8566:8545-8546" volumes: - ./.testnets:/data:Z @@ -83,7 +89,7 @@ services: container_name: evmdnode3 image: "cosmos/evmd" entrypoint: ["/usr/bin/wrapper.sh"] - command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3"] + command: ["start", "--chain-id", "local-4221", "--json-rpc.api", "eth,txpool,personal,net,debug,web3", "--metrics", "--otel.enable", "--otel.endpoint", "host.docker.internal:4317", "--otel.insecure"] environment: - DEBUG=0 - ID=3 @@ -94,10 +100,12 @@ services: - seccomp:unconfined ports: - "26686-26687:26656-26657" + - "26663:26660" - "1320:1317" - "9093:9090" - "2348:2345" - "6095:6065" + - "8103:8100" - "8575-8576:8545-8546" volumes: - ./.testnets:/data:Z diff --git a/evmd/config/config.go b/evmd/config/config.go index 37161612..5d471b06 100644 --- a/evmd/config/config.go +++ b/evmd/config/config.go @@ -42,6 +42,7 @@ func InitAppConfig(denom string, evmChainID uint64) (string, interface{}) { EVM: *evmCfg, JSONRPC: *cosmosevmserverconfig.DefaultJSONRPCConfig(), TLS: *cosmosevmserverconfig.DefaultTLSConfig(), + OTel: *cosmosevmserverconfig.DefaultOTelConfig(), } return EVMAppTemplate, customAppConfig @@ -53,6 +54,7 @@ type EVMAppConfig struct { EVM cosmosevmserverconfig.EVMConfig JSONRPC cosmosevmserverconfig.JSONRPCConfig TLS cosmosevmserverconfig.TLSConfig + OTel cosmosevmserverconfig.OTelConfig } const EVMAppTemplate = serverconfig.DefaultConfigTemplate + cosmosevmserverconfig.DefaultEVMConfigTemplate diff --git a/go.mod b/go.mod index 114891fd..c0c1edc9 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,6 @@ require ( github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 github.com/grpc-ecosystem/grpc-gateway v1.16.0 - github.com/hashicorp/go-metrics v0.5.4 github.com/holiman/uint256 v1.3.2 github.com/improbable-eng/grpc-web v0.15.0 github.com/linxGnu/grocksdb v1.10.3 @@ -50,21 +49,26 @@ require ( github.com/xrplevm/node/v10 v10.0.3 github.com/zondax/hid v0.9.2 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 - go.opentelemetry.io/otel v1.39.0 - go.opentelemetry.io/otel/trace v1.39.0 + go.opentelemetry.io/otel v1.42.0 + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 + go.opentelemetry.io/otel/metric v1.42.0 + go.opentelemetry.io/otel/sdk v1.42.0 + go.opentelemetry.io/otel/sdk/metric v1.42.0 + go.opentelemetry.io/otel/trace v1.42.0 go.uber.org/mock v0.6.0 - golang.org/x/crypto v0.47.0 - golang.org/x/net v0.48.0 + golang.org/x/crypto v0.48.0 + golang.org/x/net v0.51.0 golang.org/x/sync v0.19.0 - golang.org/x/text v0.33.0 - google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 - google.golang.org/grpc v1.78.0 + golang.org/x/text v0.34.0 + google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 + google.golang.org/grpc v1.79.2 google.golang.org/protobuf v1.36.11 sigs.k8s.io/yaml v1.6.0 ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect cloud.google.com/go v0.123.0 // indirect cloud.google.com/go/auth v0.17.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect @@ -119,7 +123,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/cloudwego/base64x v0.1.6 // indirect - github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect + github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect github.com/cockroachdb/errors v1.12.0 // indirect github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect @@ -145,8 +149,8 @@ require ( github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/ebitengine/purego v0.9.1 // indirect github.com/emicklei/dot v1.8.0 // indirect - github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect - github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.36.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.3.0 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.0 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fatih/color v1.18.0 // indirect @@ -178,13 +182,14 @@ require ( github.com/googleapis/gax-go/v2 v2.15.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-getter v1.8.4 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect + github.com/hashicorp/go-metrics v0.5.4 // indirect github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-version v1.8.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect @@ -263,7 +268,7 @@ require ( github.com/zondax/ledger-go v1.0.1 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.39.0 // indirect go.opentelemetry.io/contrib/instrumentation/host v0.64.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect go.opentelemetry.io/contrib/instrumentation/runtime v0.64.0 // indirect @@ -272,20 +277,15 @@ require ( go.opentelemetry.io/contrib/propagators/jaeger v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.61.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.15.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.39.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 // indirect go.opentelemetry.io/otel/log v0.15.0 // indirect - go.opentelemetry.io/otel/metric v1.39.0 // indirect - go.opentelemetry.io/otel/sdk v1.39.0 // indirect go.opentelemetry.io/otel/sdk/log v0.15.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -294,14 +294,14 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.21.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect - golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sys v0.40.0 // indirect - golang.org/x/term v0.39.0 // indirect + golang.org/x/oauth2 v0.35.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.40.0 // indirect + golang.org/x/tools v0.41.0 // indirect google.golang.org/api v0.256.0 // indirect google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect diff --git a/go.sum b/go.sum index 3b72ff3f..795133dd 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= @@ -231,8 +231,8 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= -github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= +github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/cockroachdb/apd/v2 v2.0.2 h1:weh8u7Cneje73dDh+2tEVLUvyBc89iwepWCD8b8034E= github.com/cockroachdb/apd/v2 v2.0.2/go.mod h1:DDxRlzC2lo3/vSlmSoS7JkqbbrARPuFOGr0B9pvN3Gw= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= @@ -359,15 +359,15 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= -github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329/go.mod h1:Alz8LEClvR7xKsrq3qzoc4N0guvVNSS8KmSChGYr9hs= -github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= -github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= +github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= -github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= +github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= +github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= github.com/ethereum/c-kzg-4844/v2 v2.1.0 h1:gQropX9YFBhl3g4HYhwE70zq3IHFRgbbNPw0Shwzf5w= github.com/ethereum/c-kzg-4844/v2 v2.1.0/go.mod h1:TC48kOKjJKPbN7C++qIgt0TJzZ70QznYR7Ob+WXl57E= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= @@ -545,8 +545,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.70 h1:0HADrxxqaQkGycO1JoUUA+B4FnIkuo8d2bz/hSaTFFQ= @@ -1024,8 +1024,8 @@ go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= -go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0 h1:kWRNZMsfBHZ+uHjiH4y7Etn2FK26LAGkNFw7RHv1DhE= +go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0 h1:RN3ifU8y4prNWeEnQp2kRRHz8UwonAEYZl8tUzHEXAk= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.64.0/go.mod h1:habDz3tEWiFANTo6oUE99EmaFUrCNYAAg3wiVmusm70= go.opentelemetry.io/contrib/instrumentation/host v0.64.0 h1:/o7fG3CXOlVK8fUzK+p8CyHU9Opha3IL4DZR3UXGZ1w= @@ -1040,8 +1040,8 @@ go.opentelemetry.io/contrib/propagators/b3 v1.39.0 h1:PI7pt9pkSnimWcp5sQhUA9OzLb go.opentelemetry.io/contrib/propagators/b3 v1.39.0/go.mod h1:5gV/EzPnfYIwjzj+6y8tbGW2PKWhcsz5e/7twptRVQY= go.opentelemetry.io/contrib/propagators/jaeger v1.39.0 h1:Gz3yKzfMSEFzF0Vy5eIpu9ndpo4DhXMCxsLMF0OOApo= go.opentelemetry.io/contrib/propagators/jaeger v1.39.0/go.mod h1:2D/cxxCqTlrday0rZrPujjg5aoAdqk1NaNyoXn8FJn8= -go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= -go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0/go.mod h1:JM31r0GGZ/GU94mX8hN4D8v6e40aFlUECSQ48HaLgHM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.15.0 h1:EKpiGphOYq3CYnIe2eX9ftUkyU+Y8Dtte8OaWyHJ4+I= @@ -1050,10 +1050,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 h1:cEf go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0/go.mod h1:k1lzV5n5U3HkGvTCJHraTAGJ7MqsgL1wrGwTj1Isfiw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0 h1:nKP4Z2ejtHn3yShBb+2KawiXgpn8In5cT7aO2wXuOTE= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.39.0/go.mod h1:NwjeBbNigsO4Aj9WgM0C+cKIrxsZUaRmZUO7A8I7u8o= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye2FpXkYgiHX7fyVrN1uA/UYd9ounqqTuSNAv0k4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= go.opentelemetry.io/otel/exporters/prometheus v0.61.0 h1:cCyZS4dr67d30uDyh8etKM2QyDsQ4zC9ds3bdbrVoD0= @@ -1066,18 +1066,18 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0 h1:8UPA4IbVZxpsD76 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.39.0/go.mod h1:MZ1T/+51uIVKlRzGw1Fo46KEWThjlCBZKl2LzY5nv4g= go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= go.opentelemetry.io/otel/sdk/log/logtest v0.15.0 h1:O+dZyt9riqVDKZwFRFn9zVdUKam3uwLMud+poHRssd4= go.opentelemetry.io/otel/sdk/log/logtest v0.15.0/go.mod h1:j7aD3tWSt3KlzWz5G+9loktEng6udEY868Kc2XDzdII= -go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= -go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= @@ -1125,8 +1125,8 @@ golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= -golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= @@ -1181,13 +1181,13 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= -golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= +golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1264,8 +1264,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -1273,8 +1273,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= -golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1286,8 +1286,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= @@ -1313,8 +1313,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1340,10 +1340,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 h1:LvZVVaPE0JSqL+ZWb6ErZfnEOKIqqFWUJE2D0fObSmc= google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9/go.mod h1:QFOrLhdAe2PsTp3vQY4quuLKTi9j3XG3r6JPPaw7MSc= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls= -google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= +google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1361,8 +1361,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= +google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/local_node.sh b/local_node.sh index 1f4d4c32..1ae247e2 100755 --- a/local_node.sh +++ b/local_node.sh @@ -338,6 +338,11 @@ jq '.app_state["evm"]["params"]["active_static_precompiles"]=["0x000000000000000 fi # Start the node +OTEL_ARGS="" +if [[ "${OTEL_ENABLE:-false}" == "true" ]]; then + OTEL_ARGS="--otel.enable --otel.endpoint ${OTEL_ENDPOINT:-localhost:4317} --otel.insecure" +fi + evmd start "$TRACE" \ --pruning nothing \ --log_level $LOGLEVEL \ @@ -345,4 +350,5 @@ evmd start "$TRACE" \ --evm.min-tip=0 \ --home "$CHAINDIR" \ --json-rpc.api eth,txpool,personal,net,debug,web3 \ - --chain-id "$CHAINID" + --chain-id "$CHAINID" \ + $OTEL_ARGS diff --git a/monitoring/README.md b/monitoring/README.md new file mode 100644 index 00000000..8e57ac4c --- /dev/null +++ b/monitoring/README.md @@ -0,0 +1,214 @@ +# og-evm Observability + +Production-grade monitoring and tracing for og-evm validator and full nodes using Prometheus, Grafana, Tempo, and Loki. + +## Architecture + +``` +og-evm node(s) + ├── :26660/metrics ──→ Prometheus (scrape) ──→ Grafana dashboards + alerts + ├── :8100/metrics ──→ Prometheus (scrape) ──→ Grafana dashboards + alerts + └── OTel SDK ──→ :4317 OTel Collector ──┬→ Tempo (traces) + └→ Prometheus (span-derived metrics via remote write) +``` + +Three pillars of observability: +- **Metrics** — Prometheus scrapes CometBFT consensus and geth EVM metrics every 15s +- **Traces** — OpenTelemetry SDK exports spans (EthereumTx, BeginBlock, etc.) via OTLP gRPC to Tempo +- **Logs** — Promtail ships node logs to Loki + +## Prerequisites + +- Docker and Docker Compose +- A running `evmd` node (built with OTel support) + +## Deployment + +### 1. Start the monitoring stack + +```bash +cd monitoring +docker compose up -d +``` + +### 2. Configure your node + +Enable the following in your node's `config.toml`: + +```toml +[instrumentation] +prometheus = true +prometheus_listen_addr = ":26660" +``` + +Enable OpenTelemetry in `app.toml`: + +```toml +[otel] +enable = true +endpoint = ":4317" +insecure = true +``` + +Or pass as CLI flags when starting the node: + +```bash +evmd start \ + --otel.enable \ + --otel.endpoint :4317 \ + --otel.insecure \ + --otel.chain-id \ + --metrics +``` + +### 3. Register your node as a Prometheus target + +Add your node to `prometheus/targets/og-evm-nodes.json`: + +```json +[ + { + "targets": [":26660"], + "labels": { + "chain_id": "og-evm-mainnet", + "instance": "validator-0" + } + } +] +``` + +Prometheus reloads target files every 30s — no restart needed. Add additional nodes as separate entries. + +### 4. Access Grafana + +Open `http://:3000` (default credentials: `admin` / `admin`). + +Change the admin password on first login for production deployments. + +## Services + +| Service | Port | Purpose | +|---------|------|---------| +| Prometheus | 9099 | Metrics storage, alerting, and PromQL queries | +| Grafana | 3000 | Dashboards, trace exploration, and alert management | +| OTel Collector | 4317 (gRPC) / 4318 (HTTP) | Receives OTLP traces and metrics from nodes | +| Tempo | 3200 | Distributed trace storage with span metrics generation | +| Loki | 3100 | Log aggregation and querying | +| Promtail | — | Ships node logs to Loki | + +## Metrics Collected + +### CometBFT (port 26660) + +Consensus, P2P, mempool, and block production metrics. Key metrics: + +| Metric | Description | +|--------|-------------| +| `cometbft_consensus_height` | Current block height | +| `cometbft_consensus_validators` | Active / missing / byzantine validator counts | +| `cometbft_consensus_block_interval_seconds` | Time between blocks (histogram) | +| `cometbft_consensus_rounds` | Consensus rounds per height | +| `cometbft_p2p_peers` | Connected peer count | +| `cometbft_consensus_total_txs` | Cumulative transaction count | + +### Geth / EVM (port 8100) + +Go-Ethereum internals — state reads, cache hits, and EVM execution metrics. + +### OTel span-derived metrics (via Tempo metrics generator) + +Tempo automatically generates RED (Rate, Error, Duration) metrics from ingested traces: + +| Metric | Description | +|--------|-------------| +| `traces_spanmetrics_calls_total` | Request rate per span name | +| `traces_spanmetrics_latency_bucket` | Latency histogram per span name | +| `traces_service_graph_*` | Service-to-service dependency metrics | + +## OTel Configuration Reference + +| Flag | `app.toml` key | Default | Description | +|------|----------------|---------|-------------| +| `--otel.enable` | `otel.enable` | `false` | Enable trace and metric export | +| `--otel.endpoint` | `otel.endpoint` | `localhost:4317` | OTLP gRPC collector endpoint | +| `--otel.insecure` | `otel.insecure` | `true` | Use non-TLS gRPC connection | +| `--otel.sample-rate` | `otel.sample-rate` | `1.0` | Trace sampling rate (0.0 = none, 1.0 = all) | +| `--otel.chain-id` | `otel.chain-id` | `""` | Chain ID attached as resource attribute on all telemetry | + +### Sampling + +For high-throughput chains, reduce `sample-rate` to control trace volume. A rate of `0.1` samples 10% of traces. Metrics are always exported regardless of sampling rate. + +## Grafana Views + +| View | Location | Datasource | +|------|----------|------------| +| Chain overview | Dashboards → Cosmos Dashboard | Prometheus | +| Trace waterfalls | Explore → Tempo | Tempo | +| Ad-hoc metric queries | Explore → Prometheus | Prometheus | +| Log search | Explore → Loki | Loki | + +Dashboard variables: +- **Chain ID** — filters all panels to a specific chain +- **Instance** — filters to a specific validator/node + +## Alerting + +Create alert rules in Grafana under Alerting → Alert rules using Prometheus as the datasource. + +Recommended alerts: + +| Alert | PromQL | Severity | +|-------|--------|----------| +| Chain halted | `increase(cometbft_consensus_height[5m]) == 0` | Critical | +| Peer count low | `cometbft_p2p_peers < 3` | Warning | +| Missed blocks | `cometbft_consensus_missing_validators > 0` | Warning | +| High consensus rounds | `cometbft_consensus_rounds > 2` | Warning | +| Slow block time | `rate(cometbft_consensus_block_interval_seconds_sum[5m]) / rate(cometbft_consensus_block_interval_seconds_count[5m]) > 10` | Warning | + +Configure notification channels (Slack, PagerDuty, email) under Alerting → Contact points. + +## Retention + +| Store | Default | Configuration | +|-------|---------|---------------| +| Prometheus (metrics) | 30 days | `--storage.tsdb.retention.time` in `docker-compose.yml` | +| Tempo (traces) | 14 days | `compactor.compaction.block_retention` in `tempo/config.yml` | +| Loki (logs) | Per Loki defaults | `limits_config.retention_period` in `loki/config.yml` | + +## Production Considerations + +- **Change Grafana admin password** on first login +- **Use TLS** for the OTel endpoint (`otel.insecure = false`) when the collector is on a different host +- **Tune sampling rate** — `1.0` exports every trace; lower this on high-throughput chains +- **Persistent volumes** — the `docker-compose.yml` uses named Docker volumes; back these up or mount to host paths for durability +- **Resource limits** — consider setting memory/CPU limits on Tempo and Prometheus for production workloads +- **Network security** — restrict access to Grafana (3000), Prometheus (9099), and Tempo (3200) ports + +--- + +## Local Development / Testnet + +For local testing, convenience scripts are provided: + +```bash +# Single-node local devnet with OTel +OTEL_ENABLE=true ./local_node.sh -y --no-install + +# 4-node Docker testnet +make localnet-start +# Then enable metrics: +for i in 0 1 2 3; do + sed -i.bak 's/prometheus = false/prometheus = true/' .testnets/node${i}/evmd/config/config.toml +done +docker compose restart +``` + +Local testnet port mapping: + +| Node | CometBFT metrics | Geth metrics | JSON-RPC | P2P | +|------|------------------|-------------|----------|-----| +| node0 | 26660 | 8100 | 8545 | 26656 | +| node1 | 26661 | 8101 | 8555 | 26666 | +| node2 | 26662 | 8102 | 8565 | 26676 | +| node3 | 26663 | 8103 | 8575 | 26686 | diff --git a/monitoring/docker-compose.yml b/monitoring/docker-compose.yml new file mode 100644 index 00000000..3de06d83 --- /dev/null +++ b/monitoring/docker-compose.yml @@ -0,0 +1,89 @@ +version: "3.8" + +services: + prometheus: + image: prom/prometheus:latest + container_name: og-evm-prometheus + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - ./prometheus/targets:/etc/prometheus/targets:ro + - prometheus_data:/prometheus + command: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.retention.time=30d" + - "--web.enable-lifecycle" + - "--web.enable-remote-write-receiver" + ports: + - "9099:9090" + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + + grafana: + image: grafana/grafana:latest + container_name: og-evm-grafana + volumes: + - grafana_data:/var/lib/grafana + - ./grafana/provisioning:/etc/grafana/provisioning:ro + environment: + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=admin + - GF_USERS_ALLOW_SIGN_UP=false + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer + ports: + - "3000:3000" + depends_on: + - prometheus + restart: unless-stopped + + otel-collector: + image: otel/opentelemetry-collector-contrib:latest + container_name: og-evm-otel-collector + volumes: + - ./otel-collector/config.yml:/etc/otelcol-contrib/config.yaml:ro + ports: + - "4317:4317" # OTLP gRPC + - "4318:4318" # OTLP HTTP + depends_on: + - tempo + restart: unless-stopped + + tempo: + image: grafana/tempo:2.6.1 + container_name: og-evm-tempo + volumes: + - ./tempo/config.yml:/etc/tempo/config.yaml:ro + - tempo_data:/var/tempo + command: ["-config.file=/etc/tempo/config.yaml"] + ports: + - "3200:3200" # Tempo query frontend + restart: unless-stopped + + loki: + image: grafana/loki:latest + container_name: og-evm-loki + volumes: + - ./loki/config.yml:/etc/loki/local-config.yaml:ro + - loki_data:/loki + command: ["-config.file=/etc/loki/local-config.yaml"] + ports: + - "3100:3100" + restart: unless-stopped + + promtail: + image: grafana/promtail:latest + container_name: og-evm-promtail + volumes: + - ./promtail/config.yml:/etc/promtail/config.yaml:ro + - /var/log:/var/log:ro + command: ["-config.file=/etc/promtail/config.yaml"] + depends_on: + - loki + restart: unless-stopped + +volumes: + prometheus_data: + grafana_data: + tempo_data: + loki_data: diff --git a/monitoring/grafana/provisioning/dashboards/cometbft.json b/monitoring/grafana/provisioning/dashboards/cometbft.json new file mode 100644 index 00000000..c40c37ab --- /dev/null +++ b/monitoring/grafana/provisioning/dashboards/cometbft.json @@ -0,0 +1,1451 @@ +{ + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "prometheus", + "description": "", + "type": "datasource", + "pluginId": "prometheus", + "pluginName": "Prometheus" + } + ], + "__requires": [ + { + "type": "panel", + "id": "gauge", + "name": "Gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "6.4.3" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "prometheus", + "name": "Prometheus", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "singlestat", + "name": "Singlestat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "A Grafana dashboard compatible with all the cosmos-sdk and tendermint based blockchains.", + "editable": true, + "gnetId": 11036, + "graphTooltip": 0, + "id": null, + "iteration": 1571905700769, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 64, + "panels": [], + "title": "$chain_id overview", + "type": "row" + }, + { + "content": "", + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 62, + "links": [], + "mode": "html", + "options": {}, + "title": "", + "transparent": true, + "type": "text" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#FF780A", + "#FF780A", + "#FF780A" + ], + "datasource": "$DS", + "decimals": 0, + "description": "", + "format": "locale", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 3 + }, + "hideTimeOverride": false, + "id": 4, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "100%", + "prefix": "", + "prefixFontSize": "100%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgb(45, 41, 32)", + "full": false, + "lineColor": "#ef843c", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "cometbft_consensus_height{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "hide": false, + "instant": true, + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Block Height", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorValue": true, + "colors": [ + "#FF780A", + "#FF780A", + "#FF780A" + ], + "datasource": "$DS", + "decimals": 0, + "description": "", + "format": "locale", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 3 + }, + "hideTimeOverride": false, + "id": 40, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "80%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgb(45, 41, 32)", + "full": false, + "lineColor": "#ef843c", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "cometbft_consensus_total_txs{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Total Transactions", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorPostfix": false, + "colorValue": true, + "colors": [ + "#FF780A", + "#FF780A", + "#FF780A" + ], + "datasource": "$DS", + "decimals": 2, + "description": "", + "format": "s", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 3 + }, + "hideTimeOverride": true, + "id": 39, + "interval": null, + "links": [], + "mappingType": 2, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "120%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgb(45, 41, 32)", + "full": false, + "lineColor": "#FF780A", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "rate(cometbft_consensus_block_interval_seconds_sum{chain_id=\"$chain_id\", instance=\"$instance\"}[5m]) / rate(cometbft_consensus_block_interval_seconds_count{chain_id=\"$chain_id\", instance=\"$instance\"}[5m])", + "format": "time_series", + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": "1h", + "timeShift": null, + "title": "Avg Block Time", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [], + "valueName": "avg" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorPostfix": false, + "colorValue": true, + "colors": [ + "#FF780A", + "#FF780A", + "#FF780A" + ], + "datasource": "$DS", + "decimals": 0, + "description": "", + "format": "short", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 3 + }, + "hideTimeOverride": false, + "id": 47, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "80%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgb(45, 41, 32)", + "full": false, + "lineColor": "#FF780A", + "show": true + }, + "tableColumn": "", + "targets": [ + { + "expr": "cometbft_consensus_validators_power{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "instant": false, + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Bonded Tokens", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [], + "valueName": "current" + }, + { + "aliasColors": { + "Height for last 3 hours": "#447ebc", + "Total Transactions for last 3 hours": "#ef843c" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS", + "decimals": 0, + "fill": 3, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 7 + }, + "hideTimeOverride": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sideWidth": 350, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cometbft_consensus_validators{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Active", + "refId": "A" + }, + { + "expr": "cometbft_consensus_missing_validators{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Missing", + "refId": "B" + }, + { + "expr": "cometbft_consensus_byzantine_validators{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Byzantine", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Validators", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "locale", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Height for last 3 hours": "#447ebc", + "Total Transactions for last 3 hours": "#ef843c" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS", + "fill": 3, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 7 + }, + "hideTimeOverride": false, + "id": 48, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "sideWidth": 350, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cometbft_consensus_validators_power{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Online", + "refId": "A" + }, + { + "expr": "cometbft_consensus_missing_validators_power{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "Missing", + "refId": "B" + }, + { + "expr": "cometbft_consensus_byzantine_validators_power{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "Byzantine", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Voting Power", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Height for last 3 hours": "#447ebc", + "Total Transactions for last 3 hours": "#ef843c" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS", + "fill": 3, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 0, + "y": 16 + }, + "hideTimeOverride": false, + "id": 49, + "legend": { + "alignAsTable": false, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cometbft_consensus_block_size_bytes{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Block Size", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Block Size", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 2, + "format": "bytes", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": { + "Height for last 3 hours": "#447ebc", + "Total Transactions for last 3 hours": "#ef843c" + }, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "$DS", + "decimals": 0, + "fill": 3, + "fillGradient": 0, + "gridPos": { + "h": 5, + "w": 12, + "x": 12, + "y": 16 + }, + "hideTimeOverride": false, + "id": 50, + "legend": { + "alignAsTable": false, + "avg": true, + "current": false, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cometbft_consensus_num_txs{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "instant": false, + "interval": "", + "intervalFactor": 1, + "legendFormat": "Transactions", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Transactions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": "${DS_PROMETHEUS}", + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 55, + "panels": [], + "repeat": "instance", + "title": "instance overview: $instance", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": "$DS", + "description": "", + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 22 + }, + "hideTimeOverride": true, + "id": 53, + "links": [], + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "decimals": 0, + "mappings": [], + "max": 20, + "min": 0, + "nullValueMode": "connected", + "thresholds": [ + { + "color": "#e24d42", + "value": null + }, + { + "color": "#ef843c", + "value": 2 + }, + { + "color": "#7eb26d", + "value": 5 + } + ], + "unit": "short" + }, + "override": {}, + "values": false + }, + "orientation": "horizontal", + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "6.4.3", + "targets": [ + { + "expr": "cometbft_p2p_peers{chain_id=\"$chain_id\", instance=~\"$instance\"}", + "format": "time_series", + "instant": true, + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Connected Peers", + "type": "gauge" + }, + { + "cacheTimeout": null, + "datasource": "$DS", + "description": "", + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 22 + }, + "hideTimeOverride": true, + "id": 56, + "links": [], + "options": { + "fieldOptions": { + "calcs": [ + "last" + ], + "defaults": { + "decimals": 0, + "mappings": [], + "max": 50, + "min": null, + "nullValueMode": "connected", + "thresholds": [ + { + "color": "#7eb26d", + "value": null + }, + { + "color": "#ef843c", + "value": 10 + }, + { + "color": "#e24d42", + "value": 20 + } + ], + "unit": "short" + }, + "override": {}, + "values": false + }, + "orientation": "horizontal", + "showThresholdLabels": false, + "showThresholdMarkers": true + }, + "pluginVersion": "6.4.3", + "targets": [ + { + "expr": "cometbft_mempool_size{chain_id=\"$chain_id\", instance=~\"$instance\"}", + "format": "time_series", + "instant": true, + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Unconfirmed Transactions", + "type": "gauge" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorPostfix": false, + "colorValue": true, + "colors": [ + "#FF780A", + "#FF780A", + "#FF780A" + ], + "datasource": "$DS", + "decimals": 0, + "description": "", + "format": "short", + "gauge": { + "maxValue": null, + "minValue": null, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 22 + }, + "hideTimeOverride": true, + "id": 60, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "80%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [], + "sparkline": { + "fillColor": "rgb(45, 41, 32)", + "full": false, + "lineColor": "#ef843c", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "cometbft_mempool_failed_txs{chain_id=\"$chain_id\", instance=~\"$instance\"}", + "format": "time_series", + "instant": true, + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Failed Transactions", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [], + "valueName": "current" + }, + { + "cacheTimeout": null, + "colorBackground": false, + "colorPostfix": false, + "colorValue": true, + "colors": [ + "#FF780A", + "#FF780A", + "#FF780A" + ], + "datasource": "$DS", + "decimals": 0, + "description": "", + "format": "locale", + "gauge": { + "maxValue": null, + "minValue": null, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 22 + }, + "hideTimeOverride": true, + "id": 61, + "interval": null, + "links": [], + "mappingType": 1, + "mappingTypes": [ + { + "name": "value to text", + "value": 1 + }, + { + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "options": {}, + "postfix": "", + "postfixFontSize": "80%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgb(45, 41, 32)", + "full": false, + "lineColor": "#ef843c", + "show": false + }, + "tableColumn": "", + "targets": [ + { + "expr": "cometbft_mempool_recheck_times{chain_id=\"$chain_id\", instance=~\"$instance\"}", + "format": "time_series", + "instant": true, + "interval": "30s", + "intervalFactor": 1, + "refId": "A" + } + ], + "thresholds": "", + "timeFrom": null, + "timeShift": null, + "title": "Recheck Times", + "type": "singlestat", + "valueFontSize": "120%", + "valueMaps": [], + "valueName": "current" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$DS", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 59, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pluginVersion": "6.4.3", + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cometbft_p2p_peer_receive_bytes_total{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer_id}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total Network Input", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "$DS", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 58, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "cometbft_p2p_peer_send_bytes_total{chain_id=\"$chain_id\", instance=\"$instance\"}", + "format": "time_series", + "intervalFactor": 1, + "legendFormat": "{{peer_id}}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Total Network Output", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": false, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": false, + "schemaVersion": 20, + "style": "dark", + "tags": [ + "Blockchain", + "Cosmos" + ], + "templating": { + "list": [ + { + "current": { + "selected": true, + "tags": [], + "text": "prometheus", + "value": "prometheus" + }, + "hide": 0, + "includeAll": false, + "label": "Datasource", + "multi": false, + "name": "DS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "type": "datasource" + }, + { + "allValue": null, + "current": {}, + "datasource": "$DS", + "definition": "label_values(cometbft_consensus_height, chain_id)", + "hide": 0, + "includeAll": false, + "label": "Chain ID", + "multi": false, + "name": "chain_id", + "options": [], + "query": "label_values(cometbft_consensus_height, chain_id)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": "", + "current": {}, + "datasource": "$DS", + "definition": "label_values(cometbft_consensus_height{chain_id=\"$chain_id\"}, instance)", + "hide": 0, + "includeAll": false, + "label": "Instance", + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(cometbft_consensus_height{chain_id=\"$chain_id\"}, instance)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now/d", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "Cosmos Dashboard", + "uid": "UJyurCTWz", + "version": 9 +} \ No newline at end of file diff --git a/monitoring/grafana/provisioning/dashboards/dashboards.yml b/monitoring/grafana/provisioning/dashboards/dashboards.yml new file mode 100644 index 00000000..1162d39c --- /dev/null +++ b/monitoring/grafana/provisioning/dashboards/dashboards.yml @@ -0,0 +1,12 @@ +apiVersion: 1 + +providers: + - name: default + orgId: 1 + folder: "" + type: file + disableDeletion: false + updateIntervalSeconds: 30 + options: + path: /etc/grafana/provisioning/dashboards + foldersFromFilesStructure: false diff --git a/monitoring/grafana/provisioning/datasources/datasources.yml b/monitoring/grafana/provisioning/datasources/datasources.yml new file mode 100644 index 00000000..20437ac6 --- /dev/null +++ b/monitoring/grafana/provisioning/datasources/datasources.yml @@ -0,0 +1,26 @@ +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + editable: true + + - name: Tempo + type: tempo + access: proxy + url: http://tempo:3200 + editable: true + jsonData: + tracesToMetrics: + datasourceUid: prometheus + nodeGraph: + enabled: true + + - name: Loki + type: loki + access: proxy + url: http://loki:3100 + editable: true diff --git a/monitoring/loki/config.yml b/monitoring/loki/config.yml new file mode 100644 index 00000000..12cd2283 --- /dev/null +++ b/monitoring/loki/config.yml @@ -0,0 +1,25 @@ +auth_enabled: false + +server: + http_listen_port: 3100 + +common: + path_prefix: /loki + storage: + filesystem: + chunks_directory: /loki/chunks + rules_directory: /loki/rules + replication_factor: 1 + ring: + kvstore: + store: inmemory + +schema_config: + configs: + - from: 2020-10-24 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h diff --git a/monitoring/otel-collector/config.yml b/monitoring/otel-collector/config.yml new file mode 100644 index 00000000..3b52f240 --- /dev/null +++ b/monitoring/otel-collector/config.yml @@ -0,0 +1,32 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + http: + endpoint: 0.0.0.0:4318 + +processors: + batch: + timeout: 5s + send_batch_size: 1024 + +exporters: + otlp/tempo: + endpoint: tempo:4317 + tls: + insecure: true + + prometheusremotewrite: + endpoint: "http://prometheus:9090/api/v1/write" + +service: + pipelines: + traces: + receivers: [otlp] + processors: [batch] + exporters: [otlp/tempo] + metrics: + receivers: [otlp] + processors: [batch] + exporters: [prometheusremotewrite] diff --git a/monitoring/prometheus/prometheus.yml b/monitoring/prometheus/prometheus.yml new file mode 100644 index 00000000..768e6528 --- /dev/null +++ b/monitoring/prometheus/prometheus.yml @@ -0,0 +1,32 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: "prometheus" + static_configs: + - targets: ["localhost:9090"] + + - job_name: "cometbft" + metrics_path: /metrics + file_sd_configs: + - files: + - /etc/prometheus/targets/og-evm-nodes.json + refresh_interval: 30s + relabel_configs: + - source_labels: [__address__] + regex: "(.+):.*" + target_label: __address__ + replacement: "${1}:26660" + + - job_name: "geth-metrics" + metrics_path: /metrics + file_sd_configs: + - files: + - /etc/prometheus/targets/og-evm-nodes.json + refresh_interval: 30s + relabel_configs: + - source_labels: [__address__] + regex: "(.+):.*" + target_label: __address__ + replacement: "${1}:8100" diff --git a/monitoring/prometheus/targets/og-evm-nodes.json b/monitoring/prometheus/targets/og-evm-nodes.json new file mode 100644 index 00000000..cfa334a3 --- /dev/null +++ b/monitoring/prometheus/targets/og-evm-nodes.json @@ -0,0 +1,30 @@ +[ + { + "targets": ["host.docker.internal:26660"], + "labels": { + "chain_id": "og-evm", + "instance": "validator-0" + } + }, + { + "targets": ["host.docker.internal:26661"], + "labels": { + "chain_id": "og-evm", + "instance": "validator-1" + } + }, + { + "targets": ["host.docker.internal:26662"], + "labels": { + "chain_id": "og-evm", + "instance": "validator-2" + } + }, + { + "targets": ["host.docker.internal:26663"], + "labels": { + "chain_id": "og-evm", + "instance": "validator-3" + } + } +] diff --git a/monitoring/promtail/config.yml b/monitoring/promtail/config.yml new file mode 100644 index 00000000..1e7e2300 --- /dev/null +++ b/monitoring/promtail/config.yml @@ -0,0 +1,26 @@ +server: + http_listen_port: 9080 + +positions: + filename: /tmp/positions.yaml + +clients: + - url: http://loki:3100/loki/api/v1/push + +scrape_configs: + - job_name: og-evm + static_configs: + - targets: + - localhost + labels: + job: og-evm + __path__: /var/log/og-evm*.log + pipeline_stages: + - json: + expressions: + level: level + module: module + msg: msg + - labels: + level: + module: diff --git a/monitoring/tempo/config.yml b/monitoring/tempo/config.yml new file mode 100644 index 00000000..3ae90a0b --- /dev/null +++ b/monitoring/tempo/config.yml @@ -0,0 +1,41 @@ +server: + http_listen_port: 3200 + +distributor: + receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 + +storage: + trace: + backend: local + local: + path: /var/tempo/traces + wal: + path: /var/tempo/wal + +metrics_generator: + storage: + path: /var/tempo/generator/wal + remote_write: + - url: http://prometheus:9090/api/v1/write + send_exemplars: true + registry: + external_labels: + source: tempo + processor: + service_graphs: + wait: 10s + max_items: 10000 + span_metrics: {} + local_blocks: + flush_to_storage: true + traces_storage: + path: /var/tempo/generator/traces + +overrides: + defaults: + metrics_generator: + processors: [service-graphs, span-metrics, local-blocks] diff --git a/multi_node_startup.sh b/multi_node_startup.sh index 211c84c4..26209d96 100755 --- a/multi_node_startup.sh +++ b/multi_node_startup.sh @@ -11,6 +11,7 @@ BASEDIR="${BASEDIR:-"$HOME/.og-evm-devnet"}" NODE_NUMBER="${NODE_NUMBER:-}" START_VALIDATOR="${START_VALIDATOR:-false}" GENERATE_GENESIS="${GENERATE_GENESIS:-false}" +OTEL_ENABLE="${OTEL_ENABLE:-false}" VAL0_MNEMONIC="" VAL1_MNEMONIC="" @@ -42,6 +43,8 @@ usage() { echo " GENERATE_GENESIS=true Generate genesis for all 3 validators" echo " START_VALIDATOR=true Start a validator" echo " NODE_NUMBER=0|1|2 Which validator to start" + echo " OTEL_ENABLE=true Enable OpenTelemetry tracing" + echo " OTEL_ENDPOINT=host:port OTel collector endpoint (default: localhost:4317)" echo " BASEDIR=path Base directory (default: ~/.og-evm-devnet)" echo "" echo "Options:" @@ -222,9 +225,13 @@ generate_genesis() { evmd config set client chain-id "$CHAINID" --home "$HOME_DIR" evmd config set client keyring-backend "$KEYRING" --home "$HOME_DIR" - echo "$MNEMONIC" | evmd keys add "$VALKEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOME_DIR" - - echo "$MNEMONIC" | evmd init "${MONIKER}-val${i}" -o --chain-id "$CHAINID" --home "$HOME_DIR" --recover + if [[ -n "$MNEMONIC" ]]; then + echo "$MNEMONIC" | evmd keys add "$VALKEY" --recover --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOME_DIR" + echo "$MNEMONIC" | evmd init "${MONIKER}-val${i}" -o --chain-id "$CHAINID" --home "$HOME_DIR" --recover + else + evmd keys add "$VALKEY" --keyring-backend "$KEYRING" --algo "$KEYALGO" --home "$HOME_DIR" + evmd init "${MONIKER}-val${i}" -o --chain-id "$CHAINID" --home "$HOME_DIR" + fi NODE_ID=$(evmd comet show-node-id --home "$HOME_DIR") NODE_IDS+=("$NODE_ID") @@ -371,8 +378,17 @@ start_validator() { --home "$HOME_DIR" --json-rpc.api eth,txpool,personal,net,debug,web3 --chain-id "$CHAINID" + --metrics ) + if [[ "$OTEL_ENABLE" == "true" ]]; then + START_ARGS+=( + --otel.enable + --otel.endpoint "${OTEL_ENDPOINT:-localhost:4317}" + --otel.insecure + ) + fi + exec evmd start "${START_ARGS[@]}" } diff --git a/server/config/config.go b/server/config/config.go index 186ee91a..3a471882 100644 --- a/server/config/config.go +++ b/server/config/config.go @@ -134,6 +134,7 @@ type Config struct { EVM EVMConfig `mapstructure:"evm"` JSONRPC JSONRPCConfig `mapstructure:"json-rpc"` TLS TLSConfig `mapstructure:"tls"` + OTel OTelConfig `mapstructure:"otel"` } // EVMConfig defines the application configuration values for the EVM. @@ -402,6 +403,42 @@ func (c JSONRPCConfig) Validate() error { return nil } +// OTelConfig defines the OpenTelemetry configuration for exporting traces and metrics. +type OTelConfig struct { + // Enable defines if the OpenTelemetry exporter should be enabled. + Enable bool `mapstructure:"enable"` + // Endpoint defines the OTLP gRPC endpoint to export traces to (e.g., "localhost:4317"). + Endpoint string `mapstructure:"endpoint"` + // Insecure defines if the OTLP exporter should use an insecure (non-TLS) connection. + Insecure bool `mapstructure:"insecure"` + // SampleRate controls the fraction of traces sampled (0.0 to 1.0). + SampleRate float64 `mapstructure:"sample-rate"` + // ChainID identifies this chain in traces. Attached as chain_id resource attribute. + ChainID string `mapstructure:"chain-id"` +} + +// DefaultOTelConfig returns the default OpenTelemetry configuration (disabled). +func DefaultOTelConfig() *OTelConfig { + return &OTelConfig{ + Enable: false, + Endpoint: "localhost:4317", + Insecure: true, + SampleRate: 0.1, + ChainID: "", + } +} + +// Validate returns an error if the OTel configuration is invalid. +func (c OTelConfig) Validate() error { + if c.Enable && c.Endpoint == "" { + return errors.New("OTel endpoint must be set when OTel is enabled") + } + if c.SampleRate < 0 || c.SampleRate > 1 { + return fmt.Errorf("OTel sample-rate must be between 0.0 and 1.0, got %f", c.SampleRate) + } + return nil +} + // DefaultTLSConfig returns the default TLS configuration func DefaultTLSConfig() *TLSConfig { return &TLSConfig{ @@ -440,6 +477,7 @@ func DefaultConfig() *Config { EVM: *DefaultEVMConfig(), JSONRPC: *DefaultJSONRPCConfig(), TLS: *DefaultTLSConfig(), + OTel: *DefaultOTelConfig(), } } @@ -471,5 +509,9 @@ func (c Config) ValidateBasic() error { return errorsmod.Wrapf(errortypes.ErrAppConfig, "invalid tls config value: %s", err.Error()) } + if err := c.OTel.Validate(); err != nil { + return errorsmod.Wrapf(errortypes.ErrAppConfig, "invalid otel config value: %s", err.Error()) + } + return c.Config.ValidateBasic() } diff --git a/server/config/toml.go b/server/config/toml.go index 60bd3402..ba1e4326 100644 --- a/server/config/toml.go +++ b/server/config/toml.go @@ -140,4 +140,26 @@ certificate-path = "{{ .TLS.CertificatePath }}" # Key path defines the key.pem file path for the TLS configuration. key-path = "{{ .TLS.KeyPath }}" + +############################################################################### +### OpenTelemetry Configuration ### +############################################################################### + +[otel] + +# Enable defines if the OpenTelemetry exporter should be enabled. +enable = {{ .OTel.Enable }} + +# Endpoint defines the OTLP gRPC endpoint to export traces and metrics to. +# Example: "localhost:4317" for a local OTel Collector. +endpoint = "{{ .OTel.Endpoint }}" + +# Insecure defines if the exporter should use an insecure (non-TLS) connection. +insecure = {{ .OTel.Insecure }} + +# SampleRate controls the fraction of traces sampled (0.0 to 1.0). Default: 0.1 (10%). +sample-rate = {{ .OTel.SampleRate }} + +# ChainID identifies this chain in traces. Attached as chain_id resource attribute. +chain-id = "{{ .OTel.ChainID }}" ` diff --git a/server/flags/flags.go b/server/flags/flags.go index 9550a774..08f66706 100644 --- a/server/flags/flags.go +++ b/server/flags/flags.go @@ -87,6 +87,15 @@ const ( TLSKeyPath = "tls.key-path" ) +// OpenTelemetry flags +const ( + OTelEnable = "otel.enable" + OTelEndpoint = "otel.endpoint" + OTelInsecure = "otel.insecure" + OTelSampleRate = "otel.sample-rate" + OTelChainID = "otel.chain-id" +) + // AddTxFlags adds common flags for commands to post tx func AddTxFlags(cmd *cobra.Command) (*cobra.Command, error) { cmd.PersistentFlags().String(flags.FlagChainID, "", "Specify Chain ID for sending Tx") diff --git a/server/otel.go b/server/otel.go new file mode 100644 index 00000000..36c8f7b9 --- /dev/null +++ b/server/otel.go @@ -0,0 +1,121 @@ +package server + +import ( + "context" + "errors" + "os" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.26.0" + "google.golang.org/grpc/credentials/insecure" + + "cosmossdk.io/log" + + cosmosevmserverconfig "github.com/cosmos/evm/server/config" + "github.com/cosmos/evm/version" +) + +// InitOTel initializes both the TracerProvider and MeterProvider with OTLP gRPC exporters. +// Returns a shutdown function that must be called on application exit. +func InitOTel(ctx context.Context, cfg cosmosevmserverconfig.OTelConfig, logger log.Logger) (func(context.Context) error, error) { + noop := func(context.Context) error { return nil } + + logger.Info("InitOTel called", "enable", cfg.Enable, "endpoint", cfg.Endpoint, "insecure", cfg.Insecure) + if !cfg.Enable { + logger.Info("OpenTelemetry is DISABLED, skipping initialization") + return noop, nil + } + + hostname, _ := os.Hostname() + + res, err := resource.New(ctx, + resource.WithAttributes( + semconv.ServiceNameKey.String("og-evm"), + semconv.ServiceVersionKey.String(version.AppVersion), + semconv.ServiceInstanceIDKey.String(hostname), + attribute.String("chain_id", cfg.ChainID), + ), + ) + if err != nil { + return noop, err + } + + traceOpts := []otlptracegrpc.Option{ + otlptracegrpc.WithEndpoint(cfg.Endpoint), + } + if cfg.Insecure { + traceOpts = append(traceOpts, otlptracegrpc.WithTLSCredentials(insecure.NewCredentials())) + } + + traceExporter, err := otlptracegrpc.New(ctx, traceOpts...) + if err != nil { + return noop, err + } + + tp := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(traceExporter), + sdktrace.WithResource(res), + sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRatioBased(cfg.SampleRate))), + ) + otel.SetTracerProvider(tp) + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + + metricOpts := []otlpmetricgrpc.Option{ + otlpmetricgrpc.WithEndpoint(cfg.Endpoint), + } + if cfg.Insecure { + metricOpts = append(metricOpts, otlpmetricgrpc.WithTLSCredentials(insecure.NewCredentials())) + } + + metricExporter, err := otlpmetricgrpc.New(ctx, metricOpts...) + if err != nil { + logger.Error("failed to create OTel metric exporter", "error", err.Error()) + return tp.Shutdown, nil + } + + mp := metric.NewMeterProvider( + metric.WithReader(metric.NewPeriodicReader(metricExporter)), + metric.WithResource(res), + ) + otel.SetMeterProvider(mp) + + logger.Info("OpenTelemetry tracing and metrics enabled", + "endpoint", cfg.Endpoint, + "insecure", cfg.Insecure, + "sample_rate", cfg.SampleRate, + "chain_id", cfg.ChainID, + ) + + shutdown := func(ctx context.Context) error { + return errors.Join(tp.Shutdown(ctx), mp.Shutdown(ctx)) + } + + return shutdown, nil +} + +// initOTelWithCleanup initializes OTel and returns a cleanup function safe to defer. +// Logs errors rather than returning them — the node should start even if OTel fails. +func initOTelWithCleanup(ctx context.Context, cfg cosmosevmserverconfig.OTelConfig, logger log.Logger) func() { + shutdown, err := InitOTel(ctx, cfg, logger) + if err != nil { + logger.Error("failed to init OpenTelemetry", "error", err.Error()) + } + return func() { + if shutdown == nil { + return + } + if err := shutdown(context.Background()); err != nil { + logger.Error("failed to shutdown OpenTelemetry", "error", err.Error()) + } + } +} diff --git a/server/start.go b/server/start.go index 0ebf5b1b..dbaab086 100644 --- a/server/start.go +++ b/server/start.go @@ -235,6 +235,12 @@ which accepts a path for the resulting pprof file. cmd.Flags().String(srvflags.TLSCertPath, "", "the cert.pem file path for the server TLS configuration") cmd.Flags().String(srvflags.TLSKeyPath, "", "the key.pem file path for the server TLS configuration") + cmd.Flags().Bool(srvflags.OTelEnable, false, "enable OpenTelemetry trace and metric export") + cmd.Flags().String(srvflags.OTelEndpoint, cosmosevmserverconfig.DefaultOTelConfig().Endpoint, "OTLP gRPC endpoint for trace export") + cmd.Flags().Bool(srvflags.OTelInsecure, true, "use insecure (non-TLS) connection for OTLP export") + cmd.Flags().Float64(srvflags.OTelSampleRate, cosmosevmserverconfig.DefaultOTelConfig().SampleRate, "trace sampling rate (0.0 to 1.0)") + cmd.Flags().String(srvflags.OTelChainID, cosmosevmserverconfig.DefaultOTelConfig().ChainID, "chain ID for trace identification") + cmd.Flags().Uint64(server.FlagStateSyncSnapshotInterval, 0, "State sync snapshot interval") cmd.Flags().Uint32(server.FlagStateSyncSnapshotKeepRecent, 2, "State sync snapshot to keep") @@ -290,6 +296,8 @@ func startStandAlone(svrCtx *server.Context, opts StartOptions) error { return err } + defer initOTelWithCleanup(context.Background(), config.OTel, svrCtx.Logger)() + _, err = startTelemetry(config) if err != nil { return err @@ -464,6 +472,8 @@ func startInProcess(svrCtx *server.Context, clientCtx client.Context, opts Start } } + defer initOTelWithCleanup(ctx, config.OTel, logger)() + metrics, err := startTelemetry(config) if err != nil { return err diff --git a/trace/metric.go b/trace/metric.go new file mode 100644 index 00000000..0be4c28d --- /dev/null +++ b/trace/metric.go @@ -0,0 +1,34 @@ +package trace + +import ( + "fmt" + + "go.opentelemetry.io/otel/metric" +) + +// MustInt64Counter creates an Int64Counter and panics on error. +func MustInt64Counter(m metric.Meter, name string, opts ...metric.Int64CounterOption) metric.Int64Counter { + c, err := m.Int64Counter(name, opts...) + if err != nil { + panic(fmt.Sprintf("failed to create OTel counter %s: %v", name, err)) + } + return c +} + +// MustFloat64Counter creates a Float64Counter and panics on error. +func MustFloat64Counter(m metric.Meter, name string, opts ...metric.Float64CounterOption) metric.Float64Counter { + c, err := m.Float64Counter(name, opts...) + if err != nil { + panic(fmt.Sprintf("failed to create OTel counter %s: %v", name, err)) + } + return c +} + +// MustFloat64Gauge creates a Float64Gauge and panics on error. +func MustFloat64Gauge(m metric.Meter, name string, opts ...metric.Float64GaugeOption) metric.Float64Gauge { + g, err := m.Float64Gauge(name, opts...) + if err != nil { + panic(fmt.Sprintf("failed to create OTel gauge %s: %v", name, err)) + } + return g +} diff --git a/x/erc20/keeper/ibc_callbacks.go b/x/erc20/keeper/ibc_callbacks.go index ebf80b80..31ff5cdd 100644 --- a/x/erc20/keeper/ibc_callbacks.go +++ b/x/erc20/keeper/ibc_callbacks.go @@ -4,8 +4,10 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" - "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + evmtrace "github.com/cosmos/evm/trace" "github.com/cosmos/evm/ibc" "github.com/cosmos/evm/x/erc20/types" transfertypes "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" @@ -15,11 +17,22 @@ import ( errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" ) +var ( + ibcOnRecvCounter metric.Int64Counter + ibcErrorCounter metric.Int64Counter +) + +func init() { + ibcOnRecvCounter = evmtrace.MustInt64Counter(erc20Meter, "evm.erc20.ibc.on_recv.total", + metric.WithDescription("Total successful IBC ERC20 conversions on receive")) + ibcErrorCounter = evmtrace.MustInt64Counter(erc20Meter, "evm.erc20.ibc.error.total", + metric.WithDescription("Total failed IBC ERC20 conversions")) +} + // OnRecvPacket performs the ICS20 middleware receive callback for automatically // converting an IBC Coin to their ERC20 representation. // For the conversion to succeed, the IBC denomination must have previously been @@ -140,14 +153,12 @@ func (k Keeper) OnRecvPacket( } // For now the only case we are interested in adding telemetry is a successful conversion. - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{types.ModuleName, "ibc", "on_recv", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("denom", coin.Denom), //nolint:staticcheck // TODO: fix - telemetry.NewLabel("source_channel", packet.SourceChannel), //nolint:staticcheck // TODO: fix - telemetry.NewLabel("source_port", packet.SourcePort), //nolint:staticcheck // TODO: fix - }, + ibcOnRecvCounter.Add(ctx, 1, + metric.WithAttributes( + attribute.String("denom", coin.Denom), + attribute.String("source_channel", packet.SourceChannel), + attribute.String("source_port", packet.SourcePort), + ), ) } @@ -238,7 +249,7 @@ func (k Keeper) ConvertCoinToERC20FromPacket(ctx sdk.Context, data transfertypes if err := k.ConvertCoinNativeERC20(ctx, pair, coin.Amount, common.BytesToAddress(sender), sender); err != nil { // We want to record only the failed attempt to reconvert the coins during IBC. defer func() { - telemetry.IncrCounter(1, types.ModuleName, "ibc", "error", "total") //nolint:staticcheck // TODO: fix + ibcErrorCounter.Add(ctx, 1) }() ctx.EventManager().EmitEvents( sdk.Events{ diff --git a/x/erc20/keeper/msg_server.go b/x/erc20/keeper/msg_server.go index b0859b8d..5fc160fc 100644 --- a/x/erc20/keeper/msg_server.go +++ b/x/erc20/keeper/msg_server.go @@ -5,20 +5,35 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" "github.com/cosmos/evm/contracts" + evmtrace "github.com/cosmos/evm/trace" "github.com/cosmos/evm/x/erc20/types" sdkerrors "cosmossdk.io/errors" "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" errortypes "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) +var ( + erc20Meter = otel.Meter("evm/x/erc20/keeper") + convertERC20Counter metric.Int64Counter + convertERC20Amount metric.Float64Counter +) + +func init() { + convertERC20Counter = evmtrace.MustInt64Counter(erc20Meter, "evm.erc20.convert_erc20.total", + metric.WithDescription("Total ERC20 to coin conversions")) + convertERC20Amount = evmtrace.MustFloat64Counter(erc20Meter, "evm.erc20.convert_erc20.amount.total", + metric.WithDescription("Total ERC20 conversion amounts")) +} + var _ types.MsgServer = &Keeper{} // ConvertERC20 converts ERC20 tokens into native Cosmos coins for both @@ -152,21 +167,13 @@ func (k Keeper) convertERC20IntoCoinsForNativeToken( } defer func() { - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{"tx", "msg", "convert", "erc20", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("coin", pair.Denom), //nolint:staticcheck // TODO: fix - }, + convertERC20Counter.Add(ctx, 1, + metric.WithAttributes(attribute.String("coin", pair.Denom)), ) if msg.Amount.IsInt64() { - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{"tx", "msg", "convert", "erc20", "amount", "total"}, - float32(msg.Amount.Int64()), - []metrics.Label{ - telemetry.NewLabel("denom", pair.Denom), //nolint:staticcheck // TODO: fix - }, + convertERC20Amount.Add(ctx, float64(msg.Amount.Int64()), + metric.WithAttributes(attribute.String("denom", pair.Denom)), ) } }() diff --git a/x/feemarket/keeper/abci.go b/x/feemarket/keeper/abci.go index 2c89b6e9..cbb9b5e4 100644 --- a/x/feemarket/keeper/abci.go +++ b/x/feemarket/keeper/abci.go @@ -5,16 +5,40 @@ import ( "fmt" gomath "math" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + "go.opentelemetry.io/otel/trace" + + evmtrace "github.com/cosmos/evm/trace" "github.com/cosmos/evm/x/feemarket/types" "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" ) +var ( + feemarketTracer = otel.Tracer("evm/x/feemarket/keeper") + feemarketMeter = otel.Meter("evm/x/feemarket/keeper") + baseFeeGauge metric.Float64Gauge + blockGasGauge metric.Float64Gauge +) + +func init() { + baseFeeGauge = evmtrace.MustFloat64Gauge(feemarketMeter, "evm.feemarket.base_fee", + metric.WithDescription("Current base fee")) + blockGasGauge = evmtrace.MustFloat64Gauge(feemarketMeter, "evm.feemarket.block_gas", + metric.WithDescription("Block gas wanted")) +} + // BeginBlock updates base fee func (k *Keeper) BeginBlock(ctx sdk.Context) error { + _, span := feemarketTracer.Start(ctx.Context(), "feemarket.BeginBlock", + trace.WithAttributes(attribute.Int64("block_height", ctx.BlockHeight())), + ) + defer span.End() + baseFee := k.CalculateBaseFee(ctx) // return immediately if base fee is nil @@ -30,8 +54,7 @@ func (k *Keeper) BeginBlock(ctx sdk.Context) error { ctx.Logger().Error("error converting base fee to float64", "error", err.Error()) return } - // there'll be no panic if fails to convert to float32. Will only loose precision - telemetry.SetGauge(float32(floatBaseFee), "feemarket", "base_fee") //nolint:staticcheck // TODO: fix + baseFeeGauge.Record(ctx, floatBaseFee) }() // Store current base fee in event @@ -80,7 +103,7 @@ func (k *Keeper) EndBlock(ctx sdk.Context) error { k.SetBlockGasWanted(ctx, updatedGasWanted) defer func() { - telemetry.SetGauge(float32(updatedGasWanted), "feemarket", "block_gas") //nolint:staticcheck // TODO: fix + blockGasGauge.Record(ctx, float64(updatedGasWanted)) }() ctx.EventManager().EmitEvent(sdk.NewEvent( diff --git a/x/ibc/transfer/keeper/msg_server.go b/x/ibc/transfer/keeper/msg_server.go index 3242e28b..1ed6b721 100644 --- a/x/ibc/transfer/keeper/msg_server.go +++ b/x/ibc/transfer/keeper/msg_server.go @@ -5,17 +5,29 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" - "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + evmtrace "github.com/cosmos/evm/trace" erc20types "github.com/cosmos/evm/x/erc20/types" "github.com/cosmos/ibc-go/v10/modules/apps/transfer/types" storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" ) +var ( + ibcTransferMeter = otel.Meter("evm/x/ibc/transfer/keeper") + ibcTransferCounter metric.Int64Counter +) + +func init() { + ibcTransferCounter = evmtrace.MustInt64Counter(ibcTransferMeter, "evm.erc20.ibc.transfer.total", + metric.WithDescription("Total ERC20 IBC transfers")) +} + var _ types.MsgServer = Keeper{} // Transfer defines a gRPC msg server method for the MsgTransfer message. @@ -75,12 +87,8 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. if balance.Amount.GTE(msg.Token.Amount) { defer func() { - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{"erc20", "ibc", "transfer", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("denom", pair.Denom), //nolint:staticcheck // TODO: fix - }, + ibcTransferCounter.Add(goCtx, 1, + metric.WithAttributes(attribute.String("denom", pair.Denom)), ) }() @@ -104,12 +112,8 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types. } defer func() { - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{"erc20", "ibc", "transfer", "total"}, - 1, - []metrics.Label{ - telemetry.NewLabel("denom", pair.Denom), //nolint:staticcheck // TODO: fix - }, + ibcTransferCounter.Add(goCtx, 1, + metric.WithAttributes(attribute.String("denom", pair.Denom)), ) }() diff --git a/x/precisebank/keeper/send.go b/x/precisebank/keeper/send.go index 7eb37bbe..f70ce082 100644 --- a/x/precisebank/keeper/send.go +++ b/x/precisebank/keeper/send.go @@ -5,20 +5,32 @@ import ( "errors" "fmt" - "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" + evmtrace "github.com/cosmos/evm/trace" "github.com/cosmos/evm/x/precisebank/types" evmtypes "github.com/cosmos/evm/x/vm/types" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" ) +var ( + precisebankMeter = otel.Meter("evm/x/precisebank/keeper") + sendGauge metric.Float64Gauge +) + +func init() { + sendGauge = evmtrace.MustFloat64Gauge(precisebankMeter, "evm.tx.msg.send", + metric.WithDescription("Send transaction amount")) +} + // IsSendEnabledCoins uses the parent x/bank keeper to check the coins provided // and returns an ErrSendDisabled if any of the coins are not configured for // sending. Returns nil if sending is enabled for all provided coin. @@ -471,10 +483,8 @@ func (k Keeper) Send(goCtx context.Context, msg *banktypes.MsgSend) (*banktypes. defer func() { for _, a := range msg.Amount { if a.Amount.IsInt64() { - telemetry.SetGaugeWithLabels( //nolint:staticcheck // TODO: fix - []string{"tx", "msg", "send"}, - float32(a.Amount.Int64()), - []metrics.Label{telemetry.NewLabel("denom", a.Denom)}, //nolint:staticcheck // TODO: fix + sendGauge.Record(goCtx, float64(a.Amount.Int64()), + metric.WithAttributes(attribute.String("denom", a.Denom)), ) } } diff --git a/x/vm/keeper/msg_server.go b/x/vm/keeper/msg_server.go index e1fac779..373a03d2 100644 --- a/x/vm/keeper/msg_server.go +++ b/x/vm/keeper/msg_server.go @@ -6,8 +6,9 @@ import ( "fmt" "strconv" - "github.com/hashicorp/go-metrics" + "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" cmttypes "github.com/cometbft/cometbft/types" @@ -18,11 +19,26 @@ import ( errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) +var ( + vmMeter = otel.Meter("evm/x/vm/keeper") + ethTxCounter metric.Int64Counter + ethGasCounter metric.Float64Counter + ethGasRatio metric.Float64Gauge +) + +func init() { + ethTxCounter = evmtrace.MustInt64Counter(vmMeter, "evm.tx.ethereum_tx.total", + metric.WithDescription("Total number of Ethereum transactions")) + ethGasCounter = evmtrace.MustFloat64Counter(vmMeter, "evm.tx.ethereum_tx.gas_used.total", + metric.WithDescription("Total gas used by Ethereum transactions")) + ethGasRatio = evmtrace.MustFloat64Gauge(vmMeter, "evm.tx.ethereum_tx.gas_ratio", + metric.WithDescription("Gas limit to gas used ratio")) +} + var _ types.MsgServer = &Keeper{} // EthereumTx implements the gRPC MsgServer interface. It receives a transaction which is then @@ -38,13 +54,10 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (_ tx := msg.AsTransaction() - labels := []metrics.Label{ - telemetry.NewLabel("tx_type", fmt.Sprintf("%d", tx.Type())), //nolint:staticcheck // TODO: fix - } + txType := fmt.Sprintf("%d", tx.Type()) + execution := "call" if tx.To() == nil { - labels = append(labels, telemetry.NewLabel("execution", "create")) //nolint:staticcheck // TODO: fix - } else { - labels = append(labels, telemetry.NewLabel("execution", "call")) //nolint:staticcheck // TODO: fix + execution = "create" } response, err := k.ApplyTransaction(ctx, msg.AsTransaction()) @@ -53,29 +66,22 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (_ } defer func() { - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{"tx", "msg", "ethereum_tx", "total"}, - 1, - labels, + attrs := metric.WithAttributes( + attribute.String("tx_type", txType), + attribute.String("execution", execution), ) + ethTxCounter.Add(goCtx, 1, attrs) + if response.GasUsed != 0 { - telemetry.IncrCounterWithLabels( //nolint:staticcheck // TODO: fix - []string{"tx", "msg", "ethereum_tx", "gas_used", "total"}, - float32(response.GasUsed), - labels, - ) + ethGasCounter.Add(goCtx, float64(response.GasUsed), attrs) // Observe which users define a gas limit >> gas used. Note, that // gas_limit and gas_used are always > 0 - gasLimit := math.LegacyNewDec(int64(tx.Gas())) //#nosec G115 -- int overflow is not a concern here -- tx gas is not going to exceed int64 max value - gasRatio, err := gasLimit.QuoInt64(int64(response.GasUsed)).Float64() //#nosec G115 -- int overflow is not a concern here -- gas used is not going to exceed int64 max value + gasLimit := math.LegacyNewDec(int64(tx.Gas())) //#nosec G115 -- int overflow is not a concern here -- tx gas is not going to exceed int64 max value + gasRatioVal, err := gasLimit.QuoInt64(int64(response.GasUsed)).Float64() //#nosec G115 -- int overflow is not a concern here -- gas used is not going to exceed int64 max value if err == nil { - telemetry.SetGaugeWithLabels( //nolint:staticcheck // TODO: fix - []string{"tx", "msg", "ethereum_tx", "gas_limit", "per", "gas_used"}, - float32(gasRatio), - labels, - ) + ethGasRatio.Record(goCtx, gasRatioVal, attrs) } } }() @@ -112,7 +118,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (_ sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory), sdk.NewAttribute(sdk.AttributeKeySender, types.HexAddress(msg.From)), - sdk.NewAttribute(types.AttributeKeyTxType, fmt.Sprintf("%d", tx.Type())), + sdk.NewAttribute(types.AttributeKeyTxType, txType), ), })