EUM мониторинг Flutter-приложений

Обновлено 29.07.2026
Proto Observability Platform принимает данные RUM от Flutter-приложений. Одна интеграция покрывает Android и iOS.

На этой странице:

Введение

Пакет datadog_flutter_plugin передаёт данные RUM в формате, который Proto Observability Platform принимает и обрабатывает штатно. Чтобы данные приходили в платформу, достаточно указать в конфигурации пакета адрес приёма ProtoOBP.

Что при этом важно знать:

  • Учётная запись Datadog не требуется. Токен клиента (clientToken) и идентификатор приложения (applicationId) передаются в запросах как есть; платформа их не проверяет и не обращается к внешним сервисам для их валидации. Задайте любые непустые значения — они удобны как метки, но на приём данных не влияют.
  • Адрес приёма подставляется целиком. Пакет не дописывает путь к значению customEndpoint, поэтому указывать нужно полный URL вместе с путём. Это самая частая причина, по которой данные не появляются.
  • Параметр site обязателен по контракту пакета, но при заданном customEndpoint в отправке данных не участвует. Оставьте любое значение.

Для нативных мобильных приложений используются агенты Proto Observability: Android и iOS.

Состав атрибутов, которые собираются и становятся доступны в интерфейсе, приведён на странице Собираемые данные RUM и Mobile — Flutter-приложения используют ту же схему событий, что Android и iOS.

Состав интеграции

Подключается один пакетdatadog_flutter_plugin. Он покрывает обе мобильные платформы: приведённая ниже настройка работает и на Android, и на iOS, платформенно-зависимый код писать не нужно.

Отдельно подключать библиотеки для Android и iOS не требуется. Пакет представляет собой обвязку над платформенными библиотеками, и они подтягиваются как транзитивные зависимости при обычной сборке проекта:

  • на Android — dd-sdk-android-rum, dd-sdk-android-logs, dd-sdk-android-ndk версии 3.11.0 через Gradle;
  • на iOS — DatadogCore, DatadogRUM, DatadogLogs, DatadogCrashReporting, DatadogInternal версии 3.13.0 через CocoaPods.

Версии платформенных библиотек зафиксированы в самом пакете. Ручные правки в build.gradle и Podfile не нужны, код инициализации на Kotlin и Swift писать не нужно — вся настройка выполняется на Dart.

Требования к среде для datadog_flutter_plugin 3.4.1: Flutter 3.27 и новее, Dart 3.6 и новее, Android minSdkVersion 23, iOS 12.0 и новее.

Пакет поддерживает и Flutter Web — в этом случае под капотом используется браузерная библиотека. Подключение веб-приложений, написанных не на Flutter, описано на странице Browser.

Адрес приёма данных

Данные RUM принимаются по адресу:

https://<адрес ProtoOBP>/api/v2/rum

Равнозначные адреса, если на вашем периметре уже настроена маршрутизация по одному из этих префиксов:

https://<адрес ProtoOBP>/eum/api/v2/rum
https://<адрес ProtoOBP>/mobile/api/v2/rum

Перед подключением уточните у администратора платформы:

  • полный адрес приёма для вашего контура;
  • что лицензия платформы включает модуль мониторинга цифрового опыта (DEM) — без него запросы отклоняются с кодом 403;
  • что приём RUM включён в конфигурации компонента приёма данных.

Установка пакетов

flutter pub add datadog_flutter_plugin datadog_tracking_http_client

Инициализация

В lib/main.dart:

import 'package:datadog_flutter_plugin/datadog_flutter_plugin.dart';
import 'package:datadog_tracking_http_client/datadog_tracking_http_client.dart';
import 'package:flutter/material.dart';

// Адрес приёма ProtoOBP. Указывается ПОЛНОСТЬЮ, вместе с путём:
// пакет не дописывает /api/v2/rum к этому значению.
const protoObpRumEndpoint = 'https://protoobp.example.ru/api/v2/rum';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final configuration = DatadogConfiguration(
    // Произвольная непустая строка: платформа токен не проверяет.
    clientToken: 'protoobp',
    // Окружение — попадает в данные как тег и доступно для фильтрации.
    env: 'prod',
    // Обязателен по контракту пакета; при заданном customEndpoint не используется.
    site: DatadogSite.eu1,
    // Название приложения в интерфейсе платформы.
    service: 'my-mobile-app',
    nativeCrashReportEnabled: true,
    // Домены вашего бэкенда — к запросам к ним добавляются заголовки трассировки.
    firstPartyHosts: ['api.example.ru'],
    rumConfiguration: DatadogRumConfiguration(
      // Произвольный идентификатор приложения.
      applicationId: 'my-mobile-app',
      // 100 — собирать все сессии, 10 — 10 % сессий.
      sessionSamplingRate: 100,
      // Внутренняя телеметрия пакета платформой не используется — отключаем.
      telemetrySampleRate: 0,
      detectLongTasks: true,
      // Метрики отрисовки кадров Flutter.
      reportFlutterPerformance: true,
      customEndpoint: protoObpRumEndpoint,
    ),
  )..enableHttpTracking();

  await DatadogSdk.runApp(configuration, TrackingConsent.granted, () async {
    runApp(const MyApp());
  });
}

Данные о текущем пользователе задаются отдельно и не обязательны:

DatadogSdk.instance.setUserInfo(
  id: '1234',
  name: 'Василий Пупкин',
  email: 'vass@pupkine.com',
);

Отслеживание экранов

Чтобы переходы между экранами становились отдельными просмотрами, добавьте наблюдатель навигации:

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorObservers: [
        DatadogNavigationObserver(datadogSdk: DatadogSdk.instance),
      ],
      routes: {
        '/': (_) => const HomeScreen(),
        '/details': (_) => const DetailsScreen(),
      },
    );
  }
}

Имя маршрута становится именем экрана в интерфейсе платформы, поэтому маршруты стоит называть осмысленно.

Сетевые запросы и сквозная трассировка

Вызов ..enableHttpTracking() в примере выше подменяет HttpOverrides.global, после чего сетевые запросы приложения собираются как события ресурсов. Если в приложении используются собственные HttpOverrides, установите их до инициализации.

К запросам на домены из firstPartyHosts добавляются заголовки трассировки. Если на этих серверах установлены агенты Proto Observability, вызовы с мобильного устройства и обработка на бэкенде объединяются в единую цепочку — трейс распределённой транзакции, начавшейся на устройстве пользователя.

Пользовательские события, атрибуты и ошибки

Кроме автоматически собираемых данных (экраны, нажатия, сетевые запросы, падения) приложение может отправлять собственные события — продуктовые и бизнесовые. Отдельный SDK для этого не требуется: используются штатные методы уже подключённого пакета, а платформа принимает такие события тем же потоком, что и остальные данные RUM.

Пользовательские действия

Событие с типом custom — основной способ передать продуктовое событие вместе с произвольным набором полей.

DatadogSdk.instance.rum?.addAction(
  RumActionType.custom,
  'payment_confirmed',
  {
    'payment_type': 'p2p',
    'amount': 12500,
    'currency': 'KGS',
    'channel': 'mobile',
  },
);

Для действий с длительностью используются парные вызовы startAction и stopAction — платформа получит длительность действия.

Имя события (payment_confirmed) становится значением поля цели действия, тип — значением custom. Оба поля доступны как измерения в дашбордах и выборках.

Атрибуты

Атрибуты бывают двух видов.

Разовые — передаются вместе с конкретным событием, как в примере выше.

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

DatadogSdk.instance.rum?.addAttribute('client_segment', 'corporate');
DatadogSdk.instance.rum?.addAttribute('tariff', 'business_pro');

Атрибуты попадают в поле context события. В платформе они доступны под ключами вида context.client_segment, context.amount — включая вложенные структуры, которые разворачиваются в ключи через точку.

Персональные данные в атрибуты помещать не следует: события хранятся в аналитическом контуре платформы и доступны всем, у кого есть права на просмотр данных приложения.

Ошибки и стектрейсы

Механизм фиксирования стектрейсов включён в пакет и дополнительной разработки не требует. Собираются три категории:

  1. Падения приложения — при nativeCrashReportEnabled: true. Отправляются при следующем запуске приложения.
  2. Необработанные исключения — перехватываются автоматически после инициализации.
  3. Ошибки, переданные явно — там, где приложение обрабатывает исключение само, но событие нужно зафиксировать.
try {
  await transferService.send(request);
} catch (error, stackTrace) {
  DatadogSdk.instance.rum?.addError(
    error,
    RumErrorSource.source,
    stackTrace: stackTrace,
    errorType: 'TransferFailed',
    attributes: {'payment_type': 'p2p'},
  );
  rethrow;
}

Если исключения как объекта нет, а есть только сообщение, используется addErrorInfo(message, source, stackTrace: …).

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

Что с этими данными можно делать в платформе

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

Отсюда следует, что доступно:

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

Обфусцированные стектрейсы

Восстановление обфусцированных стектрейсов на стороне платформы не выполняется — загрузка mapping-файлов R8/ProGuard и файлов dSYM не предусмотрена. Стектрейс сохраняется в том виде, в каком его сформировало приложение.

Практические варианты:

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

Сетевые доступы

Приложению для передачи данных достаточно доступа к адресу приёма ProtoOBP по HTTPS.

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

Проверка подключения

  1. Соберите и запустите приложение, пройдите по нескольким экранам, выполните сетевые запросы.
  2. Подождите 1–2 минуты: данные передаются пачками, а не по каждому событию.
  3. В интерфейсе платформы откройте раздел с мобильными приложениями. В списке появится приложение с названием, заданным в параметре service.
  4. Перейдите на дашборд приложения. Заполняются запуски, просмотры экранов, сессии и пользователи, ошибки, сетевые запросы, разрезы по версиям приложения и операционным системам.

Проверку следует выполнить на обеих платформах: сборки для Android и iOS используют разные платформенные библиотеки, хотя настраиваются одинаково.

Область применения инструкции

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

Передача логов приложения настраивается отдельно — обратитесь к команде Proto Observability за параметрами для вашего контура.

Запись сессий (Session Replay) в этой схеме подключения не передаётся.

Диагностика неполадок

Данные не появляются, в логах приложения нет ошибок отправки. Проверьте, что в customEndpoint указан полный адрес вместе с путём /api/v2/rum. Если задан только адрес сервера, запросы уходят в корень сайта и до компонента приёма не доходят.

Данные приходят с Android, но не с iOS (или наоборот). Настройка общая, но сборки разные. Проверьте, что на iOS выполнен pod install после установки пакета, а на Android значение minSdkVersion не ниже 23.

Ответ 403, тело Module not licensed. Лицензия платформы не включает модуль мониторинга цифрового опыта (DEM). Обратитесь к администратору платформы.

Ответ 402, тело License expired. Срок действия лицензии платформы истёк. Обратитесь к администратору платформы.

Ответ 415. Запрос отправлен с типом содержимого, который компонент приёма не разбирает. Такое возможно при отправке через промежуточный прокси, изменяющий заголовки. Убедитесь, что прокси передаёт заголовки Content-Type и Content-Encoding без изменений.

Ответ 200, но данных в интерфейсе нет. Приём RUM может быть выключен в конфигурации компонента приёма данных. Обратитесь к администратору платформы — для диагностики на стороне платформы включается подробное протоколирование принимаемых пакетов.

Приложение в списке называется не так, как ожидалось. Название берётся из параметра service конфигурации пакета.