From 86985f7650158a54ec8e6c9f9b90e9b00495c3ad Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Wed, 23 Apr 2025 15:29:22 +0100 Subject: [PATCH 1/2] Track metrics ports with prometheus --- internal/components.go | 3 +++ internal/local_runner.go | 50 ++++++++++++++++++++++++++++++++++++++++ main.go | 8 +++++++ 3 files changed, 61 insertions(+) diff --git a/internal/components.go b/internal/components.go index ce86142..e4002c6 100644 --- a/internal/components.go +++ b/internal/components.go @@ -137,6 +137,7 @@ func (o *OpGeth) Run(service *service, ctx *ExContext) { WithImage("us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth"). WithTag("v1.101503.2-rc.5"). WithEntrypoint("/bin/sh"). + WithLabel("metrics_path", "/debug/metrics/prometheus"). WithArgs( "-c", "geth init --datadir {{.Dir}}/data_opgeth --state.scheme hash {{.Dir}}/l2-genesis.json && "+ @@ -262,6 +263,7 @@ func (r *RethEL) Run(svc *service, ctx *ExContext) { "--authrpc.port", `{{Port "authrpc" 8551}}`, "--authrpc.addr", "0.0.0.0", "--authrpc.jwtsecret", "{{.Dir}}/jwtsecret", + "--metrics", `0.0.0.0:{{Port "metrics" 9090}}`, // For reth version 1.2.0 the "legacy" engine was removed, so we now require these arguments: "--engine.persistence-threshold", "0", "--engine.memory-block-buffer-target", "0", logLevelToRethVerbosity(ctx.LogLevel), @@ -512,6 +514,7 @@ func (o *OpReth) Run(service *service, ctx *ExContext) { "--datadir", "{{.Dir}}/data_op_reth", "--disable-discovery", "--color", "never", + "--metrics", `0.0.0.0:{{Port "metrics" 9090}}`, "--port", `{{Port "rpc" 30303}}`) } diff --git a/internal/local_runner.go b/internal/local_runner.go index e343021..9112f40 100644 --- a/internal/local_runner.go +++ b/internal/local_runner.go @@ -755,6 +755,56 @@ func (d *LocalRunner) trackContainerStatusAndLogs() { } } +func CreatePrometheusServices(manifest *Manifest, out *output) error { + // Read all the components to be deployed and find all the ports with name 'metrics' + // to create the prometheus scrapper config + var scrapeConfigs []map[string]interface{} + for _, c := range manifest.services { + for _, port := range c.ports { + if port.Name == "metrics" { + metricsPath := "/metrics" + if overrideMetricsPath, ok := c.labels["metrics_path"]; ok { + metricsPath = overrideMetricsPath + } + + scrapeConfig := map[string]interface{}{ + "job_name": c.Name, + "metrics_path": metricsPath, + "static_configs": []map[string]interface{}{ + { + "targets": []string{fmt.Sprintf("%s:%d", c.Name, port.Port)}, + }, + }, + } + scrapeConfigs = append(scrapeConfigs, scrapeConfig) + } + } + } + + promConfig := map[string]interface{}{ + "global": map[string]interface{}{ + "scrape_interval": "1s", + "evaluation_interval": "1s", + }, + "scrape_configs": scrapeConfigs, + } + + if err := out.WriteFile("prometheus.yaml", promConfig); err != nil { + return fmt.Errorf("failed to write prometheus.yml: %w", err) + } + + // add to the manifest the prometheus service + // This is a bit of a hack. + srv := manifest.NewService("prometheus"). + WithImage("prom/prometheus"). + WithTag("latest"). + WithArgs("--config.file", "{{.Dir}}/prometheus.yaml"). + WithPort("metrics", 9090, "tcp") + manifest.services = append(manifest.services, srv) + + return nil +} + func (d *LocalRunner) Run() error { go d.trackContainerStatusAndLogs() diff --git a/main.go b/main.go index 7fa810e..e636fc0 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ var interactive bool var timeout time.Duration var logLevelFlag string var bindExternal bool +var withPrometheus bool var rootCmd = &cobra.Command{ Use: "playground", @@ -169,6 +170,7 @@ func main() { recipeCmd.Flags().DurationVar(&timeout, "timeout", 0, "") // Used for CI recipeCmd.Flags().StringVar(&logLevelFlag, "log-level", "info", "log level") recipeCmd.Flags().BoolVar(&bindExternal, "bind-external", false, "bind host ports to external interface") + recipeCmd.Flags().BoolVar(&withPrometheus, "with-prometheus", false, "whether to gather the Prometheus metrics") cookCmd.AddCommand(recipeCmd) } @@ -225,6 +227,12 @@ func runIt(recipe internal.Recipe) error { return err } + if withPrometheus { + if err := internal.CreatePrometheusServices(svcManager, artifacts.Out); err != nil { + return fmt.Errorf("failed to create prometheus services: %w", err) + } + } + if dryRun { return nil } From abd5ac86e19c25a203290ad8306c2068800b08c1 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Wed, 23 Apr 2025 15:43:53 +0100 Subject: [PATCH 2/2] Add an external scrape endpoint --- internal/local_runner.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/internal/local_runner.go b/internal/local_runner.go index 9112f40..8b29ecf 100644 --- a/internal/local_runner.go +++ b/internal/local_runner.go @@ -759,6 +759,18 @@ func CreatePrometheusServices(manifest *Manifest, out *output) error { // Read all the components to be deployed and find all the ports with name 'metrics' // to create the prometheus scrapper config var scrapeConfigs []map[string]interface{} + + // global scrape config + scrapeConfigs = append(scrapeConfigs, map[string]interface{}{ + "job_name": "external", + "metrics_path": "/metrics", + "static_configs": []map[string]interface{}{ + { + "targets": []string{"host.docker.internal:5555"}, + }, + }, + }) + for _, c := range manifest.services { for _, port := range c.ports { if port.Name == "metrics" {