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

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

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

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

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

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

ЕдиныйАгент для iOS автоматически отслеживает веб-запросы, выполняемые с использованием API URLSession от Apple, и сохраняет их в виде событий в Хранилище данных.

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

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

Кроме того, измеряются временные параметры, полученные с мобильного устройства.

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

Для каждого веб-запроса SDK фиксирует:

  • URL запроса
  • Метод HTTP (GET, POST, PUT, DELETE и т. д.)
  • Код состояния ответа
  • Размер запроса и ответа (отправлено/получено в байтах)
  • Продолжительность запроса
  • Ошибки (в случае неудачи запроса)

Собранные данные будут структурированы и представлены в соответствии с полями, указанными в request.*.

Поддерживаемые API

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

  • URLSession.dataTask(with:completionHandler:)
  • URLSession.downloadTask(with:completionHandler:)
  • URLSession.uploadTask(with:from:completionHandler:)
  • Варианты асинхронного выполнения с использованием async/await (URLSession.data(from:) и т. д.)
  • NSURLRequest, NSURLConnection, NSURLProtocol
  • Запросы WKWebView
  • Удобные методы NSData

Ограничения

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

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

Чтобы использовать Ключ-АСТРОМ и Firebase одновременно, выполните одно из следующих действий.

  • Полностью отключите мониторинг производительности Firebase.
  • Отключите автоматическую проверку веб-запросов в ЕдиномАгенте для iOS.
  • Следуйте только одному из описанных выше подходов; не выполняйте оба действия одновременно.

Для одновременного использования Ключ-АСТРОМ и mPaaS выполните одно из следующих действий.

  • Отключите автоматическую проверку веб-запросов в ЕдиномАгенте для iOS.
  • Не используйте фреймворк MPNebulaAdapter.
  • Следуйте только одному из описанных выше подходов; не выполняйте оба действия одновременно.

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

Чтобы отключить автоматическую проверку веб-запросов, установите ключ конфигурации DTXInstrumentWebRequestTiming в значение false в файле Info.plist вашего приложения:

<key>DTXInstrumentWebRequestTiming</key>
<false/>

Возможно, вам потребуется отключить автоматическую инструментацию в следующих случаях:

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

Какой тип измерительного оборудования использовать?

Тип запроса Тип измерительного прибора DTXInstrumentWebRequestTiming
HTTP(S) Вариант А: Авто true
HTTP(S) Вариант B: Ручной false

Нельзя комбинировать автоматическую и ручную инструментацию для одного и того же HTTP(S) запроса.

Контекст трассировки 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:) (Swift) / generateTraceContext:tracestate: (Objective-C) для создания или обогащения контекста трассировки в соответствии с официальной спецификацией W3C Trace Context:

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

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

Swift

import Astromkey

var request = URLRequest(url: URL(string: "https://api.example.com/data")!)

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

// Генерация/обогащение контекста трассировки
var traceparentForReporting: String?
if let ctx = Astromkey.generateTraceContext(existingTraceparent, tracestate: existingTracestate) {
    request.setValue(ctx.traceparent, forHTTPHeaderField: "traceparent")
    request.setValue(ctx.tracestate, forHTTPHeaderField: "tracestate")
    traceparentForReporting = ctx.traceparent
} else {
    // Изменения не должны применяться, если контекст не может быть создан (например, недопустимый traceparent)
}

// ...здесь выполните свой HTTP-запрос...

let requestData = DTXHttpRequestEventData(url: request.url!.absoluteString, method: request.httpMethod ?? "GET")
    .withDuration(duration)
    .withStatusCode(statusCode)

if let traceparent = traceparentForReporting {
    requestData.withTraceparentHeader(traceparent)
}

Astromkey.sendHttpRequestEvent(requestData)

Objective-C

@import Astromkey;

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.example.com/data"]];

// Считываем существующие заголовки (если таковые имеются)
NSString *existingTraceparent = [request valueForHTTPHeaderField:@"traceparent"];
NSString *existingTracestate = [request valueForHTTPHeaderField:@"tracestate"];

// Генерация/обогащение контекста трассировки
NSString *traceparentForReporting = nil;
DTXTraceContext *ctx = [Astromkey generateTraceContext:existingTraceparent tracestate:existingTracestate];
if (ctx) {
    [request setValue:ctx.traceparent forHTTPHeaderField:@"traceparent"];
    [request setValue:ctx.tracestate forHTTPHeaderField:@"tracestate"];
    traceparentForReporting = ctx.traceparent;
} else {
    // Изменения не должны применяться, если контекст не может быть создан (например, недопустимый traceparent)
}

// ...здесь выполните свой HTTP-запрос...

DTXHttpRequestEventData *requestData = [[[[DTXHttpRequestEventData alloc]
    initWithURL:request.URL.absoluteString method:request.HTTPMethod]
    withDuration:@(duration)]
    withStatusCode:@(statusCode)];

if (traceparentForReporting) {
    [requestData withTraceparentHeader:traceparentForReporting];
}

[Astromkey sendHttpRequestEvent:requestData];

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

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

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

Swift

import Astromkey

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

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

Objective-C

@import Astromkey;

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

// Отправка события веб-запроса
[Astromkey sendHttpRequestEvent:requestData];

Сообщить об ошибках

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

Swift

let requestData = DTXHttpRequestEventData(url: "https://api.example.com/data", method: "POST")
    .withDuration(1500)
    .withError(error as NSError)

Astromkey.sendHttpRequestEvent(requestData)

Objective-C

DTXHttpRequestEventData *requestData = [[[[DTXHttpRequestEventData alloc]
    initWithURL:@"https://api.example.com/data" method:@"POST"]
    withDuration:@1500]
    withError:error];

[Astromkey sendHttpRequestEvent:requestData];

Включить контекст трассировки

Для сопоставления запросов, сообщенных вручную, с распределенными трассировками, добавьте заголовок traceparent:

Совмещение ручной и автоматической передачи контекста трассировки для одного и того же запроса не поддерживается. Не устанавливайте заголовок traceparent или tracestate самостоятельно, пока активна автоматическая инструментация веб-запросов. Чтобы установить заголовки вручную, сначала отключите автоматическую передачу контекста трассировки.

Swift

// Сообщить о событии с помощью трассировки (traceparent)
let requestData = DTXHttpRequestEventData(url: url, method: "GET")
    .withDuration(duration)
    .withStatusCode(statusCode)
    .withTraceparentHeader(traceparent)

Astromkey.sendHttpRequestEvent(requestData)

Objective-C

// Сообщить о событии с помощью трассировки (traceparent)
DTXHttpRequestEventData *requestData = [[[[[DTXHttpRequestEventData alloc]
    initWithURL:url method:@"GET"]
    withDuration:duration]
    withStatusCode:statusCode]
    withTraceparentHeader:traceparent];

[Astromkey sendHttpRequestEvent:requestData];

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

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

Swift

let requestData = DTXHttpRequestEventData(url: url, method: "POST")
    .withDuration(300)
    .withStatusCode(201)
    .addEventProperty("event_properties.api_version", value: "v2")
    .addEventProperty("event_properties.endpoint", value: "users")

Astromkey.sendHttpRequestEvent(requestData)

Objective-C

DTXHttpRequestEventData *requestData = [[[[[[DTXHttpRequestEventData alloc]
    initWithURL:url method:@"POST"]
    withDuration:@300]
    withStatusCode:@201]
    addEventProperty:@"event_properties.api_version" value:@"v2"]
    addEventProperty:@"event_properties.endpoint" value:@"users"];

[Astromkey sendHttpRequestEvent:requestData];

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

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

Модификаторы событий позволяют обогащать события веб-запросов дополнительными данными перед их отправкой. Это полезно для добавления контекста из запроса/ответа, который не захватывается автоматически.

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

Swift

let subscriber = Astromkey.addHttpEventModifier { event, context in
    // Получение сведений о запросе из контекста
    if let request = context?.request {
        // Добавьте пользовательские заголовки или информацию запроса в качестве свойств
        if let customHeader = request.value(forHTTPHeaderField: "X-Custom-Header") {
            event.fields["event_properties.custom_header"] = customHeader
        }
    }

    // Доступ к подробностям ответа
    if let httpResponse = context?.response as? HTTPURLResponse {
        if let serverTiming = httpResponse.value(forHTTPHeaderField: "Server-Timing") {
            event.fields["event_properties.server_timing"] = serverTiming
        }
    }

    // Возвращает событие изменения (или nil, чтобы его отбросить)
    return event
}

Objective-C

DTXModifyEventSubscriber *subscriber = [Astromkey addHttpEventModifier:^DTXModifyableEvent *(DTXModifyableEvent *event, DTXHttpRequestEventContext *context) {
    // Получение сведений о запросе из контекста
    if (context.request) {
        // Добавьте пользовательские заголовки или информацию запроса в качестве свойств
        NSString *customHeader = [context.request valueForHTTPHeaderField:@"X-Custom-Header"];
        if (customHeader) {
            event.fields[@"event_properties.custom_header"] = customHeader;
        }
    }

    // Доступ к подробностям ответа
    if ([context.response isKindOfClass:[NSHTTPURLResponse class]]) {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)context.response;
        NSString *serverTiming = httpResponse.allHeaderFields[@"Server-Timing"];
        if (serverTiming) {
            event.fields[@"event_properties.server_timing"] = serverTiming;
        }
    }

    // Возвращает событие изменения (или nil, чтобы его отбросить)
    return event;
}];

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

Предоставляет DTXHttpRequestEventContext доступ к:

Свойство Тип Описание
request URLRequest Первоначальный запрос
response URLResponse? Ответ сервера (если имеется)
responseBody Data? Данные ответа (если получены)
error NSError? Сообщение об ошибке (если запрос не удался)

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

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

Swift

Astromkey.removeEventModifier(subscriber)

Objective-C

[Astromkey removeEventModifier:subscriber];

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

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

Swift

let subscriber = Astromkey.addHttpEventModifier { event, context in
    // Не сообщать о запросах к точкам аналитики
    if let url = context?.request.url?.absoluteString,
       url.contains("analytics.example.com") {
        return nil
    }
    return event
}

Objective-C

DTXModifyEventSubscriber *subscriber = [Astromkey addHttpEventModifier:^DTXModifyableEvent *(DTXModifyableEvent *event, DTXHttpRequestEventContext *context) {
    // Не сообщать о запросах к точкам аналитики
    NSString *url = context.request.URL.absoluteString;
    if (url && [url containsString:@"analytics.example.com"]) {
        return nil;
    }
    return event;
}];