Логирование и мониторинг

RTK Query предоставляет встроенную модель наблюдения за запросами, кэшем и жизненным циклом данных, что делает его удобным инструментом для построения наблюдаемой (observable) клиентской сетевой логики. Логирование и мониторинг в RTK Query не являются отдельной «надстройкой», а формируются через middleware, lifecycle-хуки, Redux DevTools и возможности API-слайсов.


В основе RTK Query лежит интеграция с Redux store. Любое действие — запрос, мутация, инвалидация кэша — проходит через Redux action pipeline. Это означает, что каждое событие можно:

  • перехватить через middleware
  • отследить в DevTools
  • обработать через extraReducers
  • логировать через кастомные listeners

RTK Query генерирует стандартные Redux actions с предсказуемыми именами:

  • api/executeQuery/pending
  • api/executeQuery/fulfilled
  • api/executeQuery/rejected
  • api/executeMutation/pending
  • api/executeMutation/fulfilled
  • api/executeMutation/rejected

Эти события формируют основу мониторинга.


Встроенная диагностика через Redux DevTools

RTK Query полностью совместим с Redux DevTools. Каждый запрос отображается как последовательность действий:

  • запуск запроса
  • успешное завершение
  • ошибка выполнения
  • обновление кэша

Структура наблюдаемых данных

В DevTools можно видеть:

  • endpoint name
  • аргументы запроса
  • status (pending, fulfilled, rejected)
  • время выполнения
  • нормализованные данные кэша

Особенность RTK Query заключается в том, что DevTools отражает не только результат запроса, но и внутреннее состояние кэша queries и mutations.


Middleware как основной инструмент логирования

RTK Query позволяет подключать middleware, через которые можно перехватывать все действия API-слайса.

Пример логирующего middleware

const rtkQueryLogger = (api) => (next) => (action) => {
  if (action.type.startsWith('api/')) {
    console.log('[RTK Query]', action.type, action);
  }

  return next(action);
};

Middleware регистрируется в store:

const store = configureStore({
  reducer: {
    [api.reducerPath]: api.reducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(api.middleware, rtkQueryLogger)
});

Что можно логировать через middleware

  • время старта и завершения запроса
  • payload запросов
  • ошибки сети
  • повторные запросы из-за invalidation
  • кэш-хиты (через дополнительные инструменты)

Использование lifecycle-хуков endpoint’ов

RTK Query предоставляет встроенные lifecycle-события для каждого endpoint.

onQueryStarted

Используется для отслеживания начала запроса:

getUser: builder.query({
  query: (id) => `/user/${id}`,
  async onQueryStarted(arg, { queryFulfilled }) {
    console.log('Запрос начат:', arg);

    try {
      const result = await queryFulfilled;
      console.log('Запрос завершён:', result.data);
    } catch (err) {
      console.log('Ошибка запроса:', err);
    }
  }
});

Мониторинг успешных и ошибочных состояний

queryFulfilled позволяет синхронно отследить:

  • успешный ответ
  • сетевую ошибку
  • отмену запроса

Это даёт точную точку контроля без внешнего middleware.


Интеграция с custom logging layer

Для сложных приложений часто вводится централизованный слой логирования, который объединяет:

  • API запросы
  • бизнес-логику
  • пользовательские события

Структура логгера

const createApiLogger = () => ({
  logRequestStart: (endpoint, args) => {},
  logRequestSuccess: (endpoint, args, data, duration) => {},
  logRequestError: (endpoint, args, error, duration) => {}
});

Подключение через extraOptions

RTK Query позволяет передавать extraOptions в endpoint:

getUser: builder.query({
  query: (id) => `/user/${id}`,
  extraOptions: {
    track: true
  },
  async onQueryStarted(arg, { queryFulfilled, extra }) {
    const start = Date.now();

    try {
      const { data } = await queryFulfilled;
      const duration = Date.now() - start;

      console.log('TRACK SUCCESS', arg, data, duration);
    } catch (e) {
      console.log('TRACK ERROR', arg, e);
    }
  }
});

Отслеживание производительности запросов

Мониторинг производительности строится на измерении:

  • времени запроса
  • количества повторных вызовов
  • частоты cache miss / cache hit
  • количества invalidation событий

Простейший тайминг

const measureQuery = async (queryFulfilled, label) => {
  const start = performance.now();

  try {
    const result = await queryFulfilled;
    const end = performance.now();

    console.log(`${label}: ${end - start}ms`);

    return result;
  } catch (e) {
    const end = performance.now();

    console.log(`${label} failed: ${end - start}ms`);

    throw e;
  }
};

Мониторинг кэша RTK Query

Кэш RTK Query хранится в Redux state в виде:

  • state.api.queries
  • state.api.mutations
  • state.api.subscriptions

Доступ к состоянию кэша

const selectCache = (state) => state.api.queries;

Использование для анализа

  • какие endpoint’ы чаще всего вызываются
  • какие данные устаревают
  • где происходит чрезмерная инвалидация
  • какие запросы дублируются

Отслеживание subscription lifecycle

RTK Query использует подписки для управления актуальностью данных. Мониторинг подписок позволяет выявить:

  • утечки памяти (неудалённые subscriptions)
  • избыточные перерендеры
  • активные cache entries без UI

Структура subscriptions

state.api.subscriptions[queryCacheKey]

Каждая запись содержит количество активных подписчиков.


Логирование ошибок и retry-механизмов

RTK Query поддерживает автоматические retry, которые также можно мониторить.

Retry логика через fetchBaseQuery

const baseQuery = fetchBaseQuery({
  baseUrl: '/api',
  prepareHeaders: (headers, { getState }) => {
    return headers;
  }
});

Оборачивание с логированием ошибок

const baseQueryWithLogging = async (args, api, extraOptions) => {
  const result = await baseQuery(args, api, extraOptions);

  if (result.error) {
    console.error('API ERROR:', {
      endpoint: api.endpoint,
      args,
      error: result.error
    });
  }

  return result;
};

Интеграция с внешними системами мониторинга

RTK Query легко интегрируется с системами:

  • Sentry
  • Datadog
  • New Relic
  • custom analytics backend

Пример интеграции с Sentry-подобной системой

const reportError = (error, context) => {
  fetch('/monitoring', {
    method: 'POST',
    body: JSON.stringify({ error, context })
  });
};

Использование в onQueryStarted:

catch (err) {
  reportError(err, {
    endpoint: 'getUser',
    arg
  });
}

Агрегация логов и построение метрик

Собранные данные могут использоваться для построения метрик:

  • среднее время ответа endpoint’а
  • процент ошибок по endpoint’ам
  • нагрузка на API
  • количество cache hits vs misses
  • частота invalidation

Пример структуры метрик

{
  endpoint: 'getUser',
  requests: 1200,
  errors: 23,
  avgTime: 180,
  cacheHitRate: 0.67
}

Использование listenerMiddleware для мониторинга

Redux Toolkit предоставляет listenerMiddleware, который удобно использовать для аналитики RTK Query.

listenerMiddleware.startListening({
  matcher: api.endpoints.getUser.matchFulfilled,
  effect: async (action, listenerApi) => {
    console.log('User loaded:', action.meta.arg);
  }
});

Централизованное наблюдение за всеми endpoint’ами

Можно подписаться на все события API:

listenerMiddleware.startListening({
  matcher: (action) => action.type.startsWith('api/'),
  effect: (action) => {
    console.log('API EVENT:', action.type);
  }
});

Это позволяет построить полноценную систему аудита сетевых запросов.


Практическая модель наблюдения

В зрелых приложениях логирование RTK Query обычно делится на уровни:

  • технический уровень (middleware, DevTools)
  • прикладной уровень (onQueryStarted, listenerMiddleware)
  • аналитический уровень (Sentry, BI-системы)
  • инфраструктурный уровень (backend logs, gateway metrics)

Каждый уровень решает свою задачу и не дублирует другой.


Типовые ошибки при мониторинге

  • логирование только успешных запросов без ошибок
  • отсутствие привязки логов к endpoint
  • игнорирование cache/subscription состояния
  • чрезмерный logging middleware, замедляющий dispatch pipeline
  • отсутствие корреляции между запросами и бизнес-событиями