def start_profiler(output_dir: Optional[str]) -> Optional[Any]: """ Start and return a profiler is `output_dir` is not None """ if not output_dir: return None from raiden.utils.profiling.sampler import FlameGraphCollector, SignalSampler os.makedirs(output_dir, exist_ok=True) now = datetime.datetime.now() stack_path = os.path.join(output_dir, f"{now:%Y%m%d_%H%M}_stack.data") stack_stream = open(stack_path, "w") flame = FlameGraphCollector(stack_stream) return SignalSampler(flame)
def profiler(request): profiler = None if request.config.option.profiler == "flamegraph-trace": from raiden.utils.profiling.sampler import TraceSampler, FlameGraphCollector now = datetime.datetime.now() stack_path = os.path.join("/tmp", f"{now:%Y%m%d_%H%M}_stack.data") stack_stream = open(stack_path, "w") flame = FlameGraphCollector(stack_stream) profiler = TraceSampler(flame) yield if profiler is not None: profiler.stop()
def run(ctx: Context, **kwargs: Any) -> None: # pylint: disable=too-many-locals,too-many-branches,too-many-statements flamegraph = kwargs.pop("flamegraph", None) switch_tracing = kwargs.pop("switch_tracing", None) profiler = None switch_monitor = None enable_gevent_monitoring_signal() if flamegraph: os.makedirs(flamegraph, exist_ok=True) now = datetime.datetime.now().isoformat() address = to_checksum_address(kwargs["address"]) stack_path = os.path.join(flamegraph, f"{address}_{now}_stack.data") stack_stream = open(stack_path, "w") flame = FlameGraphCollector(stack_stream) profiler = TraceSampler(flame) if switch_tracing is True: switch_monitor = SwitchMonitoring() memory_logger = None log_memory_usage_interval = kwargs.pop("log_memory_usage_interval", 0) if log_memory_usage_interval > 0: memory_logger = MemoryLogger(log_memory_usage_interval) memory_logger.start() if kwargs.pop("version", False): click.echo( click.style("Hint: Use ", fg="green") + click.style(f"'{os.path.basename(sys.argv[0])} version'", fg="yellow") + click.style(" instead", fg="green") ) ctx.invoke(version, short=True) return if kwargs["config_file"]: apply_config_file(run, kwargs, ctx) validate_option_dependencies(run, ctx, kwargs, OPTION_DEPENDENCIES) if ctx.invoked_subcommand is not None: # Pass parsed args on to subcommands. ctx.obj = kwargs return if kwargs["transport"] == "matrix": runner = MatrixRunner(kwargs, ctx) else: # Shouldn't happen raise RuntimeError(f"Invalid transport type '{kwargs['transport']}'") click.secho(runner.welcome_string, fg="green") click.secho( textwrap.dedent( """\ ---------------------------------------------------------------------- | This is an Alpha version of experimental open source software | | released as a test version under an MIT license and may contain | | errors and/or bugs. No guarantee or representations whatsoever is | | made regarding its suitability (or its use) for any purpose or | | regarding its compliance with any applicable laws and regulations. | | Use of the software is at your own risk and discretion and by | | using the software you acknowledge that you have read this | | disclaimer, understand its contents, assume all risk related | | thereto and hereby release, waive, discharge and covenant not to | | sue Brainbot Labs Establishment or any officers, employees or | | affiliates from and for any direct or indirect liability resulting | | from the use of the software as permissible by applicable laws and | | regulations. | | | | Privacy Warning: Please be aware, that by using the Raiden Client, | | among others, your Ethereum address, channels, channel deposits, | | settlements and the Ethereum address of your channel counterparty | | will be stored on the Ethereum chain, i.e. on servers of Ethereum | | node operators and ergo are to a certain extent publicly available.| | The same might also be stored on systems of parties running Raiden | | nodes connected to the same token network. Data present in the | | Ethereum chain is very unlikely to be able to be changed, removed | | or deleted from the public arena. | | | | Also be aware, that data on individual Raiden token transfers will | | be made available via the Matrix protocol to the recipient, | | intermediating nodes of a specific transfer as well as to the | | Matrix server operators. | ----------------------------------------------------------------------""" ), fg="yellow", ) if not kwargs["accept_disclaimer"]: click.confirm( "\nHave you read, understood and hereby accept the above " "disclaimer and privacy warning?", abort=True, ) # TODO: # - Ask for confirmation to quit if there are any locked transfers that did # not timeout. try: runner.run() except (ReplacementTransactionUnderpriced, EthereumNonceTooLow) as ex: click.secho( f"{ex}. Please make sure that this Raiden node is the " f"only user of the selected account", fg="red", ) sys.exit(ReturnCode.ETH_ACCOUNT_ERROR) except (ConnectionError, ConnectTimeout, RequestsConnectionError, ReadTimeoutError): print(COMMUNICATION_ERROR.format(kwargs["eth_rpc_endpoint"])) sys.exit(ReturnCode.GENERIC_COMMUNICATION_ERROR) except EthNodeInterfaceError as e: click.secho(str(e), fg="red") sys.exit(ReturnCode.ETH_INTERFACE_ERROR) except RaidenUnrecoverableError as ex: click.secho(f"FATAL: An un-recoverable error happen, Raiden is bailing {ex}", fg="red") write_stack_trace(ex) sys.exit(ReturnCode.FATAL) except APIServerPortInUseError as ex: click.secho( f"ERROR: API Address {ex} is in use. Use --api-address <host:port> " f"to specify a different port.", fg="red", ) sys.exit(ReturnCode.PORT_ALREADY_IN_USE) except (KeystoreAuthenticationError, KeystoreFileNotFound) as e: click.secho(str(e), fg="red") sys.exit(ReturnCode.ETH_ACCOUNT_ERROR) except ConfigurationError as e: click.secho(str(e), fg="red") sys.exit(ReturnCode.CONFIGURATION_ERROR) except filelock.Timeout: name_or_id = ID_TO_NETWORKNAME.get(kwargs["network_id"], kwargs["network_id"]) click.secho( f"FATAL: Another Raiden instance already running for account " f"{to_checksum_address(address)} on network id {name_or_id}", fg="red", ) sys.exit(ReturnCode.CONFIGURATION_ERROR) except Exception as ex: write_stack_trace(ex) sys.exit(ReturnCode.FATAL) finally: # teardown order is important because of side-effects, both the # switch_monitor and profiler could use the tracing api, for the # teardown code to work correctly the teardown has to be done in the # reverse order of the initialization. if switch_monitor is not None: switch_monitor.stop() if memory_logger is not None: memory_logger.stop() if profiler is not None: profiler.stop()
def run(ctx: Context, **kwargs: Any) -> None: # pylint: disable=too-many-locals,too-many-branches,too-many-statements flamegraph = kwargs.pop("flamegraph", None) profiler = None if flamegraph: os.makedirs(flamegraph, exist_ok=True) from raiden.utils.profiling.sampler import TraceSampler, FlameGraphCollector now = datetime.datetime.now() stack_path = os.path.join(flamegraph, f"{now:%Y%m%d_%H%M}_stack.data") stack_stream = open(stack_path, "w") flame = FlameGraphCollector(stack_stream) profiler = TraceSampler(flame) if kwargs.pop("version", False): click.echo( click.style("Hint: Use ", fg="green") + click.style(f"'{os.path.basename(sys.argv[0])} version'", fg="yellow") + click.style(" instead", fg="green")) ctx.invoke(version, short=True) return if kwargs["config_file"]: apply_config_file(run, kwargs, ctx) validate_option_dependencies(run, ctx, kwargs, OPTION_DEPENDENCIES) if ctx.invoked_subcommand is not None: # Pass parsed args on to subcommands. ctx.obj = kwargs return if kwargs["transport"] == "matrix": runner = MatrixRunner(kwargs, ctx) else: # Shouldn't happen raise RuntimeError(f"Invalid transport type '{kwargs['transport']}'") click.secho(runner.welcome_string, fg="green") click.secho( textwrap.dedent("""\ ---------------------------------------------------------------------- | This is an Alpha version of experimental open source software | | released as a test version under an MIT license and may contain | | errors and/or bugs. No guarantee or representations whatsoever is | | made regarding its suitability (or its use) for any purpose or | | regarding its compliance with any applicable laws and regulations. | | Use of the software is at your own risk and discretion and by | | using the software you acknowledge that you have read this | | disclaimer, understand its contents, assume all risk related | | thereto and hereby release, waive, discharge and covenant not to | | sue Brainbot Labs Establishment or any officers, employees or | | affiliates from and for any direct or indirect liability resulting | | from the use of the software as permissible by applicable laws and | | regulations. | | | | Privacy Warning: Please be aware, that by using the Raiden Client, | | among others, your Ethereum address, channels, channel deposits, | | settlements and the Ethereum address of your channel counterparty | | will be stored on the Ethereum chain, i.e. on servers of Ethereum | | node operators and ergo are to a certain extent publicly available.| | The same might also be stored on systems of parties running Raiden | | nodes connected to the same token network. Data present in the | | Ethereum chain is very unlikely to be able to be changed, removed | | or deleted from the public arena. | | | | Also be aware, that data on individual Raiden token transfers will | | be made available via the Matrix protocol to the recipient, | | intermediating nodes of a specific transfer as well as to the | | Matrix server operators. | ----------------------------------------------------------------------""" ), fg="yellow", ) if not kwargs["accept_disclaimer"]: click.confirm( "\nHave you read, understood and hereby accept the above " "disclaimer and privacy warning?", abort=True, ) # TODO: # - Ask for confirmation to quit if there are any locked transfers that did # not timeout. try: app = runner.run() app.stop() except (ReplacementTransactionUnderpriced, EthereumNonceTooLow) as e: click.secho( "{}. Please make sure that this Raiden node is the " "only user of the selected account".format(str(e)), fg="red", ) sys.exit(1) finally: if profiler is not None: profiler.stop()
def run(ctx: Context, **kwargs: Any) -> None: # pylint: disable=too-many-locals,too-many-branches,too-many-statements if kwargs["config_file"]: apply_config_file(run, kwargs, ctx) configure_logging( kwargs["log_config"], log_json=kwargs["log_json"], log_file=kwargs["log_file"], disable_debug_logfile=kwargs["disable_debug_logfile"], debug_log_file_path=kwargs["debug_logfile_path"], ) flamegraph = kwargs.pop("flamegraph", None) switch_tracing = kwargs.pop("switch_tracing", None) profiler = None switch_monitor = None enable_gevent_monitoring_signal() if flamegraph: # pragma: no cover windows_not_supported("flame graph") from raiden.utils.profiling.sampler import FlameGraphCollector, TraceSampler os.makedirs(flamegraph, exist_ok=True) now = datetime.datetime.now().isoformat() address = to_checksum_address(kwargs["address"]) stack_path = os.path.join(flamegraph, f"{address}_{now}_stack.data") stack_stream = open(stack_path, "w") flame = FlameGraphCollector(stack_stream) profiler = TraceSampler(flame) if switch_tracing is True: # pragma: no cover windows_not_supported("switch tracing") from raiden.utils.profiling.greenlets import SwitchMonitoring switch_monitor = SwitchMonitoring() if kwargs["environment_type"] == Environment.DEVELOPMENT: IDLE.enable() memory_logger = None log_memory_usage_interval = kwargs.pop("log_memory_usage_interval", 0) if log_memory_usage_interval > 0: # pragma: no cover windows_not_supported("memory usage logging") from raiden.utils.profiling.memory import MemoryLogger memory_logger = MemoryLogger(log_memory_usage_interval) memory_logger.start() if ctx.invoked_subcommand is not None: # Pass parsed args on to subcommands. ctx.obj = kwargs return raiden_version = get_system_spec()["raiden"] click.secho(f"Welcome to Raiden, version {raiden_version}!", fg="green") click.secho( textwrap.dedent("""\ +------------------------------------------------------------------------+ | This is a Beta version of experimental open source software released | | as a test version under an MIT license and may contain errors and/or | | bugs. No guarantee or representation whatsoever is made regarding its | | suitability (or its use) for any purpose or regarding its compliance | | with any applicable laws and regulations. Use of the software is at | | your own risk and discretion and by using the software you warrant and | | represent that you have read this disclaimer, understand its contents, | | assume all risk related thereto and hereby release, waive, discharge | | and covenant not to hold liable Brainbot Labs Establishment or any of | | its officers, employees or affiliates from and for any direct or | | indirect damage resulting from the software or the use thereof. | | Such to the extent as permissible by applicable laws and regulations. | | | | Privacy warning: Please be aware, that by using the Raiden Client, | | among others your Ethereum address, channels, channel deposits, | | settlements and the Ethereum address of your channel counterparty will | | be stored on the Ethereum chain, i.e. on servers of Ethereum node | | operators and ergo are to a certain extent publicly available. The | | same might also be stored on systems of parties running Raiden nodes | | connected to the same token network. Data present in the Ethereum | | chain is very unlikely to be able to be changed, removed or deleted | | from the public arena. | | | | Also be aware, that data on individual Raiden token transfers will be | | made available via the Matrix protocol to the recipient, | | intermediating nodes of a specific transfer as well as to the Matrix | | server operators, see Raiden Transport Specification. | +------------------------------------------------------------------------+""" ), fg="yellow", ) if not kwargs["accept_disclaimer"]: click.confirm( "\nHave you read, understood and hereby accept the above " "disclaimer and privacy warning?", abort=True, ) # Name used in the exception handlers, make sure the kwargs contains the # key with the correct name by always running it. name_or_id = ID_TO_CHAINNAME.get(kwargs["chain_id"], kwargs["chain_id"]) # TODO: # - Ask for confirmation to quit if there are any locked transfers that did # not timeout. try: run_services(kwargs) except KeyboardInterrupt: # The user requested a shutdown. Assume that if the exception # propagated all the way to the top-level everything was shutdown # properly. # # Notes about edge cases: # - It could happen the exception was handled somewhere else in the # code, and did not reach the top-level, ideally that should result in # an exit with a non-zero code, but currently there is not way to # detect that. # - Just because the exception reached main, it doesn't mean that all # services were properly cleaned up. Ideally at this stage we should # run extra code to verify the state of the main services, and if any # of the is not properly shutdown exit with a non-zero code. pass except (ReplacementTransactionUnderpriced, EthereumNonceTooLow) as ex: click.secho( f"{ex}. Please make sure that this Raiden node is the " f"only user of the selected account", fg="red", ) sys.exit(ReturnCode.ETH_ACCOUNT_ERROR) except (ConnectionError, ConnectTimeout, RequestsConnectionError, ReadTimeoutError): print(COMMUNICATION_ERROR.format(kwargs["eth_rpc_endpoint"])) sys.exit(ReturnCode.GENERIC_COMMUNICATION_ERROR) except EthNodeInterfaceError as e: click.secho(str(e), fg="red") sys.exit(ReturnCode.ETH_INTERFACE_ERROR) except RaidenUnrecoverableError as ex: write_stack_trace(ex) sys.exit(ReturnCode.FATAL) except APIServerPortInUseError as ex: click.secho( f"ERROR: API Address {ex} is in use. Use --api-address <host:port> " f"to specify a different port.", fg="red", ) sys.exit(ReturnCode.PORT_ALREADY_IN_USE) except (KeystoreAuthenticationError, KeystoreFileNotFound) as e: click.secho(str(e), fg="red") sys.exit(ReturnCode.ETH_ACCOUNT_ERROR) except ConfigurationError as e: click.secho(str(e), fg="red") sys.exit(ReturnCode.RAIDEN_CONFIGURATION_ERROR) except ContractCodeMismatch as e: click.secho( f"{e}. This may happen if Raiden is configured to use an " f"unsupported version of the contracts.", fg="red", ) sys.exit(ReturnCode.SMART_CONTRACTS_CONFIGURATION_ERROR) except AddressWithoutCode as e: click.secho( f"{e}. This may happen if an external ERC20 smart contract " f"selfdestructed, or if the configured address is misconfigured, make " f"sure the used address is not a normal account but a smart contract, " f"and that it is deployed to {name_or_id}.", fg="red", ) sys.exit(ReturnCode.SMART_CONTRACTS_CONFIGURATION_ERROR) except filelock.Timeout: click.secho( f"FATAL: Another Raiden instance already running for account " f"{to_checksum_address(kwargs['address'])} on network id {name_or_id}", fg="red", ) sys.exit(ReturnCode.RAIDEN_CONFIGURATION_ERROR) except Exception as ex: write_stack_trace(ex) sys.exit(ReturnCode.FATAL) finally: # pragma: no cover # teardown order is important because of side-effects, both the # switch_monitor and profiler could use the tracing api, for the # teardown code to work correctly the teardown has to be done in the # reverse order of the initialization. if switch_monitor is not None: switch_monitor.stop() if memory_logger is not None: memory_logger.stop() if profiler is not None: profiler.stop()