Мониторинг производительности веб-запросов

Материал из Документация Ключ-АСТРОМ

Мониторинг производительности веб-запросов

ЕдиныйАгент для Android предоставляет комплексные возможности мониторинга веб-запросов.

  • Автоматическая инструментация — автоматически фиксирует все веб-запросы, отправленные через HttpUrlConnection или OkHttp.
  • W3C Trace Context — активирует связь между фронтендом и бэкендом путем распространения заголовков контекста трассировки.
  • Создание отчетов вручную — формирование отчетов о веб-запросах из пользовательских сетевых конфигураций.
  • Обогащение событий — добавление пользовательских свойств к событиям веб-запросов.

Автоматизированная инструментация веб-запросов

ЕдиныйАгент для Android автоматически отслеживает веб-запросы, выполняемые с использованием встроенного API HttpUrlConnection Android, и сохраняет их в виде событий в Хранилище данных. То же самое относится и к запросам, выполняемым с помощью широко используемой библиотеки OkHttp.

Каждое событие состоит из четко определенных полей типа «ключ-значение», как указано в Семантическом словаре для пользовательских событий.

Эти данные можно запрашивать напрямую в Хранилище данных с помощью DQL.

Что фиксируется автоматически

Подробный обзор сообщаемых данных и их структуры можно найти в Семантическом словаре. Следующий список содержит обзор данных, которые автоматически отслеживаются ЕдинымАгентом:

  • URL запроса.
  • Метод HTTP (GET, POST, PUT, DELETE и т. д.).
  • Код состояния ответа.
  • Продолжительность запроса.
  • Исключение (в случае неудачи запроса).

Поддерживаемые HTTP-фреймворки

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

  • HttpURLConnection.
  • OkHttp: только версии 3, 4 и 5.

Если ваша библиотека для обработки веб-запросов основана на одном из поддерживаемых фреймворков, внутренние классы библиотеки автоматически инструментируются. Например, Retrofit версии 2 основан на OkHttp, поэтому все веб-запросы Retrofit автоматически инструментируются.

Ограничения

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

Отключить автоматическую настройку измерительных приборов

Чтобы отключить автоматическую инструментацию веб-запросов, установите флаг webRequests.enabled в значение false в блоке astromkey файла configurations вашего приложения build.gradle:

Groovy

astromkey {
    configurations {
        sampleConfig {
            webRequests.enabled false
        }
    }
}

Kotlin

configure<com.astromkey.tools.android.dsl.AstromkeyExtension> {
    configurations {
        create("sampleConfig") {
            webRequests.enabled(false)
        }
    }
}

Фильтрация веб-запросов по URL

Используйте свойство urlFilters внутри блока webRequests, чтобы предотвратить автоматическую инструментацию запросов, URL-адреса которых соответствуют одному или нескольким шаблонам регулярных выражений. Любой запрос, соответствующий хотя бы одному шаблону, исключается из автоматической инструментации и не будет отслеживаться.

Значение по умолчанию — пустой список, то есть по умолчанию никакие URL-адреса не отфильтровываются.

Groovy

astromkey {
    configurations {
        sampleConfig {
            webRequests {
                urlFilters "example.com", "^http://", "\.test\."
            }
        }
    }
}

Kotlin

configure<com.astromkey.tools.android.dsl.AstromkeyExtension> {
    configurations {
        create("sampleConfig") {
            webRequests {
                urlFilters("example.com", "^http://", "\.test\.")
            }
        }
    }
}

Каждый шаблон представляет собой регулярное выражение, сопоставляемое со всем URL-адресом.

Контекст трассировки W3C для связи между фронтендом и бэкендом

SDK поддерживает добавление контекста трассировки W3C, который позволяет связывать мобильные запросы с серверными службами. Подробнее см. раздел «Связывание фронтенда и бэкенда с использованием контекста трассировки W3C».

Автоматическое распространение заголовка контекста трассировки

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

Отсутствуют заголовки (типичный случай)

Если запрос не содержит заголовков трассировки, ЕдиныйАгент генерирует новый действительный запрос traceparent и добавляет соответствующую запись tracestate с контекстом, специфичным для Ключ-АСТРОМ.

Это позволяет установить корреляцию между мобильным запросом и трассировкой на стороне сервиса. См. раздел «Связь между фронтендом и бэкендом».

Существующий действительный traceparent заголовок

Если запрос уже содержит действительный идентификатор поставщика traceparent, ЕдиныйАгент сохраняет его и обновляет tracestate, добавляя информацию, специфичную для Ключ-АСТРОМ, без перезаписи существующих записей о поставщике.

Если общий размер данных tracestate станет слишком большим, ЕдиныйАгент может сократить количество записей, чтобы они оставались в пределах ограничений W3C. Данные Ключ-АСТРОМ сохраняются, когда это возможно.

Отключить автоматическое распространение контекста трассировки

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

  1. Перейдите в раздел Ключевые показатели опыта > Обзор.
  2. Выберите Мобильные устройства, чтобы просмотреть все мобильные версии сайта.
  3. Выберите интерфейс, который хотите настроить.
  4. На вкладке Настройки выберите Связь между фронтендом и бэкендом.
  5. Отключите функцию Включить связь между фронтендом и бэкендом через контекст трассировки W3C.

Передача заголовков контекста трассировки вручную

Если вы используете собственный сетевой стек, вы можете самостоятельно передавать заголовки W3C Trace Context и при этом сопоставлять запрос с распределенными трассировками Ключ-АСТРОМ.

Используйте Astromkey.generateTraceContext(traceparent, tracestate) для создания или обогащения контекста трассировки в соответствии с официальной спецификацией W3C Trace Context:

  • Если значение traceparent равно null, ЕдиныйАгент генерирует новый traceparent и соответствующий tracestate (включая информацию, специфичную для поставщика Ключ-АСТРОМ).
  • Если traceparent присутствует и действителен, ЕдиныйАгент сохраняет его и дополняет tracestate информацией, специфичной для поставщика Ключ-АСТРОМ (без перезаписи существующих записей о поставщике).
  • Если контекст трассировки создать не удаётся (например, из-за недопустимости traceparent или запрета на захват/тегирование), API возвращает значение null, и изменять заголовки запроса не следует.

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

Kotlin

val request = Request.Builder()
    .url("https://api.example.com/data")
    .build()

// Считываем существующие заголовки (если таковые имеются)
val existingTraceparent = request.header("traceparent")
val existingTracestate = request.header("tracestate")

// Генерация/обогащение контекста трассировки
val traceContext = Astromkey.generateTraceContext(existingTraceparent, existingTracestate)
val traceparentForReporting: String? = traceContext?.traceparent

if (traceContext != null) {
    request = request.newBuilder()
        .header("traceparent", traceContext.traceparent)
        .header("tracestate", traceContext.tracestate)
        .build()
}

// ...здесь выполните свой HTTP-запрос...
val requestData = HttpRequestEventData(request.url.toString(), request.method)
    .withDuration(duration)
    .withStatusCode(statusCode)

if (traceparentForReporting != null) {
    requestData.withTraceparentHeader(traceparentForReporting)
}

Astromkey.sendHttpRequestEvent(requestData)

Java

Request request = new Request.Builder()
    .url("https://api.example.com/data")
    .build();

// Считываем существующие заголовки (если таковые имеются)
String existingTraceparent = request.header("traceparent");
String existingTracestate = request.header("tracestate");

// Генерация/обогащение контекста трассировки
TraceContext traceContext = Astromkey.generateTraceContext(existingTraceparent, existingTracestate);
String traceparentForReporting = traceContext != null ? traceContext.getTraceparent() : null;
if (traceContext != null) {
    request = request.newBuilder()
        .header("traceparent", traceContext.getTraceparent())
        .header("tracestate", traceContext.getTracestate())
        .build();
}

// ...здесь выполните свой HTTP-запрос...
HttpRequestEventData requestData = new HttpRequestEventData(request.url().toString(), request.method())
        .withDuration(duration)
        .withStatusCode(statusCode);

if (traceparentForReporting != null) {
    requestData.withTraceparentHeader(traceparentForReporting);
}

Astromkey.sendHttpRequestEvent(requestData);

Сообщайте о веб-запросах вручную

Для сетевых библиотек, не охваченных автоматической инструментацией, вы можете вручную сообщать о веб-запросах, используя HttpRequestEventData.

Основное использование

Kotlin

// Создание данных запроса с указанием URL-адреса и метода HTTP
val requestData = HttpRequestEventData("https://api.example.com/data", "GET")
    .withDuration(250) // Длительность в миллисекундах
    .withStatusCode(200) // Код состояния HTTP
    .withBytesSent(128) // Отправлено байтов
    .withBytesReceived(4096) // Получено байтов

// Отправка события веб-запроса
Astromkey.sendHttpRequestEvent(requestData)

Java

// Создание данных запроса с указанием URL-адреса и метода HTTP
HttpRequestEventData requestData = new HttpRequestEventData("https://api.example.com/data", "GET")
    .withDuration(250) // Длительность в миллисекундах
    .withStatusCode(200) // Код состояния HTTP
    .withBytesSent(128) // Отправлено байтов
    .withBytesReceived(4096); // Получено байтов

// Отправка события веб-запроса
Astromkey.sendHttpRequestEvent(requestData);

Неудачный запрос

В случае неудачной попытки выполнения запроса, укажите информацию об ошибке:

Kotlin

val requestData = HttpRequestEventData("https://api.example.com/data", "POST")
    .withDuration(1500)
    .withThrowable(exception)

Astromkey.sendHttpRequestEvent(requestData)

Java

HttpRequestEventData requestData = new HttpRequestEventData("https://api.example.com/data", "POST")
    .withDuration(1500)
    .withThrowable(exception);

Astromkey.sendHttpRequestEvent(requestData);

Добавить пользовательские свойства

Добавьте пользовательские свойства события для получения дополнительного контекста:

Kotlin

val requestData = HttpRequestEventData(url, "POST")
    .withDuration(300)
    .withStatusCode(201)
    .addEventProperty("event_properties.api_version", "v2")
    .addEventProperty("event_properties.endpoint", "users")

Astromkey.sendHttpRequestEvent(requestData)

Java

HttpRequestEventData requestData = new HttpRequestEventData(url, "POST")
    .withDuration(300)
    .withStatusCode(201)
    .addEventProperty("event_properties.api_version", "v2")
    .addEventProperty("event_properties.endpoint", "users");

Astromkey.sendHttpRequestEvent(requestData);

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

Обогащение событий (модификаторы)

Модификаторы событий позволяют обогащать события веб-запросов дополнительными данными перед их отправкой. Это полезно для добавления контекста из запроса или ответа, который не захватывается автоматически. ЕдиныйАгент для Android в настоящее время предоставляет эту функцию только для запросов, выполняемых с помощью фреймворка OkHttp. Кроме того, вы также можете добавить другие свойства события через EventModifier.

При одновременном использовании обоих подходов сначала выполняется первый шаг, OkHttpEventModifier, а затем второй EventModifier.

Добавить модификатор веб-запроса

Чтобы добавить модификатор веб-запроса, реализуйте интерфейс OkHttpEventModifier и передайте его методу Astromkey.addHttpEventModifier. Модификатор может получить доступ к объектам запроса и ответа для извлечения дополнительных данных и добавления их к событию. В случае исключения модификатор может получить доступ к объектам запроса и исключения для извлечения дополнительных данных и добавления их к событию.

Из-за особенностей обработки тела ответа OkHttp, вам необходимо использовать peekBody() вместо body(), чтобы избежать потребления потока ответа. Таким образом, тело ответа останется доступным для последующего использования в вашей обычной системе обработки ответов.

Если вы используете body() модификатор для доступа к телу ответа, при последующей попытке повторного его обработки вы получите исключение.

Kotlin

val modifier: OkHttpEventModifier = object : OkHttpEventModifier {
    override fun modifyEvent(request: Request, response: Response): JSONObject {
        val event = JSONObject()

        // Доступ к подробностям ответа
        val serverTiming = response.header("Server-Timing")
        if (serverTiming != null) {
            event.put("event_properties.server_timing", serverTiming)
        }

        // Просматривайте только тело ответа, не обрабатывайте его.
        val body = response.peekBody(1000)
        event.put("event_properties.body", body.toString())

        return event
    }

    override fun modifyEvent(request: Request, throwable: Throwable): JSONObject {
        val event = JSONObject()

        // Добавьте пользовательские заголовки или информацию запроса в качестве свойств
        val customHeader = request.header("X-Custom-Header")
        if (customHeader != null) {
            event.put("event_properties.custom_header", customHeader)
        }
        return event
    }
}

Astromkey.addHttpEventModifier(modifier)

Java

OkHttpEventModifier modifier = new OkHttpEventModifier() {
    @Override
    public JSONObject modifyEvent(Request request, Response response) {
        JSONObject event = new JSONObject();

        // Доступ к подробностям ответа
        String serverTiming = response.header("Server-Timing");
        if (serverTiming != null) {
            event.put("event_properties.server_timing", serverTiming);
        }

        // Просматривайте только тело ответа, не обрабатывайте его.
        ResponseBody body = response.peekBody(1000);
        event.put("event_properties.body", body.toString());

        return event;
    }

    @Override
    public JSONObject modifyEvent(Request request, Throwable throwable) {
        JSONObject event = new JSONObject();

        // Добавьте пользовательские заголовки или информацию запроса в качестве свойств
        String customHeader = request.header("X-Custom-Header");
        if (customHeader != null) {
            event.put("event_properties.custom_header", customHeader);
        }
        return event;
    }
};

Astromkey.addHttpEventModifier(modifier);

Доступные свойства контекста

OkHttpEventModifier предоставляет методы обратного вызова для двух сценариев:

  • modifyEvent(Request request, Response response)
  • modifyEvent(Request request, Throwable throwable)

Первый метод вызывается после завершения запроса и получения ответа. Обратите внимание, что ответ может быть неуспешным, например, если сервер возвращает код состояния 4xx или 5xx.

Второй метод вызывается в случае, если запрос завершился с исключением.

Метод обратного вызова Параметр Тип Описание
modifyEvent(request, response) request okhttp3.Request Исходный объект запроса OkHttp
response okhttp3.Response Объект ответа OkHttp (используйте peekBody() для чтения тела ответа)
modifyEvent(request, throwable) request okhttp3.Request Исходный объект запроса OkHttp
throwable Throwable Исключение, которое привело к сбою запроса.

Удалить модификатор

Когда модификатор больше не нужен, удалите его, используя ссылку на модификатор:

Kotlin

Astromkey.removeEventModifier(modifier)

Java

Astromkey.removeEventModifier(modifier);

Фильтрация запросов

Верните значение null из модификатора, чтобы предотвратить отправку события:

Kotlin

val filterModifier: OkHttpEventModifier = object : OkHttpEventModifier {
    override fun modifyEvent(request: Request, response: Response?): JSONObject? {
        if (request.url.toString().contains("analytics.example.com")) {
            return null // вернуть null для события drop
        } else {
            return JSONObject()
        }
    }

    override fun modifyEvent(request: Request?, throwable: Throwable?): JSONObject? {
        if (throwable is IOException) {
            val event = JSONObject()
            // Информация о выбросах добавляется автоматически
            return event
        } else {
            // Возвращает null, чтобы отменить событие
            return null
        }
    }
}

Astromkey.addHttpEventModifier(filterModifier)

Java

OkHttpEventModifier filterModifier = new OkHttpEventModifier() {
    @Override
    public JSONObject modifyEvent(Request request, Response response) {
        if (request.url().toString().contains("analytics.example.com")) {
            return null; // вернуть null для события drop
        } else {
            return new JSONObject();
        }
    }

    @Override
    public JSONObject modifyEvent(Request request, Throwable throwable) {
        if (throwable instanceof IOException) {
            JSONObject event = new JSONObject();
            // Информация о выбросах добавляется автоматически
            return event;
        } else {
            // Возвращает null, чтобы отменить событие
            return null;
        }
    }
};

Astromkey.addHttpEventModifier(filterModifier);