如何在生产中调试Elixir应用程序?

时间:2017-10-11 08:50:53

标签: erlang elixir phoenix-framework

这不是特别关于我目前的问题,但更像是一般情况。有时我遇到的问题只发生在生产配置中,我想在那里进行调试。 Elixir最好的方法是什么?生产在没有图形环境(docker)的情况下运行。

在开发中我可以使用IEX.pry,但由于mix在生产中不可用,这似乎不是一种选择。

对于Erlang https://stackoverflow.com/a/21413344/1561489提到dbg和redbug,但即使可以使用它们,我也需要帮助将它们应用于Elixir代码。

3 个答案:

答案 0 :(得分:3)

首先,使用iex -S mix启动在dev计算机上运行iex的本地节点。如果您不希望本地运行的应用程序导致断点被激活,则需要禁止该应用程序在本地启动。为此,您只需在application中注释mix.exs功能或运行iex -S mix run --no-start

接下来,您需要使用Node.connect(:"remote@hostname")从dev节点上的iex连接到docker上运行的远程节点。为此,您必须确保远程计算机上的epmd和节点端口都可以从本地节点访问。

最后,一旦你的节点连接起来,从本地iex运行:debugger.start(),用GUI打开调试器。现在在本地iex中运行:int.ni(<Module you want to debug>),它将使模块对调试器可见,您可以继续添加断点并开始调试。

您可以找到包含步骤和屏幕截图here的教程。

答案 1 :(得分:2)

如果您在AWS上运行您的作品,那么您应该首先利用CloudWatch来利用您的优势。 在elixir代码中,配置您的记录器:

config :logger,
  handle_otp_reports: true,
  handle_sasl_reports: true,
  metadata: [:application, :module, :function, :file, :line]

config :logger,
  backends: [
    {LoggerFileBackend, :shared_error}
  ]

config :logger, :shared_error,
  path: "#{logging_dir}/verbose-error.log",
  level: :error

在Dockerfile中,配置一个环境变量,以准确写入erl_crash.dump,例如: ERL_CRASH_DUMP=/opt/log/erl_crash.dump

然后在awslogs下的.config文件中配置.ebextensions,如下所示:

files:
  "/etc/awslogs/config/stdout.conf":
    mode: "000755"
    owner: root
    group: root
    content: |
      [erl_crash.dump]
      log_group_name=/aws/elasticbeanstalk/your_app/erl_crash.dump
      log_stream_name={instance_id}
      file=/var/log/erl_crash.dump

      [verbose-error.log]
      log_group_name=/aws/elasticbeanstalk/your_app/verbose-error.log
      log_stream_name={instance_id}
      file=/var/log/verbose-error.log

并确保在Dockerrun.aws.json

下为您的泊坞窗设置了一个音量
  "Logging": "/var/log",
  "Volumes": [
    {
      "HostDirectory": "/var/log",
      "ContainerDirectory": "/opt/log"
    }
  ],

之后,您可以检查CloudWatch下的错误消息。 现在,如果您使用ElasticBeanstalk(我的上述示例隐式暗示)与Docker部署而不是AWS ECS,那么std_input的日志默认重定向到{在/var/log/eb-docker/containers/eb-current-app/stdouterr.log内{1}}。

CloudWatch的主要目的是至少知道您的应用程序何时崩溃,从而将容器关闭。 erl_crash.dump通常会重新启动容器,从而让您无法重启。这种理解也可以从其他与docker相关的日志中获得,您可以配置警报以监听它们,并在您的docker必须重新启动时得到相应的通知。但是,将AWS EB记录到CloudWatch的另一个好处是,如果需要,您可以随后将其导出到S3,下载文件并将其导入erl_crash.dump内以分析出错的地方。

如果在查阅日志后仍然需要与生产应用程序进行更亲密的交互,那么您需要将:observer用于您的节点。如果您使用remsh,则可以使用以下版本配置生产应用程序的distillerycookie

node name内,设置Cookie:

rel/confix.exs

并在environment :prod do set include_erts: false set include_src: false set cookie: :"my_cookie" end 下设置变量:

rel/templates/vm.args.eex

并在-name <%= node_name %> -setcookie <%= release.profile.cookie %> 内,你设置了这样的版本:

rel/config.exs

然后,您可以通过首先在包含docker容器的EC2实例内进行ssh-ing直接连接到docker内部运行的生产节点,然后运行以下命令:

release :my_app do
  set version: "0.1.0"

  set overlays: [
    {:template, "rel/templates/vm.args.eex", "releases/<%= release_version %>/vm.args"}
  ]

  set overlay_vars: [
    node_name: "p@127.0.0.1",
  ]

进入内部后,您可以尝试四处寻找或CONTAINER_ID=$(sudo docker ps --format '{{.ID}}') sudo docker exec -it $CONTAINER_ID bash -c "iex --name q@127.0.0.1 --cookie my_cookie" ,在您自己的危险中,动态注入您想要检查的模块的修改代码。一种简单的方法是在容器内创建一个文件并调用if need be

如果你的生产节点已经在运行并且你不知道cookie,你可以进入正在运行的容器并执行Node.spawn_link target_node, fn Code.eval_file(file_name, path) end并执行ps aux > t.log以找出随机cookie有哪些已经应用并相应使用。

Docker阻碍了cat t.log能够与其他节点通信的方式。因此,最好使用epmd创建自己的AWS AMI图像,而不是进行裸机部署。

亚马逊最近向Packer AWS VPC Networking Mode发布了一项新功能,这可能会促进容器间AWS ECS通信,从而直接连接到您的节点。我还没有尝试过,我可能错了。

如果您在AWS以外的提供商上运行,那么必须确定如何使用某些epmd或其他服务轻松访问远程日志。

答案 2 :(得分:0)

我建议使用某种异常处理工具,到目前为止,我在Sentry上有很棒的体验。