<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def run_spec(spec, benchmark_hosts, result_hosts=None, output_fmt=None, logfile_info=None, logfile_result=None, action=None, fail_if=None, sample_mode='reservoir'):
 """Run a spec file, executing the statements on the benchmark_hosts. Short example of a spec file: [setup] statement_files = ["sql/create_table.sql"] [[setup.data_files]] target = "t" source = "data/t.json" [[queries]] statement = "select count(*) from t" iterations = 2000 concurrency = 10 [teardown] statements = ["drop table t"] See https://github.com/mfussenegger/cr8/tree/master/specs for more examples. Args: spec: path to a spec file benchmark_hosts: hostname[:port] pairs of Crate nodes result_hosts: optional hostname[:port] Crate node pairs into which the runtime statistics should be inserted. output_fmt: output format action: Optional action to execute. Default is to execute all actions - setup, queries and teardown. If present only the specified action will be executed. The argument can be provided multiple times to execute more than one action. fail-if: An expression that causes cr8 to exit with a failure if it evaluates to true. The expression can contain formatting expressions for: - runtime_stats - statement - meta - concurrency - bulk_size For example: --fail-if "{runtime_stats.mean} > 1.34" """

    with Logger(output_fmt=output_fmt,
                logfile_info=logfile_info,
                logfile_result=logfile_result) as log:
        do_run_spec(
            spec=spec,
            benchmark_hosts=benchmark_hosts,
            log=log,
            result_hosts=result_hosts,
            action=action,
            fail_if=fail_if,
            sample_mode=sample_mode
        )