Перейти к содержимому
EN
Масштаб
Плотность
Тема
Акцент

Агентный слой

Лог

JS Копирование делает `instrument.js`. Прокрутка за хвостом и виртуализация — слой приложения

Поток строк от машины: время, уровень, сообщение. Моноширинный набор и колонки фиксированной ширины, поэтому лог читается столбцами, а не сплошным текстом.

Компонент
14:32:07infoЗапуск worldgen-01
14:32:09infoПрочитано 4 файла
14:32:11warnchunks.bin занят, повтор через 1 с
14:32:16errorEBUSY: не удалось прочитать chunks.bin
Разметка
<div class="inst-log" role="log" aria-label="Лог прогона">
  <div class="inst-log-line"><span class="inst-log-time">14:32:07</span><span class="inst-log-level">info</span><span>Запуск worldgen-01</span></div>
  <div class="inst-log-line"><span class="inst-log-time">14:32:09</span><span class="inst-log-level">info</span><span>Прочитано 4 файла</span></div>
  <div class="inst-log-line" data-tone="warn"><span class="inst-log-time">14:32:11</span><span class="inst-log-level">warn</span><span>chunks.bin занят, повтор через 1 с</span></div>
  <div class="inst-log-line" data-tone="error"><span class="inst-log-time">14:32:16</span><span class="inst-log-level">error</span><span>EBUSY: не удалось прочитать chunks.bin</span></div>
</div>

Контракт

Что Обязательно Почему
role="log" и aria-label да Строки, прибывающие во время работы, иначе не объявляются вовсе
Три узла в строке: время, уровень, сообщение да Колонки заданы шириной в ch; узел не на своём месте ломает выравнивание всех строк
data-tone только у warn и error да Обычная строка тона не несёт: в потоке из тысячи строк подсвечено то, что требует внимания
Моноширинный набор да Приходит от inst-log. Пропорциональный шрифт рассыпает колонку времени

Доступность

role="log" Область, в которую добавляются записи. Скринридер объявит новые строки, не перечитывая весь лог
Живость role="log" подразумевает aria-live="polite". Для потока в сотни строк в секунду это надо отключить явно: непрерывное озвучивание делает интерфейс неработоспособным
Имя области aria-label обязателен: двa лога на экране без имён неразличимы на слух
Время — данные inst-log-time берёт --text-muted (4.5:1), а не --text-faint: таймстемп читают, а не разглядывают
Не только цвет Уровень написан словом (warn, error) рядом с цветом
Прокрутка Область достижима с клавиатуры. Автопрокрутка вниз обязана останавливаться, когда пользователь прокрутил вверх
Перенос white-space: pre-wrap и overflow-wrap: anywhere только на ячейке сообщения: на контейнере это схлопнуло бы колонки

Устройство

Сетка объявлена на строке, то есть у каждой строки она своя. Если задать колонку уровня по содержимому, её ширина будет меняться от слова к слову: info уже, чем error, и сообщения поедут лесенкой. Поэтому inst-log-level получает фиксированную ширину в 5ch.

Варианты

<div class="inst-log-line" data-tone="error">…</div>
Тон Что красится
нет атрибута Только уровень, приглушённо
warn Уровень
error Уровень и всё сообщение

Ошибка красится целиком: её ищут в тысяче строк, пролистывая глазом, а не читая.

JS

Подключите модуль один раз на страницу — инициализировать компоненты по отдельности не нужно, instrument.js работает делегированием и видит узлы, пришедшие позже.

<script type="module" src="instrument.js"></script>

Что делает instrument.js

Пример в шапке живой: наведите на лог и нажмите кнопку копирования.

Копирование: кнопка .inst-copy внутри .inst-copyable кладёт текст в буфер и отвечает цветом. Подробности — на странице блока кода.

<div class="inst-log inst-copyable">
  <button class="inst-copy" type="button" aria-label="Скопировать лог"></button>
  …
</div>

Что остаётся приложению

Что Почему не instrument.js
Прокрутка за хвостом «Держаться низа, пока человек не отлистал вверх» — политика, а не оформление
Виртуализация Лог агента идёт десятками тысяч строк; способ зависит от источника
Фильтр по уровню Данные

Прокрутку к хвосту приложение делает само, и это одна строка:

if (atBottom) log.scrollTop = log.scrollHeight;

API

Классы
ИмяЧто делает
класс
inst-logКонтейнер, прокручивается
inst-log-lineСтрока: три колонки
inst-log-timeОтметка времени
inst-log-levelУровень, ширина 5ch
Атрибуты
ИмяЗначениеЧто делает
атрибут
data-tone—warn · error
Токены
ИмяЗначениеОткуда
переменная
--level-ink--text-mutedзадаёт приложение
токен
--font-monoui-monospace, " , " , " , Consolas, " , monospaceодно на все ячейки
--text-xs0.78125remбаза +4: масштаб
--surface-sunkenlight-dark(var(--n-2), var(--n-14))база +1: тема
--radius-md8pxбаза +4: масштаб
--space-48pxодно на все ячейки
--pad-panelvar(--space-5)база +14: плотность · масштаб
--gap-inlinevar(--space-4)база +14: плотность · масштаб
--warn-textlight-dark(var(--warn-5), var(--warn-3))база +1: тема
--err-textlight-dark(var(--err-5), var(--err-3))база +1: тема

Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument