Elixir 从零 · 第 30 课(展开目录)
01 · 先让代码说话02 · 先认六种值03 · 把值装起来04 · 从旧 list 生成新 list05 · 让形状对上06 · 用 case 做选择07 · 把文字安全变成整数08 · 拆开 &1 和管道09 · 把代码放进项目10 · 真假不只靠 true11 · 走进嵌套数据12 · 一字不一定一字节13 · 让函数按形状接活14 · 把一列数收成一个值15 · 给不同问题选不同路16 · 给 map 一张名片17 · 让项目自己验答案18 · 让成功和失败长得一样19 · 读写文件先管好路20 · 只算眼前需要的21 · 同一句话,不同做法22 · 先约好模块会做什么23 · 把数据形状写在门口24 · 测试不只看一条好路25 · 把项目磨成一个命令26 · 定下小项目边界27 · 把真实文字洗干净28 · 只开三扇门29 · 把约定钉在代码旁30 · 打包,也留下脚印31 · 照任务书交卷
ELIXIR · 作品 · LESSON 3050 分钟

打包,也留下脚印

把命令构建成 escript,用 Logger 记录失败原因与耗时。

01 · 先看完整例子

让 CLI 只负责边界

print/1 与 fail/1 留在 CLI 边界;mix.exs 配置 main_module: TrailStats.CLI。

Elixir
defmodule TrailStats.CLI do
  require Logger

  def main(args) do
    case run(args) do
      :ok -> :ok
      {:error, _reason} -> System.halt(1)
    end
  end

  # 测试调用 run/1;只有打包入口 main/1 决定退出状态
  def run([path]) do
    {micros, result} = :timer.tc(fn -> TrailStats.Parser.read(path) end)
    Logger.info("read path=#{inspect(path)} duration_us=#{micros}")

    # CLI 把内部数据翻译成终端文字
    case result do
      {:ok, lines} -> print(TrailStats.count(lines))
      {:error, reason} -> fail(reason)
    end
  end

  def run(_args), do: fail(:usage)

  defp print(stats) do
    IO.puts("lines=#{stats.lines}")
    IO.puts("words=#{stats.words}")
    IO.puts("chars=#{stats.chars}")
    :ok
  end

  defp fail(reason) do
    Logger.error("read_failed reason=#{inspect(reason)}")
    IO.puts(:stderr, "无法读取输入文件")
    {:error, reason}
  end
end
先对照结果
  • 成功打印 lines=...、words=...、chars=...;打包命令失败时写入标准错误并以状态 1 退出。
02 · 回头拆代码

从第一行往下读

  1. 计时包住文件读取,结果和耗时一起返回。
  2. CLI 调用 Parser 与统计 API,不复制两者逻辑。
  3. 日志只放定位所需信息,避开文件正文。
03 · 认清新符号

符号不是暗号

Logger.info/error

写不同级别的结构化运行线索。

System.halt/1

只在 CLI 最外层用指定状态结束 BEAM。

:timer.tc/1

测量函数运行微秒数并返回结果。

04 · 代码里的概念

把名字和意思对上

01

可观察性

通过日志、指标等外部信号理解程序运行了什么、在哪里失败。

02

退出状态

命令交给操作系统的结果数字;0 通常表示成功,非 0 表示失败。

05 · 再说清楚

这些写法为什么有用

命令行输出给使用者看,日志给维护者查问题。两者不要混成一锅。

成功时打印稳定三行;失败时向标准错误写一句短话,并由最外层返回非零退出状态。

Logger 记录路径、失败类别和耗时,不记录完整文件内容。可观察不等于把用户数据全抄进日志。

06 · 自己改一次

合上答案,动手

补全构建前的三条检查命令。

练习起点
mix format ____
mix ____
mix escript.____

目标结果: 依次运行格式检查、测试、escript 构建。

卡住了,再看提示

填写 --check-formatted、test、build。

运行过以后,再看一种答案
一种答案
# 先检查,再构建
mix format --check-formatted
mix test
mix escript.build
想一想:为什么日志里不记录读取到的完整文件内容?

正文可能很大或含隐私;路径、原因和耗时通常已足够定位问题。

带走

记住三句

  1. 1

    CLI 只处理输入输出边界。

  2. 2

    日志记录必要线索,不泄露正文。

  3. 3

    格式、测试通过后再构建。

本课结束代码也跑过一次,就把这一课收好。