/ scrape.py
scrape.py
  1  import argparse
  2  import json
  3  import logging
  4  import os
  5  import sys
  6  import traceback
  7  from pathlib import Path
  8  from typing import Callable, Iterable, List, Union
  9  
 10  from log_multi_analysis import get_folders
 11  from src.analysis.metrics.config import ScrapeConfig
 12  from src.analysis.metrics.libp2p.scrape import Nimlibp2pScrapeBuilder
 13  from src.analysis.metrics.scrapper import Scrapper
 14  from src.analysis.plotting.config import PlotConfigBuilder
 15  from src.analysis.plotting.metrics_plotter import MetricsPlotter
 16  
 17  logger = logging.getLogger(__name__)
 18  
 19  
 20  def setup_logger():
 21      level = logging.INFO
 22      logging.getLogger().setLevel(level)
 23      stream_handler = logging.StreamHandler(sys.stdout)
 24      stream_handler.setLevel(level)
 25      logging.getLogger().addHandler(stream_handler)
 26  
 27  
 28  def extract_exps(
 29      folders: List[str | Path], filters: List[Callable[[dict], bool]]
 30  ) -> Iterable[dict]:
 31      for folder in folders:
 32          try:
 33              metadata_log_path = Path(folder) / "metadata.json"
 34              logger.info(f"Events log path: {metadata_log_path}")
 35              with open(metadata_log_path, "r", encoding="utf-8") as f:
 36                  exp = json.load(f)
 37              if any(filter(exp) == False for filter in filters):
 38                  logger.warning(
 39                      f"Experiment filtered out. path: `{metadata_log_path}` metadata: `{exp}`"
 40                  )
 41                  continue
 42              yield exp
 43          except Exception as e:
 44              full_trace = traceback.format_exc()
 45              logger.error(f"exception: {e}\n{full_trace}")
 46              raise
 47  
 48  
 49  def get_nimlibp2p_exps(folder: Union[str, Path]) -> Iterable[dict]:
 50      experiment_class = "NimLibp2pExperiment"
 51  
 52      def filter_by_class(exp) -> bool:
 53          if exp["experiment"]["class"] != experiment_class:
 54              return False
 55          return True
 56  
 57      filters = []
 58      if experiment_class:
 59          filters.append(filter_by_class)
 60  
 61      paths = [folder / path for path in get_folders(Path(folder), "metadata.json")]
 62      for exp in extract_exps(paths, filters):
 63          yield exp
 64  
 65  
 66  def nimlibp2p_regression_scrape_and_plots(k8s_config: str):
 67      folders = [
 68          # TODO: Put paths here.
 69      ]
 70      exps = []
 71      for folder in folders:
 72          exps.extend(get_nimlibp2p_exps(folder))
 73  
 74      scrapes: ScrapeConfig = []
 75      dump_fmt = "test_results/libp2p/1.16.0"
 76      if len(exps) > 1:
 77          dump_fmt += "_run_{i}"
 78      for i, exp in enumerate(exps):
 79          config = (
 80              Nimlibp2pScrapeBuilder()
 81              .with_exp(exp, extract_name=True)
 82              .with_dump_location(dump_fmt.format(i=i))
 83              .with_libp2p_metrics()
 84              .build()
 85          )
 86          scrapes.append(config)
 87          scrapper = Scrapper(k8s_config, config)
 88          scrapper.query_and_dump_metrics()
 89  
 90      # Data from previous reports.
 91      base = Path(__file__).parent / "nimlibp2pdata"
 92      old_data_folders = [
 93          Path(base) / sub
 94          for sub in [
 95              "nimlibp2p-1.12.0-1KB",
 96              "nimlibp2p-1.13.0-1KB",
 97              "nimlibp2p-1.14.0-1KB",
 98              "nimlibp2p-1.15.0-1KB",
 99              "nimlibp2p-1.16.0-1KB",
100          ]
101      ]
102  
103      muxers = ["yamux", "quic", "mplex"]
104      in_plot = (
105          PlotConfigBuilder(name="in")
106          .with_metric("libp2p-in")
107          .with_folders(old_data_folders)
108          .with_include_files(muxers)
109          .with_data_from_scrapes(scrapes)
110          .build()
111      )
112      out_plot = (
113          PlotConfigBuilder(name="out")
114          .with_metric("libp2p-out")
115          .with_folders(old_data_folders)
116          .with_include_files(muxers)
117          .with_data_from_scrapes(scrapes)
118          .build()
119      )
120  
121      MetricsPlotter(configs=[in_plot, out_plot]).create_plots()
122  
123  
124  def default_kubeconfig_path() -> str:
125      return os.environ.get("KUBECONFIG", str(Path.home() / ".kube" / "config"))
126  
127  
128  def parse_args() -> argparse.Namespace:
129      parser = argparse.ArgumentParser()
130      parser.add_argument(
131          "--config",
132          default=default_kubeconfig_path(),
133          help="Path to kubeconfig file",
134      )
135      return parser.parse_args()
136  
137  
138  def main():
139      setup_logger()
140      params = parse_args()
141      nimlibp2p_regression_scrape_and_plots(params.config)
142  
143  
144  if __name__ == "__main__":
145      main()