From f123228263e568cad4edfdc24a22024134a3fd49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Ramon=20Ma=C3=B1es?= Date: Fri, 11 Aug 2023 15:57:31 +0200 Subject: [PATCH 1/4] feat: new metrics added MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jose Ramon Mañes --- Dockerfile | 2 +- Dockerfile_local | 2 +- config/config.go | 1 + deployment/overlays/local/config/config.yaml | 1 + pkg/http/server.go | 16 ++++++ pkg/k8s/k8s.go | 51 +++++++++++++++++ pkg/metrics/metrics.go | 60 +++++++++++++++++++- 7 files changed, 130 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index b4bbb70..22d2714 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.20.3-bullseye AS builder +FROM golang:1.21.0-bullseye AS builder WORKDIR / COPY go.mod go.sum ./ # Download dependencies diff --git a/Dockerfile_local b/Dockerfile_local index d61e6bc..f568cd4 100644 --- a/Dockerfile_local +++ b/Dockerfile_local @@ -1,4 +1,4 @@ -FROM golang:1.20.3-bullseye AS builder +FROM golang:1.21.0-bullseye AS builder WORKDIR / COPY go.mod go.sum ./ # Download dependencies diff --git a/config/config.go b/config/config.go index 1156923..cbf1352 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,7 @@ type MutualPeersConfig struct { // MutualPeer represents a mutual peer structure. type MutualPeer struct { + ConsensusNode string `yaml:"consensusNode,omitempty"` // List of peers. Peers []Peer `yaml:"peers"` TrustedPeersPath string `yaml:"trustedPeersPath,omitempty"` diff --git a/deployment/overlays/local/config/config.yaml b/deployment/overlays/local/config/config.yaml index 54815c7..5cfe98e 100644 --- a/deployment/overlays/local/config/config.yaml +++ b/deployment/overlays/local/config/config.yaml @@ -1,4 +1,5 @@ mutualPeers: + - consensusNode: "consensus-validator-1" - peers: - nodeName: "da-bridge-1-0" containerName: "da" diff --git a/pkg/http/server.go b/pkg/http/server.go index 7850619..80f58d9 100644 --- a/pkg/http/server.go +++ b/pkg/http/server.go @@ -62,6 +62,22 @@ func Run(cfg config.MutualPeersConfig) { return } + // Get the genesisHash + // check if the config has the consensusNode field defined + if cfg.MutualPeers[0].ConsensusNode != "" { + blockHash, earliestBlockTime := k8s.GenesisHash(cfg) + err = metrics.WithMetricsBlockHeight( + blockHash, + earliestBlockTime, + cfg.MutualPeers[0].ConsensusNode, + os.Getenv("POD_NAMESPACE"), + ) + if err != nil { + log.Errorf("Error registering metric block_height_1: %v", err) + return + } + } + // Create the server server := &http.Server{ Addr: ":" + httpPort, diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index 5404ba5..3819b7b 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -3,8 +3,11 @@ package k8s import ( "bytes" "context" + "encoding/json" "errors" + "fmt" "os" + "os/exec" "sync" "github.com/jrmanes/torch/config" @@ -274,6 +277,54 @@ func BulkTrustedPeers(pods config.MutualPeer) { } } +// GenesisHash +func GenesisHash(pods config.MutualPeersConfig) (string, string) { + consensusNode := pods.MutualPeers[0].ConsensusNode + c := exec.Command("wget", "-q", "-O", "-", fmt.Sprintf("http://%s:26657/block?height=1", consensusNode)) + + // Create a buffer to capture the command's output + var outputBuffer bytes.Buffer + c.Stdout = &outputBuffer + + // Run the command + err := c.Run() + if err != nil { + log.Error("Error:", err) + return "", "" + } + + // Convert the output buffer to a string + outputString := outputBuffer.String() + + // Parse the JSON response into a generic map + var response map[string]interface{} + err = json.Unmarshal([]byte(outputString), &response) + if err != nil { + log.Error("Error parsing JSON:", err) + return "", "" + } + + // Access and print the .block_id.hash field + blockIDHash, ok := response["result"].(map[string]interface{})["block_id"].(map[string]interface{})["hash"].(string) + if !ok { + log.Error("Unable to access .block_id.hash") + return "", "" + } + + // Access and print the .block.header.time field + blockTime, ok := response["result"].(map[string]interface{})["block"].(map[string]interface{})["header"].(map[string]interface{})["time"].(string) + if !ok { + log.Error("Unable to access .block.header.time") + return "", "" + } + + log.Info("Block ID Hash: ", blockIDHash) + log.Info("Block Time: ", blockTime) + log.Info("Full output: ", outputString) + + return blockIDHash, blockTime +} + // RunRemoteCommand executes a remote command on the specified node. func RunRemoteCommand(nodeName, container, namespace string, command []string) (string, error) { clusterConfig, err := rest.InClusterConfig() diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index 247db10..e82ea51 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -2,6 +2,8 @@ package metrics import ( "context" + "fmt" + "time" log "github.com/sirupsen/logrus" @@ -11,7 +13,7 @@ import ( ) // Get the meter from the global meter provider with the name "torch". -var meter = otel.GetMeterProvider().Meter("multiaddr") +var meter = otel.GetMeterProvider().Meter("torch") // MultiAddrs represents the information for a multiaddress. type MultiAddrs struct { @@ -56,3 +58,59 @@ func WithMetricsMultiAddress(multiAddrs []MultiAddrs) error { _, err = meter.RegisterCallback(callback, multiAddressesGauge) return err } + +// BlockHeight represents the information for the block height 1. +type BlockHeight struct { + ServiceName string // ServiceName Name of the service associated with the multiaddress. + BlockHeight string // Namespace where the service is deployed. + Value float64 // Value to be observed for the multiaddress. +} + +// WithMetricsBlockHeight creates a callback function to observe metrics for block_height_1. +// consensus-node:26657/block?height=1 +func WithMetricsBlockHeight(blockHeight, earliestBlockTime, serviceName, namespace string) error { + log.Info("registering metric: ", blockHeight) + // Create a Float64ObservableGauge named "block_height_1" with a description for the metric. + blockHeightGauge, err := meter.Float64ObservableGauge( + "block_height_1", + metric.WithDescription("Torch - BlockHeight"), + ) + if err != nil { + log.Fatalf(err.Error()) + return err + } + callback := func(ctx context.Context, observer metric.Observer) error { + // Define the callback function that will be called periodically to observe metrics. + // Create labels with attributes for each block_height_1. + labels := metric.WithAttributes( + attribute.String("service_name", serviceName), + attribute.String("block_height_1", blockHeight), + attribute.String("earliest_block_time", earliestBlockTime), + attribute.Int("days_running", CalculateDaysDifference(earliestBlockTime)), + attribute.String("namespace", namespace), + ) + // Observe the float64 value for the current block_height_1 with the associated labels. + observer.ObserveFloat64(blockHeightGauge, 1, labels) + + return nil + } + + // Register the callback with the meter and the Float64ObservableGauge. + _, err = meter.RegisterCallback(callback, blockHeightGauge) + return err +} + +func CalculateDaysDifference(inputTimeString string) int { + layout := "2006-01-02T15:04:05.999999999Z" + inputTime, err := time.Parse(layout, inputTimeString) + if err != nil { + fmt.Println("Error parsing time:", err) + return -1 + } + + currentTime := time.Now() + timeDifference := currentTime.Sub(inputTime) + daysDifference := int(timeDifference.Hours() / 24) + + return daysDifference +} From 873745df8f20920ada0583fb2174a06d9beae16d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Ramon=20Ma=C3=B1es?= Date: Fri, 11 Aug 2023 15:59:07 +0200 Subject: [PATCH 2/4] feat: add eof MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jose Ramon Mañes --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 13f5de0..bd2c39a 100644 --- a/Makefile +++ b/Makefile @@ -69,4 +69,4 @@ kubectl_deploy: docker_build_local_push kubectl_apply .PHYONY: kubectl_deploy kubectl_remote_kustomize_deploy: docker_build_local_push_gh kubectl_kustomize -.PHYONY: kubectl_remote_kustomize_deploy \ No newline at end of file +.PHYONY: kubectl_remote_kustomize_deploys \ No newline at end of file From dab817d623eb7ed4a2e9d14bc1201ff6980c8bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Ramon=20Ma=C3=B1es?= Date: Fri, 11 Aug 2023 16:20:27 +0200 Subject: [PATCH 3/4] docs: update readme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jose Ramon Mañes --- pkg/k8s/k8s.go | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index 3819b7b..af2e3cc 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -6,8 +6,9 @@ import ( "encoding/json" "errors" "fmt" + "io/ioutil" + "net/http" "os" - "os/exec" "sync" "github.com/jrmanes/torch/config" @@ -280,39 +281,47 @@ func BulkTrustedPeers(pods config.MutualPeer) { // GenesisHash func GenesisHash(pods config.MutualPeersConfig) (string, string) { consensusNode := pods.MutualPeers[0].ConsensusNode - c := exec.Command("wget", "-q", "-O", "-", fmt.Sprintf("http://%s:26657/block?height=1", consensusNode)) + url := fmt.Sprintf("http://%s:26657/block?height=1", consensusNode) - // Create a buffer to capture the command's output - var outputBuffer bytes.Buffer - c.Stdout = &outputBuffer + response, err := http.Get(url) + if err != nil { + log.Error("Error making GET request:", err) + return "", "" + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + log.Error("Non-OK response:", response.Status) + return "", "" + } - // Run the command - err := c.Run() + bodyBytes, err := ioutil.ReadAll(response.Body) if err != nil { - log.Error("Error:", err) + log.Error("Error reading response body:", err) return "", "" } - // Convert the output buffer to a string - outputString := outputBuffer.String() + bodyString := string(bodyBytes) + fmt.Println("Response Body:") + fmt.Println(bodyString) // Parse the JSON response into a generic map - var response map[string]interface{} - err = json.Unmarshal([]byte(outputString), &response) + var jsonResponse map[string]interface{} + err = json.Unmarshal([]byte(bodyString), &jsonResponse) if err != nil { log.Error("Error parsing JSON:", err) return "", "" } // Access and print the .block_id.hash field - blockIDHash, ok := response["result"].(map[string]interface{})["block_id"].(map[string]interface{})["hash"].(string) + blockIDHash, ok := jsonResponse["result"].(map[string]interface{})["block_id"].(map[string]interface{})["hash"].(string) if !ok { log.Error("Unable to access .block_id.hash") return "", "" } // Access and print the .block.header.time field - blockTime, ok := response["result"].(map[string]interface{})["block"].(map[string]interface{})["header"].(map[string]interface{})["time"].(string) + blockTime, ok := jsonResponse["result"].(map[string]interface{})["block"].(map[string]interface{})["header"].(map[string]interface{})["time"].(string) if !ok { log.Error("Unable to access .block.header.time") return "", "" @@ -320,7 +329,7 @@ func GenesisHash(pods config.MutualPeersConfig) (string, string) { log.Info("Block ID Hash: ", blockIDHash) log.Info("Block Time: ", blockTime) - log.Info("Full output: ", outputString) + log.Info("Full output: ", bodyString) return blockIDHash, blockTime } From 659eb0896e8662b4089093d00096d0bfe1513abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Ramon=20Ma=C3=B1es?= Date: Fri, 11 Aug 2023 16:24:00 +0200 Subject: [PATCH 4/4] feat: fmt to log MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jose Ramon Mañes --- pkg/k8s/k8s.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/k8s/k8s.go b/pkg/k8s/k8s.go index af2e3cc..a32d716 100644 --- a/pkg/k8s/k8s.go +++ b/pkg/k8s/k8s.go @@ -302,8 +302,7 @@ func GenesisHash(pods config.MutualPeersConfig) (string, string) { } bodyString := string(bodyBytes) - fmt.Println("Response Body:") - fmt.Println(bodyString) + log.Info("Response Body:", bodyString) // Parse the JSON response into a generic map var jsonResponse map[string]interface{}