# `Ascii.Pieces.BootLog`
[🔗](https://github.com/houllette/ascii_art/blob/main/lib/ascii/pieces/boot_log.ex#L1)

A self test counts memory, then the boot log scrolls by.

A machine starting up. The firmware tests its memory and probes its
devices, the kernel prints timestamped lines, services start, and a login
waits. That is upstream's boot, which it plays by default; give it
`steps` and it is your app's own log instead: a deploy, a setup wizard,
a CI run.

## Options

Give them to `Ascii.new/2` as `options:`, and new ones while it plays
with `Ascii.put_options/2` (or a Phoenix player's `options`): new
steps take their place at once, and as the stars and the cursor keep play
time, nothing jumps.

  * `steps` - the log, a list of `%{text: "...", status: "..."}`, a line
    each, systemd style: `"ok"` is `[  OK  ] text`, `"warn"`
    `[ WARN ] text`, `"fail"` `[FAILED] text`, and `"busy"`, a step under
    way, has three stars sweeping in its brackets; any other status (or
    none) is the text alone. The newest steps are at the bottom, older
    ones scrolled away as upstream scrolls its boot, with a cursor
    blinking on the line after the last. Default `[]`.
  * `title` - a heading over a rule, which stays put as the steps scroll
    under it. Default `""`. With no `steps` and no `title` (the
    defaults) it plays upstream's boot; a title alone is an empty log,
    for an app with no steps yet.
  * `cols`, `rows` - the frame's size, 24 to 200 by 3 to 60; upstream's
    64 by 16 by default. Upstream's boot lays its self test out to the
    width, and lines longer than the frame are cut at its edge.

## Colours

In one ink, or a gradient, with `:ink` and `:gradient` (see
`Ascii.Ink`); part by part with `:parts` (see `Ascii.Parts`),
`parts: true` taking the colours suggested here:

  * `title` - the firmware's heading, or the log's title.
  * `rule` - the rule under it, grey.
  * `status.ok` - `ok`, `link up` and `[  OK  ]`, green; `status.warn`,
    `[ WARN ]`, yellow; `status.fail`, `[FAILED]`, red; and
    `status.busy`, a test or probe under way, or a start job's or a busy
    step's stars, cyan.
  * `message` - a kernel or service line's text, or a step's.
  * `label`, `detail` - a self test row's device, and what was found.
  * `bar`, `track` - the memory test's done, blue, and to do, grey; with
    its `address`, grey, and `percent`.
  * `key`, `hint` - the keys the firmware offers, yellow, and what they
    do, grey.
  * `time` - a kernel line's timestamp, grey.
  * `prompt`, `cursor` - the login prompt, and the cursor at the login or
    after the steps.

## Keys and clicks

It takes none: it shows a log, and `Ascii.handle_event/2` ignores
every event. A Phoenix player given `interactive` and `notify` still
tells your LiveView where it was clicked, and on which part
(`Ascii.part_at/4`): a step's `status.fail`, say, or its `message`
and its text, to show what went wrong.

## Screen readers

`Ascii.describe/1` counts the steps by status, naming a failed or a
running one, as "deploy web: 4 steps, 2 ok, 1 warning, 1 failed (health
check)"; with a title and no steps, "deploy web: no steps yet". Playing
upstream's boot, it gives the piece's name and note.

## Example

```elixir
steps = [
  %{text: "built release 1.4.2", status: "ok"},
  %{text: "disk 81% full", status: "warn"},
  %{text: "migrating database", status: "busy"}
]

log = Ascii.new!("boot-log", options: %{title: "deploy web", steps: steps}, parts: true)
Ascii.describe(log)
#=> "deploy web: 3 steps, 1 ok, 1 warning, 1 running (migrating database)"

done = List.replace_at(steps, 2, %{text: "migrated database", status: "ok"})
log = Ascii.put_options!(log, steps: done ++ [%{text: "health check", status: "fail"}])
{frame, _log} = Ascii.frame(log, 1.0)
frame.text =~ "[FAILED] health check"
#=> true
```

```heex
<Ascii.Phoenix.live_player id="deploy" piece="boot-log" options={%{title: "deploy web", steps: @steps}} parts />
```

Ported from `src/pieces/boot-log.ts` in bas3line/ascii (MIT).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
