Skip to content

Commit

Permalink
feat(tooling): Add Ethereum Metrics Exporter (#331)
Browse files Browse the repository at this point in the history
Adds support for
https://github.com/ethpandaops/ethereum-metrics-exporter. An instance
for every participant is spun up as EME only supports a single EL/CL
pair. Can be enabled on a global or participant level.

Resolves #305
  • Loading branch information
samcm committed Oct 25, 2023
1 parent e721373 commit de5eee8
Show file tree
Hide file tree
Showing 11 changed files with 3,766 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -187,6 +187,10 @@ To configure the package behaviour, you can modify your `network_params.json` fi
// Defaults to false
"snooper_enabled": false,

// Enables Ethereum Metrics Exporter for this participant. Can be set globally.
// Defaults to false
"ethereum_metrics_exporter_enabled": false,

// Count of nodes to spin up for this participant
// Default to 1
"count": 1,
Expand Down Expand Up @@ -276,6 +280,10 @@ To configure the package behaviour, you can modify your `network_params.json` fi
// Default to false
"snooper_enabled": false,

// Enables Ethereum Metrics Exporter for all participants
// Defaults to false
"ethereum_metrics_exporter_enabled": false,

// Parallelizes keystore generation so that each node has keystores being generated in their own container
// This will result in a large number of containers being spun up than normal. We advise users to only enable this on a sufficiently large machine or in the cloud as it can be resource consuming on a single machine.
"parallel_keystore_generation": false,
Expand Down
5 changes: 5 additions & 0 deletions main.star
Expand Up @@ -97,9 +97,13 @@ def run(plan, args={}):

all_el_client_contexts = []
all_cl_client_contexts = []
all_ethereum_metrics_exporter_contexts = []
for participant in all_participants:
all_el_client_contexts.append(participant.el_client_context)
all_cl_client_contexts.append(participant.cl_client_context)
all_ethereum_metrics_exporter_contexts.append(
participant.ethereum_metrics_exporter_context
)

# Generate validator ranges
validator_ranges_config_template = read_file(
Expand Down Expand Up @@ -347,6 +351,7 @@ def run(plan, args={}):
all_el_client_contexts,
all_cl_client_contexts,
prometheus_additional_metrics_jobs,
all_ethereum_metrics_exporter_contexts,
)

plan.print("Launching grafana...")
Expand Down
2 changes: 2 additions & 0 deletions network_params.json
Expand Up @@ -12,6 +12,7 @@
"validator_extra_params": [],
"builder_network_params": null,
"validator_count": null,
"ethereum_metrics_exporter_enabled": false,
"count": 2
}
],
Expand All @@ -37,6 +38,7 @@
"wait_for_finalization": false,
"global_client_log_level": "info",
"snooper_enabled": false,
"ethereum_metrics_exporter_enabled": false,
"parallel_keystore_generation": false,
"mev_type": null,
"mev_params": {
Expand Down
@@ -0,0 +1,14 @@
def new_ethereum_metrics_exporter_context(
pair_name,
ip_addr,
metrics_port_num,
cl_name,
el_name,
):
return struct(
pair_name=pair_name,
ip_addr=ip_addr,
metrics_port_num=metrics_port_num,
cl_name=cl_name,
el_name=el_name,
)
@@ -0,0 +1,54 @@
shared_utils = import_module("../shared_utils/shared_utils.star")
constants = import_module("../package_io/constants.star")
static_files = import_module("../static_files/static_files.star")
ethereum_metrics_exporter_context = import_module(
"../ethereum_metrics_exporter/ethereum_metrics_exporter_context.star"
)

HTTP_PORT_ID = "http"
METRICS_PORT_NUMBER = 9090


def launch(
plan,
pair_name,
ethereum_metrics_exporter_service_name,
ethereum_metrics_exporter_image,
el_client_context,
cl_client_context,
):
exporter_service = plan.add_service(
ethereum_metrics_exporter_service_name,
ServiceConfig(
image=ethereum_metrics_exporter_image,
ports={
HTTP_PORT_ID: shared_utils.new_port_spec(
METRICS_PORT_NUMBER,
shared_utils.TCP_PROTOCOL,
shared_utils.HTTP_APPLICATION_PROTOCOL,
)
},
cmd=[
"--metrics-port",
str(METRICS_PORT_NUMBER),
"--consensus-url",
"http://{}:{}".format(
cl_client_context.ip_addr,
cl_client_context.http_port_num,
),
"--execution-url",
"http://{}:{}".format(
el_client_context.ip_addr,
el_client_context.rpc_port_num,
),
],
),
)

return ethereum_metrics_exporter_context.new_ethereum_metrics_exporter_context(
pair_name,
exporter_service.ip_address,
METRICS_PORT_NUMBER,
cl_client_context.client_name,
el_client_context.client_name,
)
2 changes: 2 additions & 0 deletions src/package_io/constants.star
Expand Up @@ -31,6 +31,8 @@ GENESIS_VALIDATORS_ROOT_PLACEHOLDER = "GENESIS_VALIDATORS_ROOT_PLACEHOLDER"

DEFAULT_SNOOPER_IMAGE = "ethpandaops/json-rpc-snoop:1.1.0"

DEFAULT_ETHEREUM_METRICS_EXPORTER_IMAGE = "ethpandaops/ethereum-metrics-exporter:0.22.0"

ARCHIVE_MODE = True


Expand Down
18 changes: 18 additions & 0 deletions src/package_io/input_parser.star
Expand Up @@ -142,6 +142,9 @@ def input_parser(plan, input_args):
validator_count=participant["validator_count"],
snooper_enabled=participant["snooper_enabled"],
count=participant["count"],
ethereum_metrics_exporter_enabled=participant[
"ethereum_metrics_exporter_enabled"
],
)
for participant in result["participants"]
],
Expand Down Expand Up @@ -199,6 +202,7 @@ def input_parser(plan, input_args):
global_client_log_level=result["global_client_log_level"],
mev_type=result["mev_type"],
snooper_enabled=result["snooper_enabled"],
ethereum_metrics_exporter_enabled=result["ethereum_metrics_exporter_enabled"],
parallel_keystore_generation=result["parallel_keystore_generation"],
grafana_additional_dashboards=result["grafana_additional_dashboards"],
disable_peer_scoring=result["disable_peer_scoring"],
Expand Down Expand Up @@ -267,6 +271,18 @@ def parse_network_params(input_args):
if default_snooper_enabled:
participant["snooper_enabled"] = default_snooper_enabled

ethereum_metrics_exporter_enabled = participant[
"ethereum_metrics_exporter_enabled"
]
if ethereum_metrics_exporter_enabled == False:
default_ethereum_metrics_exporter_enabled = result[
"ethereum_metrics_exporter_enabled"
]
if default_ethereum_metrics_exporter_enabled:
participant[
"ethereum_metrics_exporter_enabled"
] = default_ethereum_metrics_exporter_enabled

validator_count = participant["validator_count"]
if validator_count == None:
default_validator_count = result["network_params"][
Expand Down Expand Up @@ -357,6 +373,7 @@ def default_input_args():
"wait_for_finalization": False,
"global_client_log_level": "info",
"snooper_enabled": False,
"ethereum_metrics_exporter_enabled": False,
"parallel_keystore_generation": False,
"disable_peer_scoring": False,
}
Expand Down Expand Up @@ -406,6 +423,7 @@ def default_participant():
"v_max_mem": 0,
"validator_count": None,
"snooper_enabled": False,
"ethereum_metrics_exporter_enabled": False,
"count": 1,
}

Expand Down
2 changes: 2 additions & 0 deletions src/participant.star
Expand Up @@ -4,11 +4,13 @@ def new_participant(
el_client_context,
cl_client_context,
snooper_engine_context,
ethereum_metrics_exporter_context,
):
return struct(
el_client_type=el_client_type,
cl_client_type=cl_client_type,
el_client_context=el_client_context,
cl_client_context=cl_client_context,
snooper_engine_context=snooper_engine_context,
ethereum_metrics_exporter_context=ethereum_metrics_exporter_context,
)
43 changes: 43 additions & 0 deletions src/participant_network.star
Expand Up @@ -24,6 +24,10 @@ teku = import_module("./cl/teku/teku_launcher.star")

snooper = import_module("./snooper/snooper_engine_launcher.star")

ethereum_metrics_exporter = import_module(
"./ethereum_metrics_exporter/ethereum_metrics_exporter_launcher.star"
)

genesis_constants = import_module(
"./prelaunch_data_generator/genesis_constants/genesis_constants.star"
)
Expand Down Expand Up @@ -237,6 +241,7 @@ def launch_participant_network(

all_snooper_engine_contexts = []
all_cl_client_contexts = []
all_ethereum_metrics_exporter_contexts = []
preregistered_validator_keys_for_nodes = validator_data.per_node_keystores

for index, participant in enumerate(participants):
Expand Down Expand Up @@ -341,6 +346,35 @@ def launch_participant_network(

all_cl_client_contexts.append(cl_client_context)

ethereum_metrics_exporter_context = None

if participant.ethereum_metrics_exporter_enabled:
pair_name = "{0}-{1}-{2}".format(index_str, cl_client_type, el_client_type)

ethereum_metrics_exporter_service_name = (
"ethereum-metrics-exporter-{0}".format(pair_name)
)

ethereum_metrics_exporter_image = (
constants.DEFAULT_ETHEREUM_METRICS_EXPORTER_IMAGE
)

ethereum_metrics_exporter_context = ethereum_metrics_exporter.launch(
plan,
pair_name,
ethereum_metrics_exporter_service_name,
ethereum_metrics_exporter_image,
el_client_context,
cl_client_context,
)
plan.print(
"Succesfully added {0} ethereum metrics exporter participants".format(
ethereum_metrics_exporter_context
)
)

all_ethereum_metrics_exporter_contexts.append(ethereum_metrics_exporter_context)

plan.print("Succesfully added {0} CL participants".format(num_participants))

all_participants = []
Expand All @@ -351,15 +385,24 @@ def launch_participant_network(

el_client_context = all_el_client_contexts[index]
cl_client_context = all_cl_client_contexts[index]

if participant.snooper_enabled:
snooper_engine_context = all_snooper_engine_contexts[index]

ethereum_metrics_exporter_context = None

if participant.ethereum_metrics_exporter_enabled:
ethereum_metrics_exporter_context = all_ethereum_metrics_exporter_contexts[
index
]

participant_entry = participant_module.new_participant(
el_client_type,
cl_client_type,
el_client_context,
cl_client_context,
snooper_engine_context,
ethereum_metrics_exporter_context,
)

all_participants.append(participant_entry)
Expand Down
22 changes: 22 additions & 0 deletions src/prometheus/prometheus_launcher.star
Expand Up @@ -34,11 +34,13 @@ def launch_prometheus(
el_client_contexts,
cl_client_contexts,
additional_metrics_jobs,
ethereum_metrics_exporter_contexts,
):
template_data = new_config_template_data(
el_client_contexts,
cl_client_contexts,
additional_metrics_jobs,
ethereum_metrics_exporter_contexts,
)
template_and_data = shared_utils.new_template_and_data(
config_template, template_data
Expand Down Expand Up @@ -86,6 +88,7 @@ def new_config_template_data(
el_client_contexts,
cl_client_contexts,
additional_metrics_jobs,
ethereum_metrics_exporter_contexts,
):
metrics_jobs = []
# Adding execution clients metrics jobs
Expand Down Expand Up @@ -142,6 +145,25 @@ def new_config_template_data(
},
)
)

# Adding ethereum-metrics-exporter metrics jobs
for context in ethereum_metrics_exporter_contexts:
if context != None:
metrics_jobs.append(
new_metrics_job(
job_name="ethereum-metrics-exporter-{0}".format(context.pair_name),
endpoint="{}:{}".format(
context.ip_addr,
context.metrics_port_num,
),
metrics_path="/metrics",
labels={
"instance": context.pair_name,
"consensus_client": context.cl_name,
"execution_client": context.el_name,
},
)
)
# Adding additional metrics jobs
for job in additional_metrics_jobs:
if job == None:
Expand Down

0 comments on commit de5eee8

Please sign in to comment.