Skip to content

Commit abf88b7

Browse files
stats: add output_file option to output the stats to a file
1 parent 13bb69f commit abf88b7

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

src/python/pants/goal/stats_aggregator.py

+28-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import logging
88
from collections import Counter
99
from dataclasses import dataclass
10+
from typing import Optional
1011

1112
from pants.engine.internals.scheduler import Workunit
1213
from pants.engine.rules import collect_rules, rule
@@ -17,7 +18,7 @@
1718
WorkunitsCallbackFactoryRequest,
1819
)
1920
from pants.engine.unions import UnionRule
20-
from pants.option.option_types import BoolOption
21+
from pants.option.option_types import BoolOption, StrOption
2122
from pants.option.subsystem import Subsystem
2223
from pants.util.collections import deep_getsizeof
2324
from pants.util.strutil import softwrap
@@ -55,13 +56,21 @@ class StatsAggregatorSubsystem(Subsystem):
5556
),
5657
advanced=True,
5758
)
59+
output_file = StrOption(
60+
default=None,
61+
metavar="<path>",
62+
help="Output the stats to this file. If unspecified, outputs to stdout.",
63+
)
5864

5965

6066
class StatsAggregatorCallback(WorkunitsCallback):
61-
def __init__(self, *, log: bool, memory: bool, has_histogram_module: bool) -> None:
67+
def __init__(
68+
self, *, log: bool, memory: bool, output_file: Optional[str], has_histogram_module: bool
69+
) -> None:
6270
super().__init__()
6371
self.log = log
6472
self.memory = memory
73+
self.output_file = output_file
6574
self.has_histogram_module = has_histogram_module
6675

6776
@property
@@ -80,6 +89,8 @@ def __call__(
8089
if not finished:
8190
return
8291

92+
output_contents = ""
93+
8394
if self.log:
8495
# Capture global counters.
8596
counters = Counter(context.get_metrics())
@@ -93,7 +104,7 @@ def __call__(
93104
counter_lines = "\n".join(
94105
f" {name}: {count}" for name, count in sorted(counters.items())
95106
)
96-
logger.info(f"Counters:\n{counter_lines}")
107+
output_contents += f"Counters:\n{counter_lines}"
97108

98109
if self.memory:
99110
ids: set[int] = set()
@@ -115,18 +126,20 @@ def __call__(
115126
memory_lines = "\n".join(
116127
f" {size}\t\t{count}\t\t{name}" for size, count, name in sorted(entries)
117128
)
118-
logger.info(f"Memory summary (total size in bytes, count, name):\n{memory_lines}")
129+
output_contents += (
130+
f"\nMemory summary (total size in bytes, count, name):\n{memory_lines}"
131+
)
119132

120133
if not (self.log and self.has_histogram_module):
121134
return
122135
from hdrh.histogram import HdrHistogram # pants: no-infer-dep
123136

124137
histograms = context.get_observation_histograms()["histograms"]
125138
if not histograms:
126-
logger.info("No observation histogram were recorded.")
139+
output_contents += "\nNo observation histogram were recorded."
127140
return
128141

129-
logger.info("Observation histogram summaries:")
142+
output_contents += "\nObservation histogram summaries:"
130143
for name, encoded_histogram in histograms.items():
131144
# Note: The Python library for HDR Histogram will only decode compressed histograms
132145
# that are further encoded with base64. See
@@ -138,8 +151,8 @@ def __call__(
138151
[25, 50, 75, 90, 95, 99]
139152
).items()
140153
)
141-
logger.info(
142-
f"Summary of `{name}` observation histogram:\n"
154+
output_contents += (
155+
f"\nSummary of `{name}` observation histogram:\n"
143156
f" min: {histogram.get_min_value()}\n"
144157
f" max: {histogram.get_max_value()}\n"
145158
f" mean: {histogram.get_mean_value():.3f}\n"
@@ -149,6 +162,12 @@ def __call__(
149162
f"{percentile_to_vals}"
150163
)
151164

165+
if self.output_file:
166+
with open(self.output_file, "w") as fh:
167+
fh.write(output_contents)
168+
else:
169+
logger.info(output_contents)
170+
152171

153172
@dataclass(frozen=True)
154173
class StatsAggregatorCallbackFactoryRequest:
@@ -178,6 +197,7 @@ def construct_callback(
178197
StatsAggregatorCallback(
179198
log=subsystem.log,
180199
memory=subsystem.memory_summary,
200+
output_file=subsystem.output_file,
181201
has_histogram_module=has_histogram_module,
182202
)
183203
if subsystem.log or subsystem.memory_summary

0 commit comments

Comments
 (0)