Statistics about a crawler run.
| 20 | @dataclass(frozen=True) |
| 21 | @docs_group('Statistics') |
| 22 | class FinalStatistics: |
| 23 | """Statistics about a crawler run.""" |
| 24 | |
| 25 | requests_finished: int |
| 26 | requests_failed: int |
| 27 | retry_histogram: list[int] |
| 28 | request_avg_failed_duration: timedelta | None |
| 29 | request_avg_finished_duration: timedelta | None |
| 30 | requests_finished_per_minute: float |
| 31 | requests_failed_per_minute: float |
| 32 | request_total_duration: timedelta |
| 33 | requests_total: int |
| 34 | crawler_runtime: timedelta |
| 35 | |
| 36 | def to_table(self) -> str: |
| 37 | """Print out the Final Statistics data as a table.""" |
| 38 | formatted_dict = {} |
| 39 | for k, v in asdict(self).items(): |
| 40 | if isinstance(v, timedelta): |
| 41 | formatted_dict[k] = format_duration(v) |
| 42 | else: |
| 43 | formatted_dict[k] = v |
| 44 | |
| 45 | return make_table([(str(k), str(v)) for k, v in formatted_dict.items()], width=_STATISTICS_TABLE_WIDTH) |
| 46 | |
| 47 | def to_dict(self) -> dict[str, float | int | list[int]]: |
| 48 | return {k: v.total_seconds() if isinstance(v, timedelta) else v for k, v in asdict(self).items()} |
| 49 | |
| 50 | @override |
| 51 | def __str__(self) -> str: |
| 52 | return json.dumps( |
| 53 | {k: v.total_seconds() if isinstance(v, timedelta) else v for k, v in asdict(self).items()}, |
| 54 | ) |
| 55 | |
| 56 | |
| 57 | @docs_group('Statistics') |
no outgoing calls