Как стать автором
Обновить

Измерение аудитории блога с помощью OpenTelemetry

Время на прочтение6 мин
Количество просмотров479
Автор оригинала: Marthym
Мне интересно следить, какие статьи в моём блоге наиболее популярны, и сколько людей заглядывает в блог каждый день. Этот блог прошел через несколько этапов, позволяющих оценить эти показатели. Сначала это была Google Аналитика, но делиться всей этой информацией с Google не очень комфортно. Поэтому я перешёл на Matomo, развернутый на сервере CHATON: Libréon.

TL;DR

Хотите отслеживать трафик на статическом блоге без Matomo и Google Analytics?
Рассказываю, как с помощью OpenTelemetry, Prometheus, Grafana и небольшого самописного скрипта на JS (Otela) можно элегантно и эффективно следить за посещаемостью — при этом полностью сохранив контроль над своими данными.

Проблема


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

Я уже успел поработать со стеком Grafana + OpenTelemetry в проекте Baywatch, и мне захотелось применить эту же связку для замены Matomo. К тому же у меня уже был настроен сервер со всеми необходимыми компонентами.

Другая проблема – если сайт статический, размещенный на Github Pages или других “Pages”, у вас нет доступа к логам веб-сервера, поэтому для их сбора необходимо использовать JS-клиент.

image

Otela — JS-клиент


Первый шаг – это JavaScript-клиент, который будет «стучаться» в Open Telemetry collector с информацией о посещённой страницей. У OpenTelemetry есть SDK, с помощью которого можно передавать метрики и трассировки.

Передавать сигнал «ping» в виде метрики невозможно, т.к. это не сочетается с принципами работы OpenTelemetry и Prometheus. Дело в том, что передается только значение 1, и счетчик сбрасывается на каждом визите.

Зато хорошо работает отправка интервалов (spans). При каждом посещении Otela отправляет интервал с атрибутами посещенных страниц (заголовок, ссылка и т.д.) в OpenTelemetry collector.

Проект Otela доступен github: github.com/Marthym/otela

Проект Otela вырос из одного из примеров в SDK OpenTelemetry и распространяется с открытым исходным кодом. Файл otela.js собирается с помощью WebPack, что позволяет максимально сократить его размер — его легко подключить к любой странице.

Что такое интервал?


В контексте OpenTelemetry интервал представляет собой отдельную операцию или событие при трассировке. Это основная единица наблюдения. Каждый раз, когда пользователь посещает страницу на вашем сайте с Otela, создаётся интервал, который фиксирует это «действие»: посещённый URL, заголовок страницы, использованный браузер, источник (реферер) и другие данные. Этот интервал затем отправляется в OpenTelemetry Collector. Он содержит настраиваемые атрибуты, которые можно извлекать и трансформировать для генерации метрик, используемых в Prometheus. Короче говоря, интервал — это информационно обогащённый и структурированный лог, идеально подходящий для отслеживания взаимодействий пользователей на статическом сайте.

Установка


Чтобы установить Otela, достаточно добавить следующий JavaScript-код в конец HTML-страницы:

<!-- Otela -->
<script>
    var _ota=window._ota=window._ota||{};_ota.t="your.opentelemetry.server";
    (function(){
        var t=document,e=t.createElement("script"),a=t.getElementsByTagName("script")[0];
        e.async=!0;e.src="https://github.com/Marthym/otela/releases/download/1.0.0/otela.js";a.parentNode.insertBefore(e,a)
    })();
</script>
<!-- Конец кода Otela -->

Также нужно настроить OpenTelemetry Collector для приёма интервалов, а также указать источник JS-скрипта. В примерах используется артефакт с GitHub, но на практике лучше встраивать otela.js прямо в исходный код сайта — это снижает риск блокировки скрипта по URL и улучшает загрузку.

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


Для сбора интервалов, отправленных Otela, необходимо настроить OpenTelemetry Collector таким образом, чтобы он принимал входящие интервалы, преобразовывал их в метрики и записывал в Prometheus.

Receiver (приёмник)


receivers:
  otlp/otela:
    protocols:
      http:
        endpoint: ':4318'
        cors:
          allowed_origins:
            - http://*
            - https://*
          max_age: 7200

На стороне приёмника важно правильно настроить CORS. В зависимости от ваших задач, постарайтесь максимально ограничить доступ. В приведённом примере CORS настроены довольно свободно, но если вы отслеживаете только один сайт — лучше ужесточить конфигурацию.

Processors (процессоры)


processors:
  batch:
  filter/otela:
    spans:
      include:
        match_type: strict
        services:
          - "blog.ght1pc9kc.fr"
          - "swr.ght1pc9kc.fr"

  attributes/otela:
    actions:
      - key: referrer
        pattern: ^https?:\/\/(?P<dummy>[^@\n]+@)?(?P<referrer>[^:\/\n?]+)
        action: extract
      - key: dummy
        action: delete
      - key: referrer
        value: direct
        action: insert

Сначала фильтруются входящие данные — остаются только интервалы, поступающие с отслеживаемых сайтов. Затем обрабатываются атрибуты интервалов в зависимости от того, что именно нужно сохранить. В нашем случае мы не сохраняем полный referrer, а оставляем только домен.

Connector (коннектор)


Остаётся только преобразовать интервалы в метрики — то есть просто посчитать интервалы, чтобы получить количество посещений. В OpenTelemetry для этого есть специальные коннекторы. Они позволяют связать конвейер интервалов напрямую с конвейером метрик.

connectors:
  spanmetrics/otela:
    namespace: otela
    histogram:
      explicit:
        buckets: [6ms, 10ms, 100ms, 250ms, 500ms]
    dimensions:
      - name: navigator
      - name: os
      - name: platform
      - name: referrer
      - name: title

service:
  pipelines:
    traces:
      receivers: [otlp/otela]
      processors: [filter/otela, attributes/otela]
      exporters: [spanmetrics/otela]
    metrics:
      receivers: [spanmetrics/otela]
      processors: [batch]
      exporters: [prometheus]

Таким образом, мы подключаем коннектор одновременно к выходу трассировок и ко входу метрик. Помимо подсчёта интервалов, коннектор «span-to-metrics» позволяет рассчитывать процентильные значения.

Получение IP-адресов


Чтобы отличать пользователей друг от друга, нужно получать их IP-адреса. Однако сделать это средствами JavaScript невозможно — для этого потребуются дополнительные запросы и, скорее всего, придётся передавать данные стороннему сервису.

Здесь на помощь приходит фронтенд на базе NginX, который должен стоять перед OpenTelemetry Collector. Он знает IP-адрес клиента, отправляющего интервал, и может передать эту информацию в OpenTelemetry через заголовки запроса.

    location / {
        try_files $uri $uri/ @proxy;
    }

    location @proxy {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port 443;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-GeoIP-Latitude  $geoip_latitude;
        proxy_set_header X-GeoIP-Longitude $geoip_longitude;
        proxy_pass $upstream;
    }

А с помощью модуля GeoIP для NginX можно дополнительно определить географические координаты посетителей и отображать их на карте в Grafana.

Со стороны OpenTelemetry конфигурация выглядит следующим образом:

receivers:
  otlp/otela:
    protocols:
      http:
        endpoint: ':4318'
        include_metadata: true
        cors:
          allowed_origins:
            - http://*
            - https://*
          max_age: 7200

connectors:
  spanmetrics/otela:
    namespace: otela
    histogram:
      explicit:
        buckets: [6ms, 10ms, 100ms, 250ms, 500ms]
    dimensions:
      - name: ip
      - name: navigator
      - name: os
      - name: platform
      - name: referrer
      - name: title
      - name: latitude
      - name: longitude

  attributes/otela:
    actions:
      - key: referrer
        pattern: ^https?:\/\/(?P<dummy>[^@\n]+@)?(?P<referrer>[^:\/\n?]+)
        action: extract
      - key: dummy
        action: delete
      - key: referrer
        value: direct
        action: insert
      - key: ip
        from_context: X-Real-IP
        action: upsert
      - key: latitude
        from_context: X-GeoIP-Latitude
        action: upsert
      - key: longitude
        from_context: X-GeoIP-Longitude
        action: upsert

Важно указать параметр include_metadata: true, который позволяет извлекать заголовки NginX в процессорах OpenTelemetry. Затем достаточно извлечь эти значения и добавить их в атрибуты интервалов перед отправкой в Prometheus.

🔥Важно учесть🔥: сбор IP-адресов и геоданных значительно увеличивает кардинальность атрибутов метрик, что влияет на требования к объёму хранимых данных в Prometheus. Поэтому следует осторожно использовать эту конфигурацию и установить ограничения на объём хранения.

   --storage.tsdb.retention.time=90d
   --storage.tsdb.retention.size=4GB

В этом примере срок хранения данных ограничен 90 днями, а объём хранилища — 4 ГБ.

Помещаем результат Grafana


Наконец после небольшой настройки в Grafana мы получаем дашборд, который выглядит следующим образом:

image

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

Вы можете найти JSON дашборда в этом gist.

С помощью счётчика интервалов и настроенных атрибутов дашборд показывает:
  • Общее количество посещений
  • Количество уникальных посетителей
  • Источники трафика
  • Какие страницы были посещены и как часто
  • А ещё — благодаря геолокации, точки на карте 🗺️

Заключение


Все конфигурационные файлы доступны в этом gist.

В итоге, эта конфигурация идеально подходит под мои нужды и является отличной заменой Matomo. К тому же, благодаря Otela, все данные хранятся и контролируются в Франции. Ничто не покидает мои серверы.

Однако решение не без недостатков. Prometheus не предназначен для хранения такого типа данных. Для логов лучше подойдёт что-то вроде Loki. На данный момент Otela — это всего лишь концепт, и я ещё не нашёл наилучший способ перенаправить данные в Loki.

В продолжение темы рекомендуем вам ознакомиться с книгой «Изучаем OpenTelemetry: современный мониторинг систем».
Теги:
Хабы:
+7
Комментарии1

Публикации

Информация

Сайт
piter.com
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия