diff --git a/README.md b/README.md index ec33dfcc..d5e431db 100644 --- a/README.md +++ b/README.md @@ -153,24 +153,16 @@ Note: In this case, if the service is staked, then it will not update the on-cha cd trader; poetry run python ../report.py; cd .. ``` -3. Use the following set of commands to investigate your agent's logs: +3. Use the `analyse_logs.py` script to investigate your agent's logs: ```bash - cd trader - service_dir="trader_service" - build_dir=$(ls -d "$service_dir"/abci_build_???? 2>/dev/null || echo "$service_dir/abci_build") - poetry run autonomy analyse logs --from-dir "$build_dir/persistent_data/logs/" --agent aea_0 --reset-db - cd .. + cd trader; poetry run python ../analyse_logs.py --agent aea_0 --reset-db; cd .. ``` - For example, inspect the state transitions using the following set of commands: + For example, inspect the state transitions using the following command: ```bash - cd trader - service_dir="trader_service" - build_dir=$(ls -d "$service_dir"/abci_build_???? 2>/dev/null || echo "$service_dir/abci_build") - poetry run autonomy analyse logs --from-dir "$build_dir/persistent_data/logs/" --agent aea_0 --fsm --reset-db - cd .. + cd trader; poetry run python ../analyse_logs.py --agent aea_0 --fsm --reset-db; cd .. ``` This will output the different state transitions of your agent per period, for example: diff --git a/analyse_logs.py b/analyse_logs.py new file mode 100644 index 00000000..faf180b8 --- /dev/null +++ b/analyse_logs.py @@ -0,0 +1,145 @@ +import os +import subprocess +import sys +import argparse + + +def _parse_args(): + """Parse the script arguments.""" + parser = argparse.ArgumentParser(description="Analyse agent logs.") + + parser.add_argument( + "--service-dir", + default="trader_service", + help="The service directory containing build directories (default: 'trader_service')." + ) + parser.add_argument( + "--from-dir", + help="Path to the logs directory. If not provided, it is auto-detected." + ) + parser.add_argument( + "--agent", + default="aea_0", + help="The agent name to analyze (default: 'aea_0')." + ) + parser.add_argument( + "--reset-db", + action="store_true", + help="Use this flag to disable resetting the log database." + ) + parser.add_argument( + "--start-time", + help="Start time in `YYYY-MM-DD H:M:S,MS` format." + ) + parser.add_argument( + "--end-time", + help="End time in `YYYY-MM-DD H:M:S,MS` format." + ) + parser.add_argument( + "--log-level", + choices=["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"], + help="Logging level." + ) + parser.add_argument( + "--period", + type=int, + help="Period ID." + ) + parser.add_argument( + "--round", + help="Round name." + ) + parser.add_argument( + "--behaviour", + help="Behaviour name filter." + ) + parser.add_argument( + "--fsm", + action="store_true", + help="Print only the FSM execution path." + ) + parser.add_argument( + "--include-regex", + help="Regex pattern to include in the result." + ) + parser.add_argument( + "--exclude-regex", + help="Regex pattern to exclude from the result." + ) + + return parser.parse_args() + + +def find_build_directory(service_dir): + """Find the appropriate build directory within the service directory.""" + try: + build_dirs = [ + d for d in os.listdir(service_dir) + if d.startswith("abci_build_") and os.path.isdir(os.path.join(service_dir, d)) + ] + return os.path.join(service_dir, build_dirs[0]) if build_dirs else os.path.join(service_dir, "abci_build") + except FileNotFoundError: + print(f"Service directory '{service_dir}' not found") + sys.exit(1) + + +def run_analysis(logs_dir, **kwargs): + """Run the log analysis command.""" + command = [ + "poetry", "run", "autonomy", "analyse", "logs", + "--from-dir", logs_dir, + ] + if kwargs.get("agent"): + command.extend(["--agent", kwargs.get("agent")]) + if kwargs.get("reset_db"): + command.extend(["--reset-db"]) + if kwargs.get("start_time"): + command.extend(["--start-time", kwargs.get("start_time")]) + if kwargs.get("end_time"): + command.extend(["--end-time", kwargs.get("end_time")]) + if kwargs.get("log_level"): + command.extend(["--log-level", kwargs.get("log_level")]) + if kwargs.get("period"): + command.extend(["--period", kwargs.get("period")]) + if kwargs.get("round"): + command.extend(["--round", kwargs.get("round")]) + if kwargs.get("behaviour"): + command.extend(["--behaviour", kwargs.get("behaviour")]) + if kwargs.get("fsm"): + command.extend(["--fsm"]) + if kwargs.get("include_regex"): + command.extend(["--include-regex", kwargs.get("include_regex")]) + if kwargs.get("exclude_regex"): + command.extend(["--exclude-regex", kwargs.get("exclude_regex")]) + + try: + subprocess.run(command, check=True) + print("Analysis completed successfully.") + except subprocess.CalledProcessError as e: + print(f"Command failed with exit code {e.returncode}") + sys.exit(e.returncode) + except FileNotFoundError: + print("Poetry or autonomy not found. Ensure they are installed and accessible.") + sys.exit(1) + + +if __name__ == "__main__": + # Parse user arguments + args = _parse_args() + + # Determine the logs directory + if args.from_dir: + logs_dir = args.from_dir + if not os.path.exists(logs_dir): + print(f"Specified logs directory '{logs_dir}' not found.") + sys.exit(1) + else: + # Auto-detect the logs directory + build_dir = find_build_directory(args.service_dir) + logs_dir = os.path.join(build_dir, "persistent_data", "logs") + if not os.path.exists(logs_dir): + print(f"Logs directory '{logs_dir}' not found.") + sys.exit(1) + + # Run the analysis + run_analysis(logs_dir, **vars(args))