Files
mongo/buildscripts/resmokelib/hang_analyzer/core_analyzer.py
2023-08-31 18:30:44 +00:00

88 lines
4.0 KiB
Python

import argparse
import logging
import os
import sys
from typing import Optional
from buildscripts.resmokelib.hang_analyzer import dumper
from buildscripts.resmokelib.hang_analyzer.extractor import download_task_artifacts
from buildscripts.resmokelib.plugin import PluginInterface, Subcommand
class CoreAnalyzer(Subcommand):
def __init__(self, options: argparse.Namespace, logger: logging.Logger = None):
self.options = options
self.task_id = options.task_id
self.root_logger = self.setup_logging(logger)
def execute(self):
base_dir = self.options.working_dir
if self.task_id:
if not download_task_artifacts(self.root_logger, self.task_id, base_dir):
self.root_logger.error("Artifacts were not found.")
raise RuntimeError(
"Artifacts were not found for specified task. Could not analyze cores.")
core_dump_dir = os.path.join(base_dir, "core-dumps")
install_dir = os.path.join(base_dir, "install")
else: # if a task id was not specified, look for input files on the current machine
if not self.options.install_dir:
install_dir = os.path.join(os.path.curdir, "build", "install")
if not self.options.core_dir:
core_dump_dir = os.path.curdir
analysis_dir = os.path.join(base_dir, "analysis")
dumpers = dumper.get_dumpers(self.root_logger, self.options.debugger_output)
dumpers.dbg.analyze_cores(core_dump_dir, install_dir, analysis_dir)
def setup_logging(self, logger: Optional[logging.Logger]):
if logger is None:
root_logger = logging.Logger("hang_analyzer", level=logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter(fmt="%(message)s"))
root_logger.addHandler(handler)
return root_logger
else:
return logger
class CoreAnalyzerPlugin(PluginInterface):
"""Integration-point for core-analyzer."""
def parse(self, subcommand: str, parser: argparse.ArgumentParser,
parsed_args: argparse.Namespace, **kwargs) -> Optional[Subcommand]:
"""Parse command-line options."""
return CoreAnalyzer(parsed_args) if subcommand == 'core-analyzer' else None
def add_subcommand(self, subparsers: argparse._SubParsersAction):
"""Create and add the parser for the core analyzer subcommand."""
parser = subparsers.add_parser(
"core-analyzer", help="Analyzes the core dumps from the specified input files.")
parser.add_argument("--task-id", '-t', action="store", type=str, default=None,
help="Fetch corresponding core dumps and binaries for a given task id.")
parser.add_argument("--install-dir", '-b', action="store", type=str, default=None,
help="Directory that contains binaires and debugsymbols.")
parser.add_argument("--core-dir", '-c', action="store", type=str, default=None,
help="Directory that contains core dumps.")
parser.add_argument(
"--working-dir", '-w', action="store", type=str, default="core-analyzer",
help="Directory that downloaded artifacts will be stores and output will be written to."
)
parser.add_argument(
'-o', '--debugger-output', dest='debugger_output', action="append",
choices=('file', 'stdout'), default=['stdout'],
help="If 'stdout', then the debugger's output is written to the Python"
" process's stdout. If 'file', then the debugger's output is written"
" to a file named debugger_<process>_<pid>.log for each process it"
" attaches to. This option can be specified multiple times on the"
" command line to have the debugger's output written to multiple"
" locations. By default, the debugger's output is written only to the"
" Python process's stdout.")