12 июля 2018 года увидел свет первый коммит проекта :telemetry. Автор коммита — Аркадий Гил, но README утверждает, что авторское право принадлежит © 2018 Chris McCord and Erlang Solutions, а последний коммит по состоянию на сегодня был сделан Жозе Валимом.


Big Brother is Watching You


Библиотека представляется следующим образом:


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

Главным преимуществом библиотеки является то, что она действительно очень проста. Вы просто регистрируете событие, которое «состоит из числового значения и прикрепленных метаданных», и просто посылаете соответствующее сообщение всякий раз, когда это необходимо. Сообщение будет доставлено в обработчик, который может делать все, что вздумается потребителю; обычно это запись в журнал или что-то типа того. Разделение бизнес-логики и метрик в лучшем виде.


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




Чувства мои были противоречивы. Я люблю, чтобы метрики были встроены везде, но я не могу согласиться, что grep -r telemetry\.execute ./{lib,test}/**/*.ex* — это то, что я хочу добавить в свой конвейер сборки. Поэтому я придумал удобную обертку для :telemetry, и назвал ее Telemetri?a. Я преследовал следующие цели:


  • простой способ добавления :telemetry к функциям и выражениям;
  • автоматическое создание имен событий на основе контекста;
  • генерация конфигурации во время компиляции для регистрации всех активных событий;
  • автоматическое включение метрик виртуальной машины и системы через :telemetry_poller;
  • настраиваемые обработчики для различных случаев, основанные не только на имени события;
  • полная поддержка релизов;
  • минимум (отсутствие) шаблонного кода для копипаста

В общем и целом


Проект сейчас только-только отправился в детский сад, но он уже полностью пригоден для использования. Все, что вам нужно, чтобы внедрить его в какой-нибудь проект (и, следовательно, запрыгнуть в наш поезд едущих в светлое будущее с ветерком и метриками), — это изменить mix.exs, включив :telemetria, и обеспечить минимальную конфигурацию.


# mix.exs
def project do
  [
    ...
    # needed for autogeneration of events
    compilers: [:telemetria | Mix.compilers()]
  ]
end

def deps do
  [
    ...
    {:telemetria, "~> 0.5"}
  ]
end

Полный список поддерживаемых параметров всегда можно найти в документации, единственным обязательным является :otp_app.


config :telemetria,
  otp_app: :my_app,
  polling: [enabled: true]

С этими настройками, метрики виртуальной машины и системы будут каждые пять секунд доставляться обработчику по умолчанию, который выплюнет их в журнал с уровнем :info.


Интерфейс


Интерфейс у Telemetri?a также очень прост. Он предоставляет три макрокоманды и одну аннотацию для обработки :telemetry событий. Макросы deft/2, defpt/2, и t/2 — для обертки функции, приватных функций и любых пользовательских выражений, добавив к ним события :telemetry. Проще говоря, все три — ничто иное, как аспекты, которые разворачиваются в получить метрики > выполнить обернутые инструкции > снова получить метрики и отослать ивент. Аннотация @telemetria true по существу совпадает с изменением аннотированного вызова на deft/2 / defp/2. Давайте рассмотрим следующий пример.


Используя макрос


defmodule Geom do
  import Telemetria

  @spec circle_area(float()) :: float()
  deft circle_area(radius),
    do: 2 * 3.14 * radius
end

После компиляции этот код выплюнет событие с именем [:geom, :circle_area] при каждом вызове Geom.circle_are/1:


iex|1> Geom.circle_area 2.0

14:59:49.686 [info] [event: [:geom, :circle_area],
  measurements: %{consumed: 3162, reference: "#Reference<0.12.34.56>",
  system_time: [system: 1590843589680306588,
                monotonic: -576460720784457,
                utc: ~U[2020-05-30 12:59:49.681885Z]]},
  metadata: %{context: [], env: #Macro.Env<aliases: [], context: nil, ...},
  config: #PID<0.314.0>]

#? 12.56

Используя аннотацию


defmodule Geom do
  use Telemetria

  @telemetria true 
  @spec circle_area(float()) :: float()
  def circle_area(radius),
    do: 2 * 3.14 * radius
end

Этот код делает в точности то же самое, что и приведенный выше.


Компилятор


Это не обязательно, но работать с Telemetri?a будет заметно проще, если добавить пользовательский компилятор в список компиляторов в вашем mix.exs


def project do
  [
    ...
    compilers: [:telemetria | Mix.compilers()]
  ]
end

Компилятор собирает добавленные / удаленные события, за кулисами поддерживает файл манифеста, чтобы всегда иметь актуальный список событий, и предоставляет диагностику основному компилятору Elixir.


Он также создает и предоставляет конфигурацию JSON, которая может быть найдена в папке config локально и может использоваться в качестве конфигурации JSON в релизах. Telemetri?a умеет читать конфиги в формате JSON.


Конфигурация


Конфигурация позволяет:


  • глобальное включение / отключение телеметрии (очистка на уровне компилятора);
  • включение опроса телеметрии виртуальной машины / системы с интервалом;
  • испольщование обычного файла настройки дополнительных событий, непосредственно обрабатываемых с; помощью :telemetry;
  • конфигурацию JSON дополнительных событий (полезно для релизов);
  • настройку собственного пользовательского обработчика для событий телеметрии.

Полный список настроек доступен в соответствуюшем разделе документации.


Потроха


Глубокое погружение в детали реализации, безусловно, выходит за рамки этой рекламной заметки, но несколько слов все-таки нужно сказать и о том, как оно устроено изнутри.


Если вы хотите легко перейти к добавлению метрик в свое приложение, пожалуйста, прекратите читать прямо сейчас и обратитесь к сниппетам из главки, озаглавленной «В общем и целом».


Если же, наоборот, вас интересуют какие-то хитрости и тонкости, то вот список того, что может оказаться интересным и даже познавательным.


  • ??? всегда актуальные, автодокументируемые настройки с использованием nimble_options;
  • ??? реализация аннотаций с использованием @on_definition и @before_compile хуков времени компиляции;
  • ??? запуск приложения поэтапно посредством Application.start_phase/3, чтобы обеспечить полную доступность :telemetry в момент запуска основного приложения;
  • ??? реализация пользовательского компилятора эликсира для сбора событий и поддержка файла манифеста.



Удачных всем метрик!