156 lines
4.9 KiB
Python
156 lines
4.9 KiB
Python
# isort: skip_file
|
|
# ruff: noqa: E402
|
|
import sys
|
|
import requests
|
|
import os
|
|
|
|
import pytest
|
|
|
|
import ray
|
|
from ray._private.test_utils import wait_for_assertion
|
|
from ray._common.test_utils import (
|
|
fetch_prometheus_metric_timeseries,
|
|
PrometheusTimeseries,
|
|
)
|
|
from ray._common.network_utils import build_address
|
|
from ray._private.telemetry.metric_cardinality import (
|
|
WORKER_ID_TAG_KEY,
|
|
TASK_OR_ACTOR_NAME_TAG_KEY,
|
|
MetricCardinality,
|
|
)
|
|
|
|
|
|
try:
|
|
import prometheus_client
|
|
except ImportError:
|
|
prometheus_client = None
|
|
|
|
|
|
_TO_TEST_METRICS = ["tasks", "actors", "running_jobs"]
|
|
_COMPONENT_TAG_KEY = "Component"
|
|
|
|
|
|
@pytest.fixture
|
|
def _setup_cluster_for_test(request, ray_start_cluster):
|
|
global _CARDINALITY_LEVEL
|
|
_CARDINALITY_LEVEL = None
|
|
core_metric_cardinality_level = request.param
|
|
os.environ["RAY_metric_cardinality_level"] = core_metric_cardinality_level
|
|
cluster = ray_start_cluster
|
|
cluster.add_node(
|
|
_system_config={
|
|
"metrics_report_interval_ms": 1000,
|
|
"enable_metrics_collection": True,
|
|
"metric_cardinality_level": core_metric_cardinality_level,
|
|
}
|
|
)
|
|
cluster.wait_for_nodes()
|
|
ray_context = ray.init(
|
|
address=cluster.address,
|
|
)
|
|
|
|
@ray.remote
|
|
def t():
|
|
print("task")
|
|
|
|
@ray.remote
|
|
class A:
|
|
async def run(self):
|
|
print("actor")
|
|
|
|
a = A.remote()
|
|
obj_refs = [t.remote(), a.run.remote()]
|
|
|
|
# Make a request to the dashboard to produce some dashboard metrics
|
|
requests.get(f"http://{ray_context.dashboard_url}/nodes")
|
|
|
|
node_info_list = ray.nodes()
|
|
prom_addresses = []
|
|
for node_info in node_info_list:
|
|
prom_addresses.append(
|
|
build_address(
|
|
node_info["NodeManagerAddress"], node_info["MetricsExportPort"]
|
|
)
|
|
)
|
|
yield prom_addresses
|
|
|
|
ray.get(obj_refs)
|
|
|
|
|
|
def _cardinality_level_test(_setup_cluster_for_test, cardinality_level, metric):
|
|
"""
|
|
Test that the ray_tasks and ray_actors metric are reported with the expected cardinality level
|
|
"""
|
|
TEST_TIMEOUT_S = 30
|
|
prom_addresses = _setup_cluster_for_test
|
|
|
|
def _validate():
|
|
timeseries = PrometheusTimeseries()
|
|
metric_samples = fetch_prometheus_metric_timeseries(prom_addresses, timeseries)
|
|
samples = metric_samples.get(f"ray_{metric}")
|
|
assert samples, f"Metric {metric} not found in samples"
|
|
for sample in samples:
|
|
if (
|
|
cardinality_level == "legacy"
|
|
or metric not in MetricCardinality.get_high_cardinality_metrics()
|
|
):
|
|
# If the cardinality level is legacy, the WorkerId tag should be
|
|
# present
|
|
assert (
|
|
sample.labels.get(WORKER_ID_TAG_KEY) is not None
|
|
), f"Sample {sample} does not contain WorkerId tag"
|
|
if metric == "tasks" or metric == "actors":
|
|
assert (
|
|
sample.labels.get(TASK_OR_ACTOR_NAME_TAG_KEY) is not None
|
|
), f"Sample {sample} does not contain Name tag"
|
|
elif cardinality_level == "recommended":
|
|
# If the cardinality level is recommended, the WorkerId tag should
|
|
# be removed
|
|
assert (
|
|
sample.labels.get(WORKER_ID_TAG_KEY) is None
|
|
), f"Sample {sample} contains WorkerId tag"
|
|
elif cardinality_level == "low":
|
|
# If the cardinality level is low, the WorkerId and Name tags should
|
|
# be removed
|
|
assert (
|
|
sample.labels.get(WORKER_ID_TAG_KEY) is None
|
|
), f"Sample {sample} contains WorkerId tag"
|
|
assert (
|
|
sample.labels.get(TASK_OR_ACTOR_NAME_TAG_KEY) is None
|
|
), f"Sample {sample} contains Name tag"
|
|
else:
|
|
raise ValueError(f"Unknown cardinality level: {cardinality_level}")
|
|
|
|
# The Component tag should be present on all cardinality levels
|
|
assert (
|
|
sample.labels.get(_COMPONENT_TAG_KEY) is not None
|
|
), f"Sample {sample} does not contain Component tag"
|
|
|
|
wait_for_assertion(
|
|
_validate,
|
|
timeout=TEST_TIMEOUT_S,
|
|
retry_interval_ms=1000, # Yield resource for other processes
|
|
)
|
|
|
|
|
|
@pytest.mark.skipif(prometheus_client is None, reason="Prometheus not installed")
|
|
@pytest.mark.parametrize(
|
|
"_setup_cluster_for_test,cardinality_level,metric",
|
|
[
|
|
(cardinality, cardinality, metric)
|
|
for cardinality in ["low", "recommended", "legacy"]
|
|
for metric in _TO_TEST_METRICS
|
|
],
|
|
indirect=["_setup_cluster_for_test"],
|
|
)
|
|
def test_cardinality_recommended_and_legacy_levels(
|
|
_setup_cluster_for_test, cardinality_level, metric
|
|
):
|
|
_cardinality_level_test(_setup_cluster_for_test, cardinality_level, metric)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
sys.exit(pytest.main(["-sv", __file__]))
|