все посты
Заставка Sparkline: заголовок «Charts with a URL you can curl», под ним строка curl -fsS sparkline.ivashkin.dev/i/KEY?latency=112 и оранжевая линия графика на чёрном фоне.

Sparkline — от curl до графика за один запрос

Представляю вам небольшой сервис, который решает ровно одну задачу — построение графиков. Каких графиков? Да абсолютно любых: от нагрузки на систему до лайков под вашим постом.

Мысль простая: число у вас уже есть. Время сборки печатает CI, глубину очереди знает воркер, количество деплоев за день — скрипт выкатки, а количество лайков — база. Не хватает только места, куда это число отправить, и картинки, на которую потом можно посмотреть. Ни библиотеки в lock-файле, ни демона на машине, ни заголовка с токеном для этого не нужно.

Сам сервис sparkline.ivashkin.dev Три графика по 256 измерений — бесплатно и без карты. Минута на то, чтобы завести, и одна строчка curl, чтобы наполнять.

Сначала — минута в мастере

Работает всё максимально просто. Как и в любом сервисе, начинается с регистрации, а дальше мастер из нескольких шагов. Первый — имя графика, и на нём останавливаться не на чем.

Второй — форма, и их пять. Линия — значение во времени, по линии на серию: время ответа, глубина очереди. Площадь — та же линия с залитым объёмом под ней, и несколько серий складываются друг на друга. Столбцы — по столбцу на измерение: деплои за день, ошибки за час. Столбцы с накоплением — сумма за измерение, разложенная на то, сколько внесла каждая серия. И кольцо — что серии показывают прямо сейчас, долями от общей суммы; одна серия в кольце меряется против своей цели.

Шаг «Shape» в мастере: пять карточек — Line, Area, Bars, Stacked bars и Donut, выбрана Line.

Третий шаг — серии. Имя серии это то самое имя, по которому потом адресуется измерение: ?cpu=42 находит серию cpu. Здесь можно (но не обязательно) заранее задать, как будут выглядеть разные серии на одном графике — да, на одном графике можно показывать сразу несколько линий. Список можно оставить и пустым: тогда серия заведётся сама от первого же измерения, которое её назовёт, а цвет ей достанется из градиента между двумя выбранными. Отредактировать всё это можно и потом.

Шаг «Series»: две серии, cpu красная и ram салатовая, кнопка «+ Add series» и палитра автоматических цветов.

Четвёртый шаг — сколько точек график хранит и сколько точек рисует. Это два разных числа, и разница между ними важнее, чем кажется.

Первое — размер окна. Один запрос это одно измерение, и как только приходит новое, самое старое уходит — в той же транзакции, так что график никогда не оказывается даже на мгновение больше своего окна. Это именно окно, а не архив: сервис не хранит историю, он показывает последние N измерений. Второе число — сколько точек попадёт в картинку. Если оно меньше первого, соседние измерения усредняются уже на выходе, а подробность возвращается простым поднятием числа обратно — данные при этом никуда не деваются. В бесплатной версии окно до 256 измерений, в платной — до 4096; платная стоит $3 в месяц, чего как раз хватает на сервер для этого сервиса.

Шаг «Window»: два поля, «Samples kept» и «Points drawn», в обоих 256.

Пятый шаг — что именно видно на картинке. Тумблеров здесь четыре:

  1. Линии сетки — горизонтали по круглым значениям, с подписями сбоку.
  2. Временная ось — метки времени вдоль всего нижнего края, а не только под последним измерением.
  3. Легенда — какая серия каким цветом и что на ней сейчас.
  4. Начинать ось с нуля.

На последнем стоит остановиться, потому что это единственный тумблер, которым можно испортить себе картину мира. Для счётчиков ноль в основании — единственный честный вариант: столбец, висящий над собственным основанием, врёт о том, во сколько раз он больше соседнего. А ряд, который живёт в узком диапазоне, тот же самый ноль расплющивает: загрузка процессора, гуляющая между 40 и 46 процентами, превратится в прямую линию у самого пола, и вы перестанете видеть на ней ровно то, ради чего её рисовали.

Поэтому по умолчанию он выключен для линий и включён для столбцов.

Шаг «What the drawing shows»: тумблеры Value gridlines, Time axis и Legend включены, Start the axis at zero выключен; ниже поле Target и выбор тёмной или светлой темы.

Ещё здесь задаётся целевое значение — оно рисуется пунктиром поперёк графика, и на кольце из одной серии именно оно становится тем, долей от чего эта серия показана, — и тема: под тёмную страницу или под светлую. Меняется от темы только обстановка, то есть сетка, цифры и легенда; цвета серий остаются вашими.

На этом всё, ваш график готов, и вы получите два ID: публичный и приватный. Оба понадобятся чуть позже.

Дальше всё делает одна строчка

А это самый интересный раздел. Данные попадают на график одним запросом. Помните два ID, которые вы получили при создании графика? Вот здесь они и используются.

curl -fsS 'https://sparkline.ivashkin.dev/i/e48z7fg5ke9k3tv5xy3npwz4v5enhwbp?cpu=42&ram=17'

Это всё. e48z7fg5ke9k3tv5xy3npwz4v5enhwbp — тот самый приватный ID, который вы получили после создания графика, cpu=42 кладёт значение 42 в серию cpu, а ram=17 — значение 17 в серию ram. Если серии с таким именем ещё нет, она заведётся сама.

Один запрос — это одно измерение, сколько бы серий оно ни несло: на оси времени появится одна засечка, а не две. Время отправлять не нужно и нельзя, ось времени идёт по часам сервиса — именно это и позволяет запросу состоять из одних только чисел.

Ответ приходит одинаковой формы независимо от того, получилось или нет, так что jq -e .ok — это уже законченная проверка:

{"ok":true,"chart":"Demo","values":{"cpu":42.0,"ram":17.0},"created":["ram"],
 "points":256,"capacity":256,"series":["cpu","mem","ram"],
 "url":"https://sparkline.ivashkin.dev/g/hvej9gpqjz5u"}

За created стоит приглядывать: это серии, которые изобрёл вот этот конкретный запрос. Строчка выше — настоящая, и в ней видно, как я опечатался в собственном примере: на демо-графике были cpu и mem, а я отправил ram — и график молча оброс третьей дорожкой. Никакой ошибки здесь нет, так и задумано, но узнать об этом лучше из ответа, чем с картинки неделю спустя.

Кроме строки запроса тот же адрес принимает форму и JSON — это на случай, если число берётся не из шелла:

curl -fsS -d cpu=42 -d ram=17 https://sparkline.ivashkin.dev/i/KEY
curl -fsS -H 'content-type: application/json' -d '{"cpu":42,"ram":17}' https://sparkline.ivashkin.dev/i/KEY

Отдельно стоит знать про пропуски. Прочерк или пустое значение — это не ноль, а дырка: линия на этом месте разрывается, а столбец не рисуется вовсе. То есть ?cpu=$CPU с незаданным CPU запишет сам момент, а не пол, которого никто не мерил. Разница между «здесь было нулевое значение» и «здесь мы не знали значения» — единственное, что на графике нельзя восстановить задним числом.

Дальше достаточно повторять этот запрос, как только у вас появляются новые данные, — и они сразу будут показаны на графике. Возьмите ваш любимый язык программирования, или curl и cron, что угодно, — и вы получите мощную систему построения графиков в одну строчку!

Прежде чем это уедет в cron

Приватный ID — это весь пароль целиком. Он лежит в пути, а не в заголовке, и это осознанный размен: строчка влезает в Makefile, а график времени сборки не стоит того, чтобы разводить вокруг него OAuth. Тот, кто держит этот ID, может ровно одно — дописывать измерения в этот один график. Ни прочитать настройки, ни удалить график, ни добраться до остальных. Утёк не в тот канал в Slack — меняется в один клик, и всё, что было встроено по публичному ID, продолжает работать.

Запись через GET — такой же размен. Запрос, который меняет состояние, положено отправлять через POST, и POST здесь есть, тем же адресом. Но в одну строчку Makefile влезает GET, и ради этого правило нарушено сознательно. Помнить стоит об обратной стороне: чужой прокси имеет полное право такой запрос переспросить, а curl --retry — тем более, и лишняя засечка на графике придёт именно оттуда.

Лимит — 120 запросов подряд, дальше 120 в минуту на один ID. Считаются запросы, а не числа: один запрос с шестью сериями стоит ровно столько же, сколько один с единственным значением. За лимитом приходит 429 с заголовком Retry-After и тем же числом в теле ответа, так что backoff пишется одной строчкой и не требует угадывания. Из остальных ответов интересны 404 — нет графика с таким приватным ID, тем же ответом и на ID неправильной формы, — и 422, когда записывать нечего: бесконечность и NaN сервис отказывается хранить.

А DELETE по тому же адресу опустошает график. Не удаляет: остаются оба ID, серии, их цвета и всё, что вы уже успели встроить. Уходят только измерения — это то, что нужно, когда график пережил переезд и старые числа больше не про то же самое.

Картинка живёт по собственному адресу

Помимо дашборда, который показывает все графики разом, вы можете встроить график в вашу страницу, в файл README на GitHub — да куда угодно, что поддерживает вставку SVG-изображений.

Для этого вам потребуется взять ваш публичный ID и использовать его как изображение:

https://sparkline.ivashkin.dev/g/hvej9gpqjz5u.svg

Demo

Картинка рисуется в момент, когда её попросили, поэтому вчерашней она не бывает. Размер подгоняется параметрами ?w= и ?h= — они обрезаются до разумного, а не отвергаются, — и примерно ниже 320×120 подписи осей пропадают сами: на такой картинке они крупнее самого графика. Таблице в README и экрану на стене нужны разные размеры, и ради этого не должно заводиться двух графиков.

Помимо этого, вам будет доступно ещё два способа поделиться вашим графиком.

Первый — <script>, который вы встраиваете на свой сайт:

<script src="https://sparkline.ivashkin.dev/g/hvej9gpqjz5u.js"></script>

А вот тот же график, вставленный этим тегом прямо сюда:

Выше была картинка, а это уже график: наведите на него мышкой и получите подробности по каждой серии. ?fill=1 растягивает его на ширину колонки, ?refresh=60 перерисовывает раз в минуту — чаще десяти секунд нельзя, а в фоновой вкладке обновление встаёт на паузу. График встроится синхронно и ровно там, где стоит тег, а сам тег исчезнет. Рисуется он в shadow root, куда стили страницы не дотягиваются, так что чужой CSS ему ничего не сделает — и наоборот. Несколько таких тегов на одной странице друг другу не мешают.

Второй способ — публичная страница, доступная всем без авторизации и использующая только ваш публичный ID: https://sparkline.ivashkin.dev/g/hvej9gpqjz5u. На ней тот же динамический график, и её можно отправить кому угодно.

А если график нужен не человеку, а программе, к тому же адресу приписывается .json, и приходит таблица: серии — это колонки, измерения — строки, null — то, чего в этот момент не мерили. Никакой из трёх адресов не требует авторизации и ни один из них не умеет писать.

Попробуйте прямо отсюда

Sparkline — простой, но мощный сервис для создания и очень простого наполнения графиков. Ссылки, что я оставил в посте, рабочие, и приватный ID тоже настоящий: вы можете сами отправить запрос на тот URL, что указан в статье, и увидеть, как ваше значение появляется на графике. Регистрироваться для этого не нужно.

И да, график в этом посте общий на всех. Дописать в него может кто угодно — собственно, я об этом и прошу. Если вы открыли эту страницу и увидели на картинке чью-то ерунду, значит, всё работает.

Комментарии 0

Комментариев пока нет.