Elixir - 当从命令行 运行 时记录器输出是彩色的,当从 iex 运行 时不是这样

Elixir - Logger output is colorful when run from command line, not so when run from iex

当 运行ning 在我的 Elixir 混合应用程序中进行测试时,我有几个实例包含对 Logger.debug() 的一些调用以监视行为。我发现,当我从命令行调用 mix test 时,Logger 输出颜色为浅蓝色,如果我对 .debug() 调用添加自定义颜色,输出​​会相应地着色-

test "some behavior" do
  Logger.debug("foo", ansi_color: :yellow)
  assert true
end

按预期将日志行写成黄色。

但是,我注意到如果我在 iex 会话中 运行 我的测试,颜色不会应用,只是以默认字体颜色(灰色,在我的例子中)-

iex(1)> Mix.shell().cmd(
          "mix test --color",
          env: [{"MIX_ENV", "test"}]
        )

为什么 运行 从 bash 命令行执行测试会产生彩色输出,而 运行 在 iex 中执行测试会导致我的默认字体颜色?

对于上下文——我运行在 Mac (Mojave) 上,从 bash 命令行(如前所述),Elixir 版本 1.8.1。

不可否认,这本身就是一件相当微不足道的事情 - 但我正在努力更好地了解 Elixir shell 和 Mix 与 shell 和系统的各种交互,以及破解这可能有助于我更好地了解幕后发生的事情。这不是我期望发生的事情,我想知道为什么。

解释在 this and this 文章中,但下面的 TL;DR:

您需要通过以下方式在 iex 中启用颜色:

iex> Application.put_env(:elixir, :ansi_enabled, true)

但这只是会话范围。如果你想让它永久化,你需要在当前目录或你的主目录中创建 .iex.exs 文件:

timestamp = fn ->
  {_date, {hour, minute, _second}} = :calendar.local_time
  [hour, minute]
  |> Enum.map(&(String.pad_leading(Integer.to_string(&1), 2, "0")))
  |> Enum.join(":")
end

IEx.configure(
  colors: [
    syntax_colors: [
      number: :light_yellow,
      atom: :light_cyan,
      string: :light_black,
      boolean: :red,
      nil: [:magenta, :bright],
    ],
    ls_directory: :cyan,
    ls_device: :yellow,
    doc_code: :green,
    doc_inline_code: :magenta,
    doc_headings: [:cyan, :underline],
    doc_title: [:cyan, :bright, :underline],
  ],
)

IEx.configure(
  default_prompt:
    "#{IO.ANSI.green}%prefix#{IO.ANSI.reset} " <>
    "[#{IO.ANSI.magenta}#{timestamp.()}#{IO.ANSI.reset} " <>
    ":: #{IO.ANSI.cyan}%counter#{IO.ANSI.reset}] >"
)

就这些了

推理很简单——stdout 在 运行 和 "real" 终端连接到 stdout 时以及它是管道或文件时具有不同的特性。当您 运行:

时可以看到相同的行为
mix test | cat

因为这将附加管道,而不是 "real" 终端(实际上它是终端仿真器,但这超出了问题的范围)。这意味着 Elixir 不能假定生成的流将支持 ANSI 转义码。当您将命令通过管道传输到单独的工具或文件以进行进一步处理时,这一点很重要,因为很多这些工具不理解 ANSI 转义码,会导致错误的结果。

IEx 中 运行 mix test 并保持所有当前配置的最佳方法是:

Mix.Task.rerun(:test)

这将重用当前配置。当然,这会有缺点,它将 运行 与当前环境一起使用,但这也可以通过 运行ning MIX_ENV=test iex -S mix 来修复,以便在 shell 内访问整个测试环境].