Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 52 additions & 5 deletions esrally/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# under the License.

import collections
import datetime
import glob
import json
import logging
Expand Down Expand Up @@ -1270,12 +1271,14 @@ def format_dict(d):
race.race_id,
time.to_iso8601(race.race_timestamp),
race.track,
format_dict(race.track_params),
race.challenge_name,
race.car_name,
format_dict(race.user_tags),
race.distribution_version,
race.revision,
race.rally_version,
race.track_revision,
race.team_revision,
format_dict(race.user_tags),
]
)

Expand All @@ -1288,12 +1291,14 @@ def format_dict(d):
"Race ID",
"Race Timestamp",
"Track",
"Track Parameters",
"Challenge",
"Car",
"User Tags",
"ES Version",
"Revision",
"Rally Version",
"Track Revision",
"Team Revision",
"User Tags",
],
)
)
Expand Down Expand Up @@ -1526,6 +1531,18 @@ def store_race(self, race):
def _max_results(self):
return int(self.cfg.opts("system", "list.races.max_results"))

def _track(self):
return self.cfg.opts("system", "list.races.track", mandatory=False)

def _benchmark_name(self):
return self.cfg.opts("system", "list.races.benchmark_name", mandatory=False)

def _from_date(self):
return self.cfg.opts("system", "list.races.from_date", mandatory=False)

def _to_date(self):
return self.cfg.opts("system", "list.races.to_date", mandatory=False)


# Does not inherit from RaceStore as it is only a delegator with the same API.
class CompositeRaceStore:
Expand Down Expand Up @@ -1576,13 +1593,30 @@ def find_by_race_id(self, race_id):

def _to_races(self, results):
races = []
track = self._track()
name = self._benchmark_name()
pattern = "%Y%m%d"
from_date = self._from_date()
to_date = self._to_date()
for result in results:
# noinspection PyBroadException
try:
with open(result, mode="rt", encoding="utf-8") as f:
races.append(Race.from_dict(json.loads(f.read())))
except BaseException:
logging.getLogger(__name__).exception("Could not load race file [%s] (incompatible format?) Skipping...", result)

if track:
races = filter(lambda r: r.track == track, races)
if name:
filtered_on_name = filter(lambda r: r.user_tags.get("name") == name, races)
filtered_on_benchmark_name = filter(lambda r: r.user_tags.get("benchmark-name") == name, races)
races = list(filtered_on_name) + list(filtered_on_benchmark_name)
if from_date:
races = filter(lambda r: r.race_timestamp.date() >= datetime.datetime.strptime(from_date, pattern).date(), races)
if to_date:
races = filter(lambda r: r.race_timestamp.date() <= datetime.datetime.strptime(to_date, pattern).date(), races)

return sorted(races, key=lambda r: r.race_timestamp, reverse=True)


Expand Down Expand Up @@ -1612,12 +1646,18 @@ def index_name(self, race):
return f"{EsRaceStore.INDEX_PREFIX}{race_timestamp:%Y-%m}"

def list(self):
track = self._track()
name = self._benchmark_name()
from_date = self._from_date()
to_date = self._to_date()

filters = [
{
"term": {
"environment": self.environment_name,
},
}
},
{"range": {"race-timestamp": {"gte": from_date, "lte": to_date, "format": "basic_date"}}},
]

query = {
Expand All @@ -1635,6 +1675,13 @@ def list(self):
},
],
}
if track:
query["query"]["bool"]["filter"].append({"term": {"track": track}})
if name:
query["query"]["bool"]["filter"].append(
{"bool": {"should": [{"term": {"user-tags.benchmark-name": name}}, {"term": {"user-tags.name": name}}]}}
)

result = self.client.search(index="%s*" % EsRaceStore.INDEX_PREFIX, body=query)
hits = result["hits"]["total"]
# Elasticsearch 7.0+
Expand Down
36 changes: 36 additions & 0 deletions esrally/rally.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ class ExitStatus(Enum):


def create_arg_parser():
def valid_date(v):
pattern = "%Y%m%d"
try:
datetime.datetime.strptime(v, pattern)
# don't convert, just check that the format is correct, we'll use the string value later on anyway
return v
except ValueError:
msg = "[{}] does not conform to the pattern [yyyyMMdd]".format(v)
raise argparse.ArgumentTypeError(msg)

def positive_number(v):
value = int(v)
if value <= 0:
Expand Down Expand Up @@ -144,6 +154,28 @@ def add_track_source(subparser):
help="Limit the number of search results for recent races (default: 10).",
default=10,
)
list_parser.add_argument(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the way things are structured right now, all list commands will accept these new race-specific arguments, but can't do anything useful with them. It's not a huge deal, but seeing them in the --help output for something like esrally list tracks --help could add some confusion.

That said, there's already precedent for this. --limit only really applies to races, but you can pass it to any other list subcommand.

Could you perhaps change the help text for the new arguments to indicate that they're intended to be used for races only? Something like Show only races for this track in this case, for example.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the plan is to add list annotations eventually, which --track and --to-date/--from-date options should be applicable as well. I could change to records to races for now and change it back to records once list annotations is implemented.. what do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, interesting. That works for me. Like I said, not a huge deal anyway.

"--track",
help="Show only records from this track",
default=None,
)
list_parser.add_argument(
"--benchmark-name",
help="Show only records from with corresponding 'name' or 'benchmark-name' user tag",
default=None,
)
list_parser.add_argument(
"--from-date",
help="Show only records on or after this date (format: yyyyMMdd)",
type=valid_date,
default=None,
)
list_parser.add_argument(
"--to-date",
help="Show only records before or on this date (format: yyyyMMdd)",
type=valid_date,
default=None,
)
add_track_source(list_parser)

info_parser = subparsers.add_parser("info", help="Show info about a track")
Expand Down Expand Up @@ -993,6 +1025,10 @@ def dispatch_sub_command(arg_parser, args, cfg):
elif sub_command == "list":
cfg.add(config.Scope.applicationOverride, "system", "list.config.option", args.configuration)
cfg.add(config.Scope.applicationOverride, "system", "list.races.max_results", args.limit)
cfg.add(config.Scope.applicationOverride, "system", "list.races.track", args.track)
cfg.add(config.Scope.applicationOverride, "system", "list.races.benchmark_name", args.benchmark_name)
cfg.add(config.Scope.applicationOverride, "system", "list.races.from_date", args.from_date)
cfg.add(config.Scope.applicationOverride, "system", "list.races.to_date", args.to_date)
configure_mechanic_params(args, cfg, command_requires_car=False)
configure_track_params(arg_parser, args, cfg, command_requires_track=False)
dispatch_list(cfg)
Expand Down
71 changes: 71 additions & 0 deletions tests/metrics_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ def as_dict(self):

def setup_method(self, method):
self.cfg = config.Config()
self.cfg.add(config.Scope.application, "system", "list.races.max_results", 100)
self.cfg.add(config.Scope.application, "system", "env.name", "unittest-env")
self.cfg.add(config.Scope.application, "system", "time.start", self.RACE_TIMESTAMP)
self.cfg.add(config.Scope.application, "system", "race.id", self.RACE_ID)
Expand Down Expand Up @@ -1024,6 +1025,36 @@ def test_store_race(self):
}
self.es_mock.index.assert_called_with(index="rally-races-2016-01", id=self.RACE_ID, item=expected_doc)

def test_filter_race(self):
self.es_mock.search.return_value = {"hits": {"total": 0}}
self.cfg.add(config.Scope.application, "system", "list.races.track", "unittest")
self.cfg.add(config.Scope.application, "system", "list.races.benchmark_name", "unittest-test")
self.cfg.add(config.Scope.application, "system", "list.races.to_date", "20160131")
self.cfg.add(config.Scope.application, "system", "list.races.from_date", "20160230")
self.race_store.list()
expected_query = {
"query": {
"bool": {
"filter": [
{"term": {"environment": "unittest-env"}},
{"range": {"race-timestamp": {"gte": "20160230", "lte": "20160131", "format": "basic_date"}}},
{"term": {"track": "unittest"}},
{
"bool": {
"should": [
{"term": {"user-tags.benchmark-name": "unittest-test"}},
{"term": {"user-tags.name": "unittest-test"}},
]
}
},
]
}
},
"size": 100,
"sort": [{"race-timestamp": {"order": "desc"}}],
}
self.es_mock.search.assert_called_with(index="rally-races-*", body=expected_query)


class TestEsResultsStore:
RACE_TIMESTAMP = datetime.datetime(2016, 1, 31)
Expand Down Expand Up @@ -1656,6 +1687,46 @@ def test_store_race(self):
assert race.race_timestamp == retrieved_race.race_timestamp
assert len(self.race_store.list()) == 1

def test_filter_race(self):
t = track.Track(
name="unittest",
indices=[track.Index(name="tests", types=["_doc"])],
challenges=[track.Challenge(name="index", default=True)],
)

race = metrics.Race(
rally_version="0.4.4",
rally_revision="123abc",
environment_name="unittest",
race_id=self.RACE_ID,
race_timestamp=self.RACE_TIMESTAMP,
pipeline="from-sources",
user_tags={"name": "unittest-test"},
track=t,
track_params={"clients": 12},
challenge=t.default_challenge,
car="4gheap",
car_params=None,
plugin_params=None,
)

self.race_store.store_race(race)
assert len(self.race_store.list()) == 1
self.cfg.add(config.Scope.application, "system", "list.races.track", "unittest-2")
assert len(self.race_store.list()) == 0
self.cfg.add(config.Scope.application, "system", "list.races.track", "unittest")
assert len(self.race_store.list()) == 1
self.cfg.add(config.Scope.application, "system", "list.races.benchmark_name", "unittest-test-2")
assert len(self.race_store.list()) == 0
self.cfg.add(config.Scope.application, "system", "list.races.benchmark_name", "unittest-test")
assert len(self.race_store.list()) == 1
self.cfg.add(config.Scope.application, "system", "list.races.to_date", "20160129")
assert len(self.race_store.list()) == 0
self.cfg.add(config.Scope.application, "system", "list.races.to_date", "20160131")
assert len(self.race_store.list()) == 1
self.cfg.add(config.Scope.application, "system", "list.races.from_date", "20160131")
assert len(self.race_store.list()) == 1


class TestStatsCalculator:
def test_calculate_global_stats(self):
Expand Down